crossgcc: Upgrade CMake from 3.29.3 to 3.30.2
[coreboot.git] / src / device / pnp_device.c
blob431e2274ffc933727c2abadf32fe2f2192692562
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/io.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pnp.h>
7 #include <stdint.h>
9 /* PNP config mode wrappers */
11 void pnp_enter_conf_mode(struct device *dev)
13 if (dev->ops->ops_pnp_mode)
14 dev->ops->ops_pnp_mode->enter_conf_mode(dev);
17 void pnp_exit_conf_mode(struct device *dev)
19 if (dev->ops->ops_pnp_mode)
20 dev->ops->ops_pnp_mode->exit_conf_mode(dev);
23 #if CONFIG(HAVE_ACPI_TABLES)
24 void pnp_ssdt_enter_conf_mode(struct device *dev, const char *idx, const char *data)
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);
29 void pnp_ssdt_exit_conf_mode(struct device *dev, const char *idx, const char *data)
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);
34 #endif
36 /* PNP fundamental operations */
38 void pnp_write_config(struct device *dev, u8 reg, u8 value)
40 outb(reg, dev->path.pnp.port);
41 outb(value, dev->path.pnp.port + 1);
44 u8 pnp_read_config(struct device *dev, u8 reg)
46 outb(reg, dev->path.pnp.port);
47 return inb(dev->path.pnp.port + 1);
50 void pnp_unset_and_set_config(struct device *dev, u8 reg, u8 unset, u8 set)
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);
59 void pnp_set_logical_device(struct device *dev)
61 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
64 void pnp_set_enable(struct device *dev, int enable)
66 u8 tmp, bitpos;
68 tmp = pnp_read_config(dev, PNP_IDX_EN);
70 /* Handle virtual devices, which share the same LDN register. */
71 bitpos = (dev->path.pnp.device >> 8) & 0x7;
73 if (enable)
74 tmp |= (1 << bitpos);
75 else
76 tmp &= ~(1 << bitpos);
78 pnp_write_config(dev, PNP_IDX_EN, tmp);
81 int pnp_read_enable(struct device *dev)
83 u8 tmp, bitpos;
85 tmp = pnp_read_config(dev, PNP_IDX_EN);
87 /* Handle virtual devices, which share the same LDN register. */
88 bitpos = (dev->path.pnp.device >> 8) & 0x7;
90 return !!(tmp & (1 << bitpos));
93 void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
95 /* Index == 0x60 or 0x62. */
96 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
97 pnp_write_config(dev, index + 1, iobase & 0xff);
100 void pnp_set_irq(struct device *dev, u8 index, u8 irq)
102 /* Index == 0x70 or 0x72. */
103 pnp_write_config(dev, index, irq);
106 void pnp_set_drq(struct device *dev, u8 index, u8 drq)
108 /* Index == 0x74. */
109 pnp_write_config(dev, index, drq & 0xff);
112 /* PNP device operations */
114 void pnp_read_resources(struct device *dev)
118 static void pnp_set_resource(struct device *dev, struct resource *resource)
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;
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;
139 resource->flags |= IORESOURCE_STORED;
141 report_resource_stored(dev, resource, "");
144 void pnp_set_resources(struct device *dev)
146 struct resource *res;
148 pnp_enter_conf_mode(dev);
150 /* Select the logical device (LDN). */
151 pnp_set_logical_device(dev);
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);
157 pnp_exit_conf_mode(dev);
160 void pnp_enable_resources(struct device *dev)
162 pnp_enter_conf_mode(dev);
163 pnp_set_logical_device(dev);
164 pnp_set_enable(dev, 1);
165 pnp_exit_conf_mode(dev);
168 void pnp_enable(struct device *dev)
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);
178 void pnp_alt_enable(struct device *dev)
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);
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,
193 /* PNP chip operations */
195 static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
197 struct resource *resource;
198 unsigned int bit;
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;
208 resource = new_resource(dev, index);
209 resource->flags |= IORESOURCE_IO;
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)
216 resource->gran = bit;
217 resource->align = bit;
218 resource->size = 1 << bit;
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)
225 resource->limit = (1 << (bit + 1)) - 1;
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);
235 static void get_resources(struct device *dev, struct pnp_info *info)
237 struct resource *resource;
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);
250 if (info->flags & PNP_IRQ0) {
251 resource = new_resource(dev, PNP_IDX_IRQ0);
252 resource->size = 1;
253 resource->flags |= IORESOURCE_IRQ;
255 if (info->flags & PNP_IRQ1) {
256 resource = new_resource(dev, PNP_IDX_IRQ1);
257 resource->size = 1;
258 resource->flags |= IORESOURCE_IRQ;
261 if (info->flags & PNP_DRQ0) {
262 resource = new_resource(dev, PNP_IDX_DRQ0);
263 resource->size = 1;
264 resource->flags |= IORESOURCE_DRQ;
266 if (info->flags & PNP_DRQ1) {
267 resource = new_resource(dev, PNP_IDX_DRQ1);
268 resource->size = 1;
269 resource->flags |= IORESOURCE_DRQ;
273 * These are not IRQs, but set the flag to have the
274 * resource allocator do the right thing.
276 if (info->flags & PNP_EN) {
277 resource = new_resource(dev, PNP_IDX_EN);
278 resource->size = 1;
279 resource->flags |= IORESOURCE_IRQ;
281 if (info->flags & PNP_MSC0) {
282 resource = new_resource(dev, PNP_IDX_MSC0);
283 resource->size = 1;
284 resource->flags |= IORESOURCE_IRQ;
286 if (info->flags & PNP_MSC1) {
287 resource = new_resource(dev, PNP_IDX_MSC1);
288 resource->size = 1;
289 resource->flags |= IORESOURCE_IRQ;
291 if (info->flags & PNP_MSC2) {
292 resource = new_resource(dev, PNP_IDX_MSC2);
293 resource->size = 1;
294 resource->flags |= IORESOURCE_IRQ;
296 if (info->flags & PNP_MSC3) {
297 resource = new_resource(dev, PNP_IDX_MSC3);
298 resource->size = 1;
299 resource->flags |= IORESOURCE_IRQ;
301 if (info->flags & PNP_MSC4) {
302 resource = new_resource(dev, PNP_IDX_MSC4);
303 resource->size = 1;
304 resource->flags |= IORESOURCE_IRQ;
306 if (info->flags & PNP_MSC5) {
307 resource = new_resource(dev, PNP_IDX_MSC5);
308 resource->size = 1;
309 resource->flags |= IORESOURCE_IRQ;
311 if (info->flags & PNP_MSC6) {
312 resource = new_resource(dev, PNP_IDX_MSC6);
313 resource->size = 1;
314 resource->flags |= IORESOURCE_IRQ;
316 if (info->flags & PNP_MSC7) {
317 resource = new_resource(dev, PNP_IDX_MSC7);
318 resource->size = 1;
319 resource->flags |= IORESOURCE_IRQ;
321 if (info->flags & PNP_MSC8) {
322 resource = new_resource(dev, PNP_IDX_MSC8);
323 resource->size = 1;
324 resource->flags |= IORESOURCE_IRQ;
326 if (info->flags & PNP_MSC9) {
327 resource = new_resource(dev, PNP_IDX_MSC9);
328 resource->size = 1;
329 resource->flags |= IORESOURCE_IRQ;
331 if (info->flags & PNP_MSCA) {
332 resource = new_resource(dev, PNP_IDX_MSCA);
333 resource->size = 1;
334 resource->flags |= IORESOURCE_IRQ;
336 if (info->flags & PNP_MSCB) {
337 resource = new_resource(dev, PNP_IDX_MSCB);
338 resource->size = 1;
339 resource->flags |= IORESOURCE_IRQ;
341 if (info->flags & PNP_MSCC) {
342 resource = new_resource(dev, PNP_IDX_MSCC);
343 resource->size = 1;
344 resource->flags |= IORESOURCE_IRQ;
346 if (info->flags & PNP_MSCD) {
347 resource = new_resource(dev, PNP_IDX_MSCD);
348 resource->size = 1;
349 resource->flags |= IORESOURCE_IRQ;
351 if (info->flags & PNP_MSCE) {
352 resource = new_resource(dev, PNP_IDX_MSCE);
353 resource->size = 1;
354 resource->flags |= IORESOURCE_IRQ;
358 void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
359 unsigned int functions, struct pnp_info *info)
361 struct device_path path;
362 struct device *dev;
363 int i;
365 path.type = DEVICE_PATH_PNP;
366 path.pnp.port = base_dev->path.pnp.port;
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;
374 path.pnp.device = info[i].function;
375 dev = alloc_find_dev(base_dev->upstream, &path);
377 /* Don't initialize a device multiple times. */
378 if (dev->ops)
379 continue;
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;
389 get_resources(dev, &info[i]);