- First pass through with with device tree enhancement merge. Most of the mechanisms...
[coreboot.git] / src / devices / pnp_device.c
1 /* Copyright 2004 Linux Networx  */
2 /* This code is distrubted wihtout warrant under the GPL v2 (see COPYING) */
3
4 #include <console/console.h>
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <bitops.h>
8 #include <string.h>
9 #include <arch/io.h>
10 #include <device/device.h>
11 #include <device/pnp.h>
12
13 /* PNP fundamental operations */
14
15 void pnp_write_config(device_t dev, uint8_t reg, uint8_t value)
16 {
17         outb(reg, dev->path.u.pnp.port);
18         outb(value, dev->path.u.pnp.port + 1);
19 }
20
21 uint8_t pnp_read_config(device_t dev, uint8_t reg)
22 {
23         outb(reg, dev->path.u.pnp.port);
24         return inb(dev->path.u.pnp.port + 1);
25 }
26
27 void pnp_set_logical_device(device_t dev)
28 {
29         pnp_write_config(dev, 0x07, dev->path.u.pnp.device);
30 }
31
32 void pnp_set_enable(device_t dev, int enable)
33 {
34         pnp_write_config(dev, 0x30, enable?0x1:0x0);
35 }
36
37 int pnp_read_enable(device_t dev)
38 {
39         return !!pnp_read_config(dev, 0x30);
40 }
41
42 void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
43 {
44         /* Index == 0x60 or 0x62 */
45         pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
46         pnp_write_config(dev, index + 1, iobase & 0xff);
47 }
48
49 void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
50 {
51         /* Index == 0x70 or 0x72 */
52         pnp_write_config(dev, index, irq);
53 }
54
55 void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
56 {
57         /* Index == 0x74 */
58         pnp_write_config(dev, index, drq & 0xff);
59 }
60
61 /* PNP device operations */
62
63 void pnp_read_resources(device_t dev)
64 {
65         return;
66 }
67
68 static void pnp_set_resource(device_t dev, struct resource *resource)
69 {
70         if (!(resource->flags & IORESOURCE_ASSIGNED)) {
71                 printk_err("ERROR: %s %02x not allocated\n",
72                            dev_path(dev), resource->index);
73                 return;
74         }
75
76         /* Now store the resource */
77         if (resource->flags & IORESOURCE_IO) {
78                 pnp_set_iobase(dev, resource->index, resource->base);
79         }
80         else if (resource->flags & IORESOURCE_DRQ) {
81                 pnp_set_drq(dev, resource->index, resource->base);
82         }
83         else if (resource->flags  & IORESOURCE_IRQ) {
84                 pnp_set_irq(dev, resource->index, resource->base);
85         }
86         else {
87                 printk_err("ERROR: %s %02x unknown resource type\n",
88                         dev_path(dev), resource->index);
89                 return;
90         }
91         resource->flags |= IORESOURCE_STORED;
92
93         printk_debug(
94                 "%s %02x <- [0x%08lx - 0x%08lx] %s\n",
95                 dev_path(dev),
96                 resource->index,
97                 resource->base,  resource->base + resource->size - 1,
98                 (resource->flags & IORESOURCE_IO)? "io":
99                 (resource->flags & IORESOURCE_DRQ)? "drq":
100                 (resource->flags & IORESOURCE_IRQ)? "irq":
101                 (resource->flags & IORESOURCE_MEM)? "mem":
102                 "???");
103 }
104
105 void pnp_set_resources(device_t dev)
106 {
107         int i;
108
109         /* Select the device */
110         pnp_set_logical_device(dev);
111
112         /* Paranoia says I should disable the device here... */
113         for(i = 0; i < dev->resources; i++) {
114                 pnp_set_resource(dev, &dev->resource[i]);
115         }
116 }
117
118 void pnp_enable_resources(device_t dev)
119 {
120         pnp_set_logical_device(dev);
121         pnp_set_enable(dev, 1);
122 }
123
124 void pnp_enable(device_t dev)
125 {
126         if (!dev->enabled) {
127                 pnp_set_logical_device(dev);
128                 pnp_set_enable(dev, 0);
129         }
130 }
131
132 struct device_operations pnp_ops = {
133         .read_resources   = pnp_read_resources,
134         .set_resources    = pnp_set_resources,
135         .enable_resources = pnp_enable_resources,
136         .enable           = pnp_enable,
137 };
138
139 /* PNP chip opertations */
140
141 static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info)
142 {
143         struct resource *resource;
144         uint32_t size;
145
146         resource = get_resource(dev, index);
147         
148         /* Initilize the resource */
149         resource->limit = 0xffff;
150         resource->flags |= IORESOURCE_IO;
151         
152         /* Set the resource size and alignment */
153         size = (0xffff & info->mask);
154         resource->size  = (~(size | 0xfffff800) + 1);
155         resource->align = log2(resource->size);
156         resource->gran  = resource->align;
157 }
158
159 static void get_resources(device_t dev, struct pnp_info *info)
160 {
161         struct resource *resource;
162
163         if (info->flags & PNP_IO0) {
164                 pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0);
165         }
166         if (info->flags & PNP_IO1) {
167                 pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1);
168         }
169         if (info->flags & PNP_IO2) {
170                 pnp_get_ioresource(dev, PNP_IDX_IO2, &info->io2);
171         }
172         if (info->flags & PNP_IO3) {
173                 pnp_get_ioresource(dev, PNP_IDX_IO3, &info->io3);
174         }
175         if (info->flags & PNP_IRQ0) {
176                 resource = get_resource(dev, PNP_IDX_IRQ0);
177                 resource->size = 1;
178                 resource->flags |= IORESOURCE_IRQ;
179         }
180         if (info->flags & PNP_IRQ1) {
181                 resource = get_resource(dev, PNP_IDX_IRQ1);
182                 resource->size = 1;
183                 resource->flags |= IORESOURCE_IRQ;
184         }
185         if (info->flags & PNP_DRQ0) {
186                 resource = get_resource(dev, PNP_IDX_DRQ0);
187                 resource->size = 1;
188                 resource->flags |= IORESOURCE_DRQ;
189         }
190         if (info->flags & PNP_DRQ1) {
191                 resource = get_resource(dev, PNP_IDX_DRQ1);
192                 resource->size = 1;
193                 resource->flags |= IORESOURCE_DRQ;
194         }       
195
196
197 void pnp_enumerate(struct chip *chip, unsigned functions, 
198         struct device_operations *ops, struct pnp_info *info)
199 {
200         struct device_path path;
201         device_t dev;
202         int i;
203
204         chip_enumerate(chip);
205
206         path.type       = DEVICE_PATH_PNP;
207         path.u.pnp.port = chip->dev->path.u.pnp.port;
208         
209         /* Setup the ops and resources on the newly allocated devices */
210         for(i = 0; i < functions; i++) {
211                 path.u.pnp.device = info[i].function;
212                 dev = alloc_find_dev(chip->bus, &path);
213
214                 if (info[i].ops == 0) {
215                         dev->ops = ops;
216                 } else {
217                         dev->ops = info[i].ops;
218                 }
219                 get_resources(dev, &info[i]);
220         }
221 }