Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2004 Nick Barker <nick.barker9@btinternet.com> |
| 3 | * |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License as |
| 7 | * published by the Free Software Foundation; either version 2 of |
| 8 | * the License, or (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 18 | * MA 02111-1307 USA |
| 19 | */ |
| 20 | |
| 21 | |
| 22 | |
| 23 | #include <arch/io.h> |
| 24 | #include <device/device.h> |
| 25 | #include <device/pci.h> |
| 26 | #include <device/pci_ops.h> |
| 27 | #include <device/pci_ids.h> |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 28 | #include <console/console.h> |
| 29 | #include "rl5c476.h" |
| 30 | #include "chip.h" |
| 31 | |
| 32 | static void udelay(int i){ |
| 33 | for(; i > 0 ; i--) |
| 34 | inb(0x80); |
| 35 | |
| 36 | } |
| 37 | |
| 38 | static void |
| 39 | dump_south(void) |
| 40 | { |
| 41 | device_t dev0; |
| 42 | dev0 = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, 0); |
| 43 | dev0 = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, dev0); |
| 44 | int i,j; |
| 45 | |
| 46 | for(i = 0; i < 256; i += 16) { |
| 47 | printk_debug("0x%x: ", i); |
| 48 | for(j = 0; j < 16; j++) { |
| 49 | printk_debug("%02x ", pci_read_config8(dev0, i+j)); |
| 50 | } |
| 51 | printk_debug("\n"); |
| 52 | } |
| 53 | printk_debug("Card32\n"); |
| 54 | for(i = 0 ; i < 256 ; i+=16){ |
| 55 | printk_debug("0x%x: ",i); |
| 56 | for(j = 0 ; j < 16 ; j++){ |
| 57 | printk_debug(" %02x",*(unsigned char *)(0x80000000+i+j)); |
| 58 | } |
| 59 | printk_debug("\n"); |
| 60 | } |
| 61 | printk_debug("Card16\n"); |
| 62 | for(i = 0; i < 256; i += 16) { |
| 63 | printk_debug("0x%x: ", i); |
| 64 | for(j = 0; j < 16; j++) { |
| 65 | printk_debug("%02x ", *(unsigned char *)(0x80000800+ i+j)); |
| 66 | } |
| 67 | printk_debug("\n"); |
| 68 | } |
| 69 | printk_debug("CF Config\n"); |
| 70 | for(i = 0 ; i < 256 ; i+=16){ |
| 71 | printk_debug("0x%x: ",i); |
| 72 | for(j=0 ; j < 16 ; j++){ |
| 73 | printk_debug("%02x ",*(unsigned char *)(0x81000200 + i + j)); |
| 74 | } |
| 75 | printk_debug("\n"); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | |
| 80 | static void rl5c476_init(struct southbridge_rl5c476_config *conf) |
| 81 | { |
| 82 | //unsigned char enables; |
| 83 | device_t dev; |
| 84 | pc16reg_t *pc16; |
| 85 | int i; |
| 86 | |
| 87 | printk_debug("rl5c476 init\n"); |
| 88 | /* cardbus controller function 1 for CF Socket */ |
| 89 | dev = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, 0); |
| 90 | |
| 91 | if (!dev ){ |
| 92 | // probably an epia-m rather than mii |
| 93 | printk_debug("No rl5c476 found\n"); |
| 94 | return; |
| 95 | } |
| 96 | |
| 97 | /* setup pci header manually because 'pci_device.c' doesn't know how to handle |
| 98 | * pci to cardbus bridges - (header type 2 I think) |
| 99 | */ |
| 100 | |
| 101 | |
| 102 | /* initialize function zero - pcmcia socket so it behaves itself */ |
| 103 | /* FIXME - statically put control memory at 0xe0000000 for now |
| 104 | * one day the pci_device allocator might do this */ |
| 105 | pci_write_config32(dev,0x10,0xe0000000); |
| 106 | pci_write_config8(dev,0x0d,0x20); |
| 107 | pci_write_config8(dev,0x19,0x02); |
| 108 | pci_write_config8(dev,0x1a,0x02); |
| 109 | pci_write_config8(dev,0x1b,0x20); |
| 110 | //pci_write_config8(dev,0x3c,0); |
| 111 | pci_write_config8(dev,0x82,0x00a0); |
| 112 | pci_write_config16(dev,0x04,0x07); |
| 113 | |
| 114 | |
| 115 | /* get second function - i.e. compact flash socket */ |
| 116 | dev = dev_find_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, dev); |
| 117 | |
| 118 | |
| 119 | /* FIXME - control structure statically declared at 0xe0008000 for now */ |
| 120 | pci_write_config32(dev,0x10,0xe0008000); |
| 121 | pci_write_config8(dev,0x0d,0x20); |
| 122 | pci_write_config8(dev,0x19,0x03); |
| 123 | pci_write_config8(dev,0x1a,0x03); |
| 124 | pci_write_config8(dev,0x1b,0x20); |
| 125 | |
| 126 | //pci_write_config8(dev,0x3c,0x0); |
| 127 | pci_write_config16(dev,0x3e,0x0780); |
| 128 | pci_write_config16(dev,0x82,0x00a0); |
| 129 | |
| 130 | pci_write_config16(dev,0x04,0x07); |
| 131 | |
| 132 | |
| 133 | /* pick up where 16 bit card control structure is */ |
| 134 | pc16 = (pc16reg_t *)(0xe0008800); |
| 135 | |
| 136 | /* disable memory and io windows and turn off socket power */ |
| 137 | pc16->pwctrl = 0; |
| 138 | |
| 139 | /* disable irq lines */ |
| 140 | pc16->igctrl = 0; |
| 141 | |
| 142 | /* disable memory and I/O windows */ |
| 143 | pc16->awinen = 0; |
| 144 | |
| 145 | /* reset card, configure for I/O and set IRQ line */ |
| 146 | pc16->igctrl = 0x69; |
| 147 | |
| 148 | |
| 149 | // set io window 0 for 1e8 - 1ef |
| 150 | pc16->iostl0 = 0xe8; |
| 151 | pc16->iosth0 = 1; |
| 152 | |
| 153 | pc16->iospl0 = 0xef; |
| 154 | pc16->iosph0 = 1; |
| 155 | |
| 156 | // add io offset of 8 so that CF card will decode 0x1e8 as 0x1f0 i.e. the first byte of |
| 157 | // a 16 byte aligned, 16 byte window etc |
| 158 | pc16->ioffl0 = 0x8; |
| 159 | pc16->ioffh0 = 0; |
| 160 | |
| 161 | // set io window 1 for 3ed - 3ee |
| 162 | pc16->iostl1 = 0xed; |
| 163 | pc16->iosth1 = 3; |
| 164 | |
| 165 | pc16->iospl1 = 0xee; |
| 166 | pc16->iosph1 = 3; |
| 167 | |
| 168 | pc16->ioffl1 = 0x0; |
| 169 | pc16->ioffh1 = 0; |
| 170 | |
| 171 | |
| 172 | // FIXME statically declare CF config window at 0xe1000000 |
| 173 | pc16->smstl0 = 0; |
| 174 | pc16->smsth0 = 0; |
| 175 | pc16->smspl0 = 0; |
| 176 | pc16->smsph0 = 0x80; |
| 177 | pc16->moffl0 = 0; |
| 178 | pc16->moffh0 = 0x40; |
| 179 | pc16->smpga0 = 0xe1; |
| 180 | |
| 181 | // set I/O width for Auto Data width |
| 182 | pc16->ioctrl = 0x22; |
| 183 | |
| 184 | |
| 185 | // enable I/O window 0 and 1 |
| 186 | pc16->awinen = 0xc1; |
| 187 | |
| 188 | |
| 189 | pc16->miscc1 = 1; |
| 190 | |
| 191 | // apply power and enable outputs |
| 192 | pc16->pwctrl = 0xb0; |
| 193 | |
| 194 | |
| 195 | // delay could be optimised, but this works |
| 196 | udelay(100000); |
| 197 | |
| 198 | pc16->igctrl = 0x69; |
| 199 | |
| 200 | unsigned char *cptr; |
| 201 | cptr = (unsigned char *)(0xe1000200); |
| 202 | printk_debug("CF Config = %x\n",*cptr); |
| 203 | |
| 204 | // FIX Me 16 bit CF always have first config byte at 0x200 into Config structure, |
| 205 | // but CF+ May Not according to spec - should locate through reading tuple data, |
| 206 | // but this will do for now !!! |
| 207 | |
| 208 | |
| 209 | // set CF to decode 16 IO bytes on any 16 byte boundary - rely on the io |
| 210 | // windows of the bridge set up above to map those bytes into the |
| 211 | // addresses for ide controller 3 (0x1e8 - 0x1ef and 0x3ed - 0x3ee) |
| 212 | *cptr = 0x41; |
| 213 | |
| 214 | |
| 215 | } |
| 216 | |
| 217 | static void southbridge_init(struct chip *chip, enum chip_pass pass) |
| 218 | { |
| 219 | |
| 220 | struct southbridge_rl5c476_config *conf = |
| 221 | (struct southbridge_rl5c476_config *)chip->chip_info; |
| 222 | |
| 223 | switch (pass) { |
| 224 | case CONF_PASS_PRE_PCI: |
| 225 | //rl5c476_pci_enable(conf); |
| 226 | break; |
| 227 | |
| 228 | case CONF_PASS_POST_PCI: |
| 229 | rl5c476_init(conf); |
| 230 | |
| 231 | break; |
| 232 | |
| 233 | case CONF_PASS_PRE_BOOT: |
| 234 | //dump_south(); |
| 235 | break; |
| 236 | |
| 237 | default: |
| 238 | /* nothing yet */ |
| 239 | break; |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | static void enumerate(struct chip *chip) |
| 244 | { |
| 245 | extern struct device_operations default_pci_ops_bus; |
| 246 | chip_enumerate(chip); |
| 247 | chip->dev->ops = &default_pci_ops_bus; |
| 248 | } |
| 249 | |
| 250 | struct chip_control southbridge_ricoh_rl5c476_control = { |
| 251 | .enumerate = enumerate, |
| 252 | .enable = southbridge_init, |
| 253 | .name = "RICOH RL5C476" |
| 254 | }; |