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