xref: /aosp_15_r20/external/coreboot/src/device/pnp_device.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/io.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pnp.h>
7 #include <stdint.h>
8 
9 /* PNP config mode wrappers */
10 
pnp_enter_conf_mode(struct device * dev)11 void pnp_enter_conf_mode(struct device *dev)
12 {
13 	if (dev->ops->ops_pnp_mode)
14 		dev->ops->ops_pnp_mode->enter_conf_mode(dev);
15 }
16 
pnp_exit_conf_mode(struct device * dev)17 void pnp_exit_conf_mode(struct device *dev)
18 {
19 	if (dev->ops->ops_pnp_mode)
20 		dev->ops->ops_pnp_mode->exit_conf_mode(dev);
21 }
22 
23 #if CONFIG(HAVE_ACPI_TABLES)
pnp_ssdt_enter_conf_mode(struct device * dev,const char * idx,const char * data)24 void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data)
25 {
26 	if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_enter_conf_mode)
27 		dev->ops->ops_pnp_mode->ssdt_enter_conf_mode(dev, idx, data);
28 }
pnp_ssdt_exit_conf_mode(struct device * dev,const char * idx,const char * data)29 void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data)
30 {
31 	if (dev->ops->ops_pnp_mode && dev->ops->ops_pnp_mode->ssdt_exit_conf_mode)
32 		dev->ops->ops_pnp_mode->ssdt_exit_conf_mode(dev, idx, data);
33 }
34 #endif
35 
36 /* PNP fundamental operations */
37 
pnp_write_config(struct device * dev,u8 reg,u8 value)38 void pnp_write_config(struct device *dev, u8 reg, u8 value)
39 {
40 	outb(reg, dev->path.pnp.port);
41 	outb(value, dev->path.pnp.port + 1);
42 }
43 
pnp_read_config(struct device * dev,u8 reg)44 u8 pnp_read_config(struct device *dev, u8 reg)
45 {
46 	outb(reg, dev->path.pnp.port);
47 	return inb(dev->path.pnp.port + 1);
48 }
49 
pnp_unset_and_set_config(struct device * dev,u8 reg,u8 unset,u8 set)50 void pnp_unset_and_set_config(struct device *dev, u8 reg, u8 unset, u8 set)
51 {
52 	outb(reg, dev->path.pnp.port);
53 	u8 value = inb(dev->path.pnp.port + 1);
54 	value &= ~unset;
55 	value |= set;
56 	outb(value, dev->path.pnp.port + 1);
57 }
58 
pnp_set_logical_device(struct device * dev)59 void pnp_set_logical_device(struct device *dev)
60 {
61 	pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
62 }
63 
pnp_set_enable(struct device * dev,int enable)64 void pnp_set_enable(struct device *dev, int enable)
65 {
66 	u8 tmp, bitpos;
67 
68 	tmp = pnp_read_config(dev, PNP_IDX_EN);
69 
70 	/* Handle virtual devices, which share the same LDN register. */
71 	bitpos = (dev->path.pnp.device >> 8) & 0x7;
72 
73 	if (enable)
74 		tmp |= (1 << bitpos);
75 	else
76 		tmp &= ~(1 << bitpos);
77 
78 	pnp_write_config(dev, PNP_IDX_EN, tmp);
79 }
80 
pnp_read_enable(struct device * dev)81 int pnp_read_enable(struct device *dev)
82 {
83 	u8 tmp, bitpos;
84 
85 	tmp = pnp_read_config(dev, PNP_IDX_EN);
86 
87 	/* Handle virtual devices, which share the same LDN register. */
88 	bitpos = (dev->path.pnp.device >> 8) & 0x7;
89 
90 	return !!(tmp & (1 << bitpos));
91 }
92 
pnp_set_iobase(struct device * dev,u8 index,u16 iobase)93 void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
94 {
95 	/* Index == 0x60 or 0x62. */
96 	pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
97 	pnp_write_config(dev, index + 1, iobase & 0xff);
98 }
99 
pnp_set_irq(struct device * dev,u8 index,u8 irq)100 void pnp_set_irq(struct device *dev, u8 index, u8 irq)
101 {
102 	/* Index == 0x70 or 0x72. */
103 	pnp_write_config(dev, index, irq);
104 }
105 
pnp_set_drq(struct device * dev,u8 index,u8 drq)106 void pnp_set_drq(struct device *dev, u8 index, u8 drq)
107 {
108 	/* Index == 0x74. */
109 	pnp_write_config(dev, index, drq & 0xff);
110 }
111 
112 /* PNP device operations */
113 
pnp_read_resources(struct device * dev)114 void pnp_read_resources(struct device *dev)
115 {
116 }
117 
pnp_set_resource(struct device * dev,struct resource * resource)118 static void pnp_set_resource(struct device *dev, struct resource *resource)
119 {
120 	if (!(resource->flags & IORESOURCE_ASSIGNED)) {
121 		printk(BIOS_NOTICE, "%s %02lx %s size: 0x%010llx not assigned in devicetree\n",
122 		       dev_path(dev), resource->index, resource_type(resource),
123 		       resource->size);
124 		return;
125 	}
126 
127 	/* Now store the resource. */
128 	if (resource->flags & IORESOURCE_IO) {
129 		pnp_set_iobase(dev, resource->index, resource->base);
130 	} else if (resource->flags & IORESOURCE_DRQ) {
131 		pnp_set_drq(dev, resource->index, resource->base);
132 	} else if (resource->flags & IORESOURCE_IRQ) {
133 		pnp_set_irq(dev, resource->index, resource->base);
134 	} else {
135 		printk(BIOS_ERR, "%s %02lx unknown resource type\n",
136 		       dev_path(dev), resource->index);
137 		return;
138 	}
139 	resource->flags |= IORESOURCE_STORED;
140 
141 	report_resource_stored(dev, resource, "");
142 }
143 
pnp_set_resources(struct device * dev)144 void pnp_set_resources(struct device *dev)
145 {
146 	struct resource *res;
147 
148 	pnp_enter_conf_mode(dev);
149 
150 	/* Select the logical device (LDN). */
151 	pnp_set_logical_device(dev);
152 
153 	/* Paranoia says I should disable the device here... */
154 	for (res = dev->resource_list; res; res = res->next)
155 		pnp_set_resource(dev, res);
156 
157 	pnp_exit_conf_mode(dev);
158 }
159 
pnp_enable_resources(struct device * dev)160 void pnp_enable_resources(struct device *dev)
161 {
162 	pnp_enter_conf_mode(dev);
163 	pnp_set_logical_device(dev);
164 	pnp_set_enable(dev, 1);
165 	pnp_exit_conf_mode(dev);
166 }
167 
pnp_enable(struct device * dev)168 void pnp_enable(struct device *dev)
169 {
170 	if (!dev->enabled) {
171 		pnp_enter_conf_mode(dev);
172 		pnp_set_logical_device(dev);
173 		pnp_set_enable(dev, 0);
174 		pnp_exit_conf_mode(dev);
175 	}
176 }
177 
pnp_alt_enable(struct device * dev)178 void pnp_alt_enable(struct device *dev)
179 {
180 	pnp_enter_conf_mode(dev);
181 	pnp_set_logical_device(dev);
182 	pnp_set_enable(dev, !!dev->enabled);
183 	pnp_exit_conf_mode(dev);
184 }
185 
186 struct device_operations pnp_ops = {
187 	.read_resources   = pnp_read_resources,
188 	.set_resources    = pnp_set_resources,
189 	.enable_resources = pnp_enable_resources,
190 	.enable           = pnp_enable,
191 };
192 
193 /* PNP chip operations */
194 
pnp_get_ioresource(struct device * dev,u8 index,u16 mask)195 static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
196 {
197 	struct resource *resource;
198 	unsigned int bit;
199 
200 	/* If none of the mask bits is set, the resource would occupy the whole
201 	   IO space leading to IO resource conflicts with the other devices */
202 	if (!mask) {
203 		printk(BIOS_ERR, "device %s index %d has no mask.\n",
204 				dev_path(dev), index);
205 		return;
206 	}
207 
208 	resource = new_resource(dev, index);
209 	resource->flags |= IORESOURCE_IO;
210 
211 	/* Calculate IO region size which is determined by the first one from
212 	   the LSB of the mask. */
213 	for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
214 		;
215 
216 	resource->gran  = bit;
217 	resource->align = bit;
218 	resource->size  = 1 << bit;
219 
220 	/* Calculate IO region address limit which is determined by the first
221 	   one from the MSB of the mask. */
222 	for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
223 		;
224 
225 	resource->limit = (1 << (bit + 1)) - 1;
226 
227 	/* The block of ones in the mask is expected to be continuous.
228 	   If there is any zero in between the block of ones, it is ignored
229 	   in the calculation of the resource size and limit. */
230 	if (mask != (resource->limit ^ (resource->size - 1)))
231 		printk(BIOS_WARNING, "mask of device %s index %d is wrong.\n",
232 			dev_path(dev), index);
233 }
234 
get_resources(struct device * dev,struct pnp_info * info)235 static void get_resources(struct device *dev, struct pnp_info *info)
236 {
237 	struct resource *resource;
238 
239 	if (info->flags & PNP_IO0)
240 		pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
241 	if (info->flags & PNP_IO1)
242 		pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
243 	if (info->flags & PNP_IO2)
244 		pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
245 	if (info->flags & PNP_IO3)
246 		pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
247 	if (info->flags & PNP_IO4)
248 		pnp_get_ioresource(dev, PNP_IDX_IO4, info->io4);
249 
250 	if (info->flags & PNP_IRQ0) {
251 		resource = new_resource(dev, PNP_IDX_IRQ0);
252 		resource->size = 1;
253 		resource->flags |= IORESOURCE_IRQ;
254 	}
255 	if (info->flags & PNP_IRQ1) {
256 		resource = new_resource(dev, PNP_IDX_IRQ1);
257 		resource->size = 1;
258 		resource->flags |= IORESOURCE_IRQ;
259 	}
260 
261 	if (info->flags & PNP_DRQ0) {
262 		resource = new_resource(dev, PNP_IDX_DRQ0);
263 		resource->size = 1;
264 		resource->flags |= IORESOURCE_DRQ;
265 	}
266 	if (info->flags & PNP_DRQ1) {
267 		resource = new_resource(dev, PNP_IDX_DRQ1);
268 		resource->size = 1;
269 		resource->flags |= IORESOURCE_DRQ;
270 	}
271 
272 	/*
273 	 * These are not IRQs, but set the flag to have the
274 	 * resource allocator do the right thing.
275 	 */
276 	if (info->flags & PNP_EN) {
277 		resource = new_resource(dev, PNP_IDX_EN);
278 		resource->size = 1;
279 		resource->flags |= IORESOURCE_IRQ;
280 	}
281 	if (info->flags & PNP_MSC0) {
282 		resource = new_resource(dev, PNP_IDX_MSC0);
283 		resource->size = 1;
284 		resource->flags |= IORESOURCE_IRQ;
285 	}
286 	if (info->flags & PNP_MSC1) {
287 		resource = new_resource(dev, PNP_IDX_MSC1);
288 		resource->size = 1;
289 		resource->flags |= IORESOURCE_IRQ;
290 	}
291 	if (info->flags & PNP_MSC2) {
292 		resource = new_resource(dev, PNP_IDX_MSC2);
293 		resource->size = 1;
294 		resource->flags |= IORESOURCE_IRQ;
295 	}
296 	if (info->flags & PNP_MSC3) {
297 		resource = new_resource(dev, PNP_IDX_MSC3);
298 		resource->size = 1;
299 		resource->flags |= IORESOURCE_IRQ;
300 	}
301 	if (info->flags & PNP_MSC4) {
302 		resource = new_resource(dev, PNP_IDX_MSC4);
303 		resource->size = 1;
304 		resource->flags |= IORESOURCE_IRQ;
305 	}
306 	if (info->flags & PNP_MSC5) {
307 		resource = new_resource(dev, PNP_IDX_MSC5);
308 		resource->size = 1;
309 		resource->flags |= IORESOURCE_IRQ;
310 	}
311 	if (info->flags & PNP_MSC6) {
312 		resource = new_resource(dev, PNP_IDX_MSC6);
313 		resource->size = 1;
314 		resource->flags |= IORESOURCE_IRQ;
315 	}
316 	if (info->flags & PNP_MSC7) {
317 		resource = new_resource(dev, PNP_IDX_MSC7);
318 		resource->size = 1;
319 		resource->flags |= IORESOURCE_IRQ;
320 	}
321 	if (info->flags & PNP_MSC8) {
322 		resource = new_resource(dev, PNP_IDX_MSC8);
323 		resource->size = 1;
324 		resource->flags |= IORESOURCE_IRQ;
325 	}
326 	if (info->flags & PNP_MSC9) {
327 		resource = new_resource(dev, PNP_IDX_MSC9);
328 		resource->size = 1;
329 		resource->flags |= IORESOURCE_IRQ;
330 	}
331 	if (info->flags & PNP_MSCA) {
332 		resource = new_resource(dev, PNP_IDX_MSCA);
333 		resource->size = 1;
334 		resource->flags |= IORESOURCE_IRQ;
335 	}
336 	if (info->flags & PNP_MSCB) {
337 		resource = new_resource(dev, PNP_IDX_MSCB);
338 		resource->size = 1;
339 		resource->flags |= IORESOURCE_IRQ;
340 	}
341 	if (info->flags & PNP_MSCC) {
342 		resource = new_resource(dev, PNP_IDX_MSCC);
343 		resource->size = 1;
344 		resource->flags |= IORESOURCE_IRQ;
345 	}
346 	if (info->flags & PNP_MSCD) {
347 		resource = new_resource(dev, PNP_IDX_MSCD);
348 		resource->size = 1;
349 		resource->flags |= IORESOURCE_IRQ;
350 	}
351 	if (info->flags & PNP_MSCE) {
352 		resource = new_resource(dev, PNP_IDX_MSCE);
353 		resource->size = 1;
354 		resource->flags |= IORESOURCE_IRQ;
355 	}
356 }
357 
pnp_enable_devices(struct device * base_dev,struct device_operations * ops,unsigned int functions,struct pnp_info * info)358 void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
359 			unsigned int functions, struct pnp_info *info)
360 {
361 	struct device_path path;
362 	struct device *dev;
363 	int i;
364 
365 	path.type = DEVICE_PATH_PNP;
366 	path.pnp.port = base_dev->path.pnp.port;
367 
368 	/* Setup the ops and resources on the newly allocated devices. */
369 	for (i = 0; i < functions; i++) {
370 		/* Skip logical devices this Super I/O doesn't have. */
371 		if (info[i].function == PNP_SKIP_FUNCTION)
372 			continue;
373 
374 		path.pnp.device = info[i].function;
375 		dev = alloc_find_dev(base_dev->upstream, &path);
376 
377 		/* Don't initialize a device multiple times. */
378 		if (dev->ops)
379 			continue;
380 
381 		/* use LDN-specific ops override from corresponding pnp_info
382 		   entry if not NULL */
383 		if (info[i].ops)
384 			dev->ops = info[i].ops;
385 		/* else use device ops  */
386 		else
387 			dev->ops = ops;
388 
389 		get_resources(dev, &info[i]);
390 	}
391 }
392