Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 1 | /* |
Uwe Hermann | c70e9fc | 2010-02-15 23:10:19 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 3 | * |
Uwe Hermann | c70e9fc | 2010-02-15 23:10:19 +0000 | [diff] [blame] | 4 | * Copyright (C) 2004-2005 Nick Barker <nick.barker@btinternet.com> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 15 | */ |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 16 | |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 17 | #include <arch/io.h> |
| 18 | #include <device/device.h> |
| 19 | #include <device/pci.h> |
| 20 | #include <device/pci_ops.h> |
| 21 | #include <device/pci_ids.h> |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 22 | #include <console/console.h> |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 23 | #include <device/cardbus.h> |
Stefan Reinauer | aecf251 | 2009-07-21 22:01:21 +0000 | [diff] [blame] | 24 | #include <delay.h> |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 25 | #include "rl5c476.h" |
| 26 | #include "chip.h" |
| 27 | |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 28 | static int enable_cf_boot = 0; |
| 29 | static unsigned int cf_base; |
| 30 | |
Eric Biederman | dbec2d4 | 2004-10-21 10:44:08 +0000 | [diff] [blame] | 31 | static void rl5c476_init(device_t dev) |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 32 | { |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 33 | pc16reg_t *pc16; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 34 | unsigned char *base; |
| 35 | |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 36 | /* cardbus controller function 1 for CF Socket */ |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 37 | printk(BIOS_DEBUG, "Ricoh RL5c476: Initializing.\n"); |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 38 | |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 39 | printk(BIOS_DEBUG, "CF Base = %0x\n",cf_base); |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 40 | |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 41 | /* misc control register */ |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 42 | pci_write_config16(dev,0x82,0x00a0); |
| 43 | |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 44 | /* set up second slot as compact flash port if asked to do so */ |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 45 | |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 46 | if (!enable_cf_boot) { |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 47 | printk(BIOS_DEBUG, "CF boot not enabled.\n"); |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 48 | return; |
| 49 | } |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 50 | |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 51 | if (PCI_FUNC(dev->path.pci.devfn) != 1) { |
| 52 | // Only configure if second CF slot. |
| 53 | return; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 54 | } |
| 55 | |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 56 | /* make sure isa interrupts are enabled */ |
| 57 | pci_write_config16(dev,0x3e,0x0780); |
| 58 | |
| 59 | /* pick up where 16 bit card control structure is |
| 60 | * (0x800 bytes into config structure) |
| 61 | */ |
| 62 | base = (unsigned char *)pci_read_config32(dev,0x10); |
| 63 | pc16 = (pc16reg_t *)(base + 0x800); |
| 64 | |
| 65 | /* disable memory and io windows and turn off socket power */ |
| 66 | pc16->pwctrl = 0; |
| 67 | |
| 68 | /* disable irq lines */ |
| 69 | pc16->igctrl = 0; |
| 70 | |
| 71 | /* disable memory and I/O windows */ |
| 72 | pc16->awinen = 0; |
| 73 | |
| 74 | /* reset card, configure for I/O and set IRQ line */ |
| 75 | pc16->igctrl = 0x69; |
| 76 | |
| 77 | /* set io window 0 for 1e0 - 1ef */ |
| 78 | /* NOTE: This now sets CF up on a contiguous I/O window of |
| 79 | * 16 bytes, 0x1e0 to 0x1ef. |
| 80 | * Be warned that this is not a standard IDE address as |
| 81 | * automatically detected by the likes of FILO, and would need |
Martin Roth | b348bb5 | 2014-12-09 13:50:58 -0700 | [diff] [blame] | 82 | * patching to recognize these addresses as an IDE drive. |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 83 | * |
| 84 | * An earlier version of this driver set up 2 I/O windows to |
| 85 | * emulate the expected addresses for IDE2, however the PCMCIA |
| 86 | * package within Linux then could not re-initialize the |
| 87 | * device as it tried to take control of it. So I believe it is |
| 88 | * easier to patch Filo or the like to pick up this drive |
| 89 | * rather than playing silly games as the kernel tries to |
| 90 | * boot. |
| 91 | * |
| 92 | * Nonetheless, FILO needs a special option enabled to boot |
| 93 | * from this configuration, and it needs to clean up |
| 94 | * afterwards. Please refer to FILO documentation and source |
| 95 | * code for more details. |
| 96 | */ |
| 97 | pc16->iostl0 = 0xe0; |
| 98 | pc16->iosth0 = 1; |
| 99 | |
| 100 | pc16->iospl0 = 0xef; |
| 101 | pc16->iosph0 = 1; |
| 102 | |
| 103 | pc16->ioffl0 = 0; |
| 104 | pc16->ioffh0 = 0; |
| 105 | |
| 106 | /* clear window 1 */ |
| 107 | pc16->iostl1 = 0; |
| 108 | pc16->iosth1 = 0; |
| 109 | |
| 110 | pc16->iospl1 = 0; |
| 111 | pc16->iosph1 = 0; |
| 112 | |
| 113 | pc16->ioffl1 = 0x0; |
| 114 | pc16->ioffh1 = 0; |
| 115 | |
| 116 | /* set up CF config window */ |
| 117 | pc16->smpga0 = cf_base>>24; |
| 118 | pc16->smsth0 = (cf_base>>20)&0x0f; |
| 119 | pc16->smstl0 = (cf_base>>12)&0xff; |
| 120 | pc16->smsph0 = ((cf_base>>20)&0x0f) | 0x80; |
| 121 | pc16->smspl0 = (cf_base>>12)&0xff; |
| 122 | pc16->moffl0 = 0; |
| 123 | pc16->moffh0 = 0x40; |
| 124 | |
| 125 | |
| 126 | /* set I/O width for Auto Data width */ |
| 127 | pc16->ioctrl = 0x22; |
| 128 | |
| 129 | |
| 130 | /* enable I/O window 0 and 1 */ |
| 131 | pc16->awinen = 0xc1; |
| 132 | |
| 133 | pc16->miscc1 = 1; |
| 134 | |
| 135 | /* apply power and enable outputs */ |
| 136 | pc16->pwctrl = 0xb0; |
| 137 | |
| 138 | // delay could be optimised, but this works |
| 139 | udelay(100000); |
| 140 | |
| 141 | pc16->igctrl = 0x69; |
| 142 | |
| 143 | |
| 144 | /* 16 bit CF always have first config byte at 0x200 into |
| 145 | * Config structure, but CF+ may not according to spec - |
| 146 | * should locate through reading tuple data, but this should |
| 147 | * do for now. |
| 148 | */ |
| 149 | unsigned char *cptr; |
| 150 | cptr = (unsigned char *)(cf_base + 0x200); |
Stefan Reinauer | c02b4fc | 2010-03-22 11:42:32 +0000 | [diff] [blame] | 151 | printk(BIOS_DEBUG, "CF Config = %x\n",*cptr); |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 152 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 153 | /* Set CF to decode 16 IO bytes on any 16 byte boundary - |
| 154 | * rely on the io windows of the bridge set up above to |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 155 | * map those bytes into the addresses for IDE controller 3 |
| 156 | * (0x1e8 - 0x1ef and 0x3ed - 0x3ee) |
| 157 | */ |
| 158 | *cptr = 0x41; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 159 | } |
| 160 | |
Stefan Reinauer | c51dc44 | 2010-04-07 01:44:04 +0000 | [diff] [blame] | 161 | static void rl5c476_read_resources(device_t dev) |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 162 | { |
| 163 | |
| 164 | struct resource *resource; |
| 165 | |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 166 | /* For CF socket we need an extra memory window for |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 167 | * the control structure of the CF itself |
| 168 | */ |
Elyes HAOUAS | ba28e8d | 2016-08-31 19:22:16 +0200 | [diff] [blame^] | 169 | if ( enable_cf_boot && (PCI_FUNC(dev->path.pci.devfn) == 1)){ |
Stefan Reinauer | 925b6c0 | 2009-07-21 20:27:00 +0000 | [diff] [blame] | 170 | /* fake index as it isn't in PCI config space */ |
| 171 | resource = new_resource(dev, 1); |
Stefan Reinauer | c8863a2 | 2009-10-22 17:02:44 +0000 | [diff] [blame] | 172 | resource->flags |= IORESOURCE_MEM; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 173 | resource->size = 0x1000; |
| 174 | resource->align = resource->gran = 12; |
| 175 | resource->limit= 0xffff0000; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 176 | } |
| 177 | cardbus_read_resources(dev); |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 178 | } |
| 179 | |
Stefan Reinauer | c51dc44 | 2010-04-07 01:44:04 +0000 | [diff] [blame] | 180 | static void rl5c476_set_resources(device_t dev) |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 181 | { |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 182 | struct resource *resource; |
Paul Menzel | d0cdcae | 2014-08-08 15:24:31 +0200 | [diff] [blame] | 183 | printk(BIOS_DEBUG, "%s In set resources\n",dev_path(dev)); |
Elyes HAOUAS | ba28e8d | 2016-08-31 19:22:16 +0200 | [diff] [blame^] | 184 | if ( enable_cf_boot && (PCI_FUNC(dev->path.pci.devfn) == 1)){ |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 185 | resource = find_resource(dev,1); |
Elyes HAOUAS | ba28e8d | 2016-08-31 19:22:16 +0200 | [diff] [blame^] | 186 | if ( !(resource->flags & IORESOURCE_STORED) ){ |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 187 | resource->flags |= IORESOURCE_STORED ; |
Myles Watson | 08e0fb8 | 2010-03-22 16:33:25 +0000 | [diff] [blame] | 188 | printk(BIOS_DEBUG, "%s 1 ==> %llx\n", dev_path(dev), resource->base); |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 189 | cf_base = resource->base; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | pci_dev_set_resources(dev); |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 194 | |
| 195 | } |
| 196 | |
Sven Schnelle | d175f44 | 2011-02-28 18:09:58 +0000 | [diff] [blame] | 197 | static void rl5c476_set_subsystem(device_t dev, unsigned vendor, unsigned device) |
| 198 | { |
| 199 | u16 miscreg = pci_read_config16(dev, 0x82); |
| 200 | /* Enable subsystem id register writes */ |
| 201 | pci_write_config16(dev, 0x82, miscreg | 0x40); |
| 202 | |
| 203 | pci_write_config16(dev, 0x40, vendor); |
| 204 | pci_write_config16(dev, 0x42, device); |
| 205 | /* restore original contents */ |
| 206 | pci_write_config16(dev, 0x82, miscreg); |
| 207 | } |
| 208 | |
| 209 | static struct pci_operations rl5c476_pci_ops = { |
| 210 | .set_subsystem = rl5c476_set_subsystem, |
| 211 | }; |
| 212 | |
Eric Biederman | dbec2d4 | 2004-10-21 10:44:08 +0000 | [diff] [blame] | 213 | static struct device_operations ricoh_rl5c476_ops = { |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 214 | .read_resources = rl5c476_read_resources, |
| 215 | .set_resources = rl5c476_set_resources, |
| 216 | .enable_resources = cardbus_enable_resources, |
| 217 | .init = rl5c476_init, |
Myles Watson | 84e8e45 | 2010-06-07 17:12:57 +0000 | [diff] [blame] | 218 | .scan_bus = pci_scan_bridge, |
Sven Schnelle | d175f44 | 2011-02-28 18:09:58 +0000 | [diff] [blame] | 219 | .ops_pci = &rl5c476_pci_ops, |
Eric Biederman | dbec2d4 | 2004-10-21 10:44:08 +0000 | [diff] [blame] | 220 | }; |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 221 | |
Stefan Reinauer | f1cf1f7 | 2007-10-24 09:08:58 +0000 | [diff] [blame] | 222 | static const struct pci_driver ricoh_rl5c476_driver __pci_driver = { |
Eric Biederman | dbec2d4 | 2004-10-21 10:44:08 +0000 | [diff] [blame] | 223 | .ops = &ricoh_rl5c476_ops, |
| 224 | .vendor = PCI_VENDOR_ID_RICOH, |
| 225 | .device = PCI_DEVICE_ID_RICOH_RL5C476, |
| 226 | }; |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 227 | |
Stefan Reinauer | c51dc44 | 2010-04-07 01:44:04 +0000 | [diff] [blame] | 228 | static void southbridge_init(device_t dev) |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 229 | { |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 230 | struct southbridge_ricoh_rl5c476_config *conf = dev->chip_info; |
| 231 | enable_cf_boot = conf->enable_cf; |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | struct chip_operations southbridge_ricoh_rl5c476_ops = { |
Uwe Hermann | a7aa29b | 2006-11-05 18:50:49 +0000 | [diff] [blame] | 235 | CHIP_NAME("Ricoh RL5C476 CardBus Controller") |
Ronald G. Minnich | 43225bc | 2005-11-22 00:07:02 +0000 | [diff] [blame] | 236 | .enable_dev = southbridge_init, |
Ronald G. Minnich | 02fa3b2 | 2004-10-06 17:33:54 +0000 | [diff] [blame] | 237 | }; |