- Bump the LinuxBIOS major version
[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         report_resource_stored(dev, resource, "");
94 }
95
96 void pnp_set_resources(device_t dev)
97 {
98         int i;
99
100         /* Select the device */
101         pnp_set_logical_device(dev);
102
103         /* Paranoia says I should disable the device here... */
104         for(i = 0; i < dev->resources; i++) {
105                 pnp_set_resource(dev, &dev->resource[i]);
106         }
107 }
108
109 void pnp_enable_resources(device_t dev)
110 {
111         pnp_set_logical_device(dev);
112         pnp_set_enable(dev, 1);
113 }
114
115 void pnp_enable(device_t dev)
116 {
117         if (!dev->enabled) {
118                 pnp_set_logical_device(dev);
119                 pnp_set_enable(dev, 0);
120         }
121 }
122
123 struct device_operations pnp_ops = {
124         .read_resources   = pnp_read_resources,
125         .set_resources    = pnp_set_resources,
126         .enable_resources = pnp_enable_resources,
127         .enable           = pnp_enable,
128 };
129
130 /* PNP chip opertations */
131
132 static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info)
133 {
134         struct resource *resource;
135         unsigned moving, gran, step;
136
137         resource = new_resource(dev, index);
138         
139         /* Initilize the resource */
140         resource->limit = 0xffff;
141         resource->flags |= IORESOURCE_IO;
142         
143         /* Get the resource size */
144         moving = info->mask;
145         gran = 15;
146         step = 1 << gran;
147         /* Find the first bit that moves */
148         while((moving & step) == 0) {
149                 gran--;
150                 step >>= 1;
151         }
152         /* Now find the first bit that does not move */
153         while((moving & step) != 0) {
154                 gran--;
155                 step >>= 1;
156         }
157         /* Of the moving bits the last bit in the first group,
158          * tells us the size of this resource.
159          */
160         if ((moving & step) == 0) {
161                 gran++;
162                 step <<= 1;
163         }
164         /* Set the resource size and alignment */
165         resource->gran  = gran;
166         resource->align = gran;
167         resource->limit = info->mask | (step - 1);
168         resource->size  = 1 << gran;
169 }
170
171 static void get_resources(device_t dev, struct pnp_info *info)
172 {
173         struct resource *resource;
174
175         if (info->flags & PNP_IO0) {
176                 pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0);
177         }
178         if (info->flags & PNP_IO1) {
179                 pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1);
180         }
181         if (info->flags & PNP_IO2) {
182                 pnp_get_ioresource(dev, PNP_IDX_IO2, &info->io2);
183         }
184         if (info->flags & PNP_IO3) {
185                 pnp_get_ioresource(dev, PNP_IDX_IO3, &info->io3);
186         }
187         if (info->flags & PNP_IRQ0) {
188                 resource = new_resource(dev, PNP_IDX_IRQ0);
189                 resource->size = 1;
190                 resource->flags |= IORESOURCE_IRQ;
191         }
192         if (info->flags & PNP_IRQ1) {
193                 resource = new_resource(dev, PNP_IDX_IRQ1);
194                 resource->size = 1;
195                 resource->flags |= IORESOURCE_IRQ;
196         }
197         if (info->flags & PNP_DRQ0) {
198                 resource = new_resource(dev, PNP_IDX_DRQ0);
199                 resource->size = 1;
200                 resource->flags |= IORESOURCE_DRQ;
201         }
202         if (info->flags & PNP_DRQ1) {
203                 resource = new_resource(dev, PNP_IDX_DRQ1);
204                 resource->size = 1;
205                 resource->flags |= IORESOURCE_DRQ;
206         }       
207
208
209 void pnp_enable_devices(device_t base_dev, struct device_operations *ops, 
210         unsigned functions, struct pnp_info *info)
211 {
212         struct device_path path;
213         device_t dev;
214         int i;
215
216         path.type       = DEVICE_PATH_PNP;
217         path.u.pnp.port = base_dev->path.u.pnp.port;
218         
219         /* Setup the ops and resources on the newly allocated devices */
220         for(i = 0; i < functions; i++) {
221                 path.u.pnp.device = info[i].function;
222                 dev = alloc_find_dev(base_dev->bus, &path);
223                 
224                 /* Don't initialize a device multiple times */
225                 if (dev->ops) 
226                         continue;
227
228                 if (info[i].ops == 0) {
229                         dev->ops = ops;
230                 } else {
231                         dev->ops = info[i].ops;
232                 }
233                 get_resources(dev, &info[i]);
234         }
235 }