xref: /aosp_15_r20/external/coreboot/src/southbridge/ricoh/rl5c476/rl5c476.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <device/device.h>
4 #include <device/pci.h>
5 #include <device/pci_ops.h>
6 #include <device/pci_ids.h>
7 #include <console/console.h>
8 #include <device/cardbus.h>
9 #include <delay.h>
10 #include "rl5c476.h"
11 #include "chip.h"
12 
13 static int enable_cf_boot = 0;
14 static unsigned int cf_base;
15 
rl5c476_init(struct device * dev)16 static void rl5c476_init(struct device *dev)
17 {
18 	pc16reg_t *pc16;
19 	unsigned char *base;
20 
21 	/* cardbus controller function 1 for CF Socket */
22 	printk(BIOS_DEBUG, "Ricoh RL5c476: Initializing.\n");
23 
24 	printk(BIOS_DEBUG, "CF Base = %0x\n",cf_base);
25 
26 	/* misc control register */
27 	pci_write_config16(dev,0x82,0x00a0);
28 
29 	/* set up second slot as compact flash port if asked to do so */
30 
31 	if (!enable_cf_boot) {
32 		printk(BIOS_DEBUG, "CF boot not enabled.\n");
33 		return;
34 	}
35 
36 	if (PCI_FUNC(dev->path.pci.devfn) != 1) {
37 		// Only configure if second CF slot.
38 		return;
39 	}
40 
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
67 	 * patching to recognize these addresses as an IDE drive.
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 
110 	/* set I/O width for Auto Data width */
111 	pc16->ioctrl = 0x22;
112 
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 
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);
133 	printk(BIOS_DEBUG, "CF Config = %x\n",*cptr);
134 
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
137 	 * map those bytes into the addresses for IDE controller 3
138 	 * (0x1e8 - 0x1ef and 0x3ed - 0x3ee)
139 	 */
140 	*cptr = 0x41;
141 }
142 
rl5c476_read_resources(struct device * dev)143 static void rl5c476_read_resources(struct device *dev)
144 {
145 	struct resource *resource;
146 
147 	/* For CF socket we need an extra memory window for
148 	 * the control structure of the CF itself
149 	 */
150 	if (enable_cf_boot && (PCI_FUNC(dev->path.pci.devfn) == 1)) {
151 		/* fake index as it isn't in PCI config space */
152 		resource = new_resource(dev, 1);
153 		resource->flags |= IORESOURCE_MEM;
154 		resource->size = 0x1000;
155 		resource->align = resource->gran = 12;
156 		resource->limit= 0xffff0000;
157 	}
158 	cardbus_read_resources(dev);
159 }
160 
rl5c476_set_resources(struct device * dev)161 static void rl5c476_set_resources(struct device *dev)
162 {
163 	struct resource *resource;
164 	printk(BIOS_DEBUG, "%s In set resources\n",dev_path(dev));
165 	if (enable_cf_boot && (PCI_FUNC(dev->path.pci.devfn) == 1)) {
166 		resource = find_resource(dev,1);
167 		if (!(resource->flags & IORESOURCE_STORED)) {
168 			resource->flags |= IORESOURCE_STORED;
169 			printk(BIOS_DEBUG, "%s 1 ==> %llx\n", dev_path(dev), resource->base);
170 			cf_base = resource->base;
171 		}
172 	}
173 
174 	pci_dev_set_resources(dev);
175 }
176 
rl5c476_set_subsystem(struct device * dev,unsigned int vendor,unsigned int device)177 static void rl5c476_set_subsystem(struct device *dev, unsigned int vendor,
178 				  unsigned int device)
179 {
180 	u16 miscreg = pci_read_config16(dev, 0x82);
181 	/* Enable subsystem id register writes */
182 	pci_write_config16(dev, 0x82, miscreg | 0x40);
183 
184 	pci_dev_set_subsystem(dev, vendor, device);
185 
186 	/* restore original contents */
187 	pci_write_config16(dev, 0x82, miscreg);
188 }
189 
190 static struct pci_operations rl5c476_pci_ops = {
191 	.set_subsystem    = rl5c476_set_subsystem,
192 };
193 
194 static struct device_operations ricoh_rl5c476_ops = {
195 	.read_resources   = rl5c476_read_resources,
196 	.set_resources    = rl5c476_set_resources,
197 	.enable_resources = cardbus_enable_resources,
198 	.init             = rl5c476_init,
199 	.scan_bus         = pci_scan_bridge,
200 	.ops_pci          = &rl5c476_pci_ops,
201 };
202 
203 static const struct pci_driver ricoh_rl5c476_driver __pci_driver = {
204 	.ops    = &ricoh_rl5c476_ops,
205 	.vendor = PCI_VID_RICOH,
206 	.device = PCI_DID_RICOH_RL5C476,
207 };
208 
southbridge_init(struct device * dev)209 static void southbridge_init(struct device *dev)
210 {
211 	struct southbridge_ricoh_rl5c476_config *conf = dev->chip_info;
212 	enable_cf_boot = conf->enable_cf;
213 }
214 
215 struct chip_operations southbridge_ricoh_rl5c476_ops = {
216 	.name = "Ricoh RL5C476 CardBus Controller",
217 	.enable_dev    = southbridge_init,
218 };
219