2 * This file is part of the coreboot project.
4 * Copyright (C) 2004 Linux Networx
5 * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
6 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
7 * Copyright (C) 2005 Tyan
8 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
9 * Copyright (C) 2013 Nico Huber <nico.h@gmx.de>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
25 #include <console/console.h>
30 #include <device/device.h>
31 #include <device/pnp.h>
33 /* PNP config mode wrappers */
35 void pnp_enter_conf_mode(device_t dev
)
37 if (dev
->ops
->ops_pnp_mode
)
38 dev
->ops
->ops_pnp_mode
->enter_conf_mode(dev
);
41 void pnp_exit_conf_mode(device_t dev
)
43 if (dev
->ops
->ops_pnp_mode
)
44 dev
->ops
->ops_pnp_mode
->exit_conf_mode(dev
);
47 /* PNP fundamental operations */
49 void pnp_write_config(device_t dev
, u8 reg
, u8 value
)
51 outb(reg
, dev
->path
.pnp
.port
);
52 outb(value
, dev
->path
.pnp
.port
+ 1);
55 u8
pnp_read_config(device_t dev
, u8 reg
)
57 outb(reg
, dev
->path
.pnp
.port
);
58 return inb(dev
->path
.pnp
.port
+ 1);
61 void pnp_set_logical_device(device_t dev
)
63 pnp_write_config(dev
, 0x07, dev
->path
.pnp
.device
& 0xff);
66 void pnp_set_enable(device_t dev
, int enable
)
70 tmp
= pnp_read_config(dev
, 0x30);
72 /* Handle virtual devices, which share the same LDN register. */
73 bitpos
= (dev
->path
.pnp
.device
>> 8) & 0x7;
78 tmp
&= ~(1 << bitpos
);
80 pnp_write_config(dev
, 0x30, tmp
);
83 int pnp_read_enable(device_t dev
)
87 tmp
= pnp_read_config(dev
, 0x30);
89 /* Handle virtual devices, which share the same LDN register. */
90 bitpos
= (dev
->path
.pnp
.device
>> 8) & 0x7;
92 return !!(tmp
& (1 << bitpos
));
95 void pnp_set_iobase(device_t dev
, u8 index
, u16 iobase
)
97 /* Index == 0x60 or 0x62. */
98 pnp_write_config(dev
, index
+ 0, (iobase
>> 8) & 0xff);
99 pnp_write_config(dev
, index
+ 1, iobase
& 0xff);
102 void pnp_set_irq(device_t dev
, u8 index
, u8 irq
)
104 /* Index == 0x70 or 0x72. */
105 pnp_write_config(dev
, index
, irq
);
108 void pnp_set_drq(device_t dev
, u8 index
, u8 drq
)
111 pnp_write_config(dev
, index
, drq
& 0xff);
114 /* PNP device operations */
116 void pnp_read_resources(device_t dev
)
121 static void pnp_set_resource(device_t dev
, struct resource
*resource
)
123 if (!(resource
->flags
& IORESOURCE_ASSIGNED
)) {
124 printk(BIOS_ERR
, "ERROR: %s %02lx %s size: 0x%010llx "
125 "not assigned\n", dev_path(dev
), resource
->index
,
126 resource_type(resource
), resource
->size
);
130 /* Now store the resource. */
131 if (resource
->flags
& IORESOURCE_IO
) {
132 pnp_set_iobase(dev
, resource
->index
, resource
->base
);
133 } else if (resource
->flags
& IORESOURCE_DRQ
) {
134 pnp_set_drq(dev
, resource
->index
, resource
->base
);
135 } else if (resource
->flags
& IORESOURCE_IRQ
) {
136 pnp_set_irq(dev
, resource
->index
, resource
->base
);
138 printk(BIOS_ERR
, "ERROR: %s %02lx unknown resource type\n",
139 dev_path(dev
), resource
->index
);
142 resource
->flags
|= IORESOURCE_STORED
;
144 report_resource_stored(dev
, resource
, "");
147 void pnp_set_resources(device_t dev
)
149 struct resource
*res
;
151 pnp_enter_conf_mode(dev
);
153 /* Select the logical device (LDN). */
154 pnp_set_logical_device(dev
);
156 /* Paranoia says I should disable the device here... */
157 for (res
= dev
->resource_list
; res
; res
= res
->next
)
158 pnp_set_resource(dev
, res
);
160 pnp_exit_conf_mode(dev
);
163 void pnp_enable_resources(device_t dev
)
165 pnp_enter_conf_mode(dev
);
166 pnp_set_logical_device(dev
);
167 pnp_set_enable(dev
, 1);
168 pnp_exit_conf_mode(dev
);
171 void pnp_enable(device_t dev
)
174 pnp_enter_conf_mode(dev
);
175 pnp_set_logical_device(dev
);
176 pnp_set_enable(dev
, 0);
177 pnp_exit_conf_mode(dev
);
181 void pnp_alt_enable(device_t dev
)
183 pnp_enter_conf_mode(dev
);
184 pnp_set_logical_device(dev
);
185 pnp_set_enable(dev
, !!dev
->enabled
);
186 pnp_exit_conf_mode(dev
);
189 struct device_operations pnp_ops
= {
190 .read_resources
= pnp_read_resources
,
191 .set_resources
= pnp_set_resources
,
192 .enable_resources
= pnp_enable_resources
,
193 .enable
= pnp_enable
,
196 /* PNP chip operations */
198 static void pnp_get_ioresource(device_t dev
, u8 index
, struct io_info
*info
)
200 struct resource
*resource
;
201 unsigned moving
, gran
, step
;
204 printk(BIOS_ERR
, "ERROR: device %s index %d has no mask.\n",
205 dev_path(dev
), index
);
209 resource
= new_resource(dev
, index
);
211 /* Initilize the resource. */
212 resource
->limit
= 0xffff;
213 resource
->flags
|= IORESOURCE_IO
;
215 /* Get the resource size... */
221 /* Find the first bit that moves. */
222 while ((moving
& step
) == 0) {
227 /* Now find the first bit that does not move. */
228 while ((moving
& step
) != 0) {
234 * Of the moving bits the last bit in the first group,
235 * tells us the size of this resource.
237 if ((moving
& step
) == 0) {
242 /* Set the resource size and alignment. */
243 resource
->gran
= gran
;
244 resource
->align
= gran
;
245 resource
->limit
= info
->mask
| (step
- 1);
246 resource
->size
= 1 << gran
;
249 static void get_resources(device_t dev
, struct pnp_info
*info
)
251 struct resource
*resource
;
253 if (info
->flags
& PNP_IO0
)
254 pnp_get_ioresource(dev
, PNP_IDX_IO0
, &info
->io0
);
255 if (info
->flags
& PNP_IO1
)
256 pnp_get_ioresource(dev
, PNP_IDX_IO1
, &info
->io1
);
257 if (info
->flags
& PNP_IO2
)
258 pnp_get_ioresource(dev
, PNP_IDX_IO2
, &info
->io2
);
259 if (info
->flags
& PNP_IO3
)
260 pnp_get_ioresource(dev
, PNP_IDX_IO3
, &info
->io3
);
262 if (info
->flags
& PNP_IRQ0
) {
263 resource
= new_resource(dev
, PNP_IDX_IRQ0
);
265 resource
->flags
|= IORESOURCE_IRQ
;
267 if (info
->flags
& PNP_IRQ1
) {
268 resource
= new_resource(dev
, PNP_IDX_IRQ1
);
270 resource
->flags
|= IORESOURCE_IRQ
;
273 if (info
->flags
& PNP_DRQ0
) {
274 resource
= new_resource(dev
, PNP_IDX_DRQ0
);
276 resource
->flags
|= IORESOURCE_DRQ
;
278 if (info
->flags
& PNP_DRQ1
) {
279 resource
= new_resource(dev
, PNP_IDX_DRQ1
);
281 resource
->flags
|= IORESOURCE_DRQ
;
285 * These are not IRQs, but set the flag to have the
286 * resource allocator do the right thing.
288 if (info
->flags
& PNP_EN
) {
289 resource
= new_resource(dev
, PNP_IDX_EN
);
291 resource
->flags
|= IORESOURCE_IRQ
;
293 if (info
->flags
& PNP_MSC0
) {
294 resource
= new_resource(dev
, PNP_IDX_MSC0
);
296 resource
->flags
|= IORESOURCE_IRQ
;
298 if (info
->flags
& PNP_MSC1
) {
299 resource
= new_resource(dev
, PNP_IDX_MSC1
);
301 resource
->flags
|= IORESOURCE_IRQ
;
303 if (info
->flags
& PNP_MSC4
) {
304 resource
= new_resource(dev
, PNP_IDX_MSC4
);
306 resource
->flags
|= IORESOURCE_IRQ
;
308 if (info
->flags
& PNP_MSC10
) {
309 resource
= new_resource(dev
, PNP_IDX_MSC10
);
311 resource
->flags
|= IORESOURCE_IRQ
;
315 void pnp_enable_devices(device_t base_dev
, struct device_operations
*ops
,
316 unsigned int functions
, struct pnp_info
*info
)
318 struct device_path path
;
322 path
.type
= DEVICE_PATH_PNP
;
323 path
.pnp
.port
= base_dev
->path
.pnp
.port
;
325 /* Setup the ops and resources on the newly allocated devices. */
326 for (i
= 0; i
< functions
; i
++) {
327 /* Skip logical devices this Super I/O doesn't have. */
328 if (info
[i
].function
== -1)
331 path
.pnp
.device
= info
[i
].function
;
332 dev
= alloc_find_dev(base_dev
->bus
, &path
);
334 /* Don't initialize a device multiple times. */
338 if (info
[i
].ops
== 0)
341 dev
->ops
= info
[i
].ops
;
343 get_resources(dev
, &info
[i
]);