- Updates for 64bit resource support, handling missing devices and cpus in the config...
[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         uint32_t size;
136
137         resource = new_resource(dev, index);
138         
139         /* Initilize the resource */
140         resource->limit = 0xffff;
141         resource->flags |= IORESOURCE_IO;
142         
143         /* Set the resource size and alignment */
144         size = (0xffff & info->mask);
145         resource->size  = (~(size | 0xfffff800) + 1);
146         resource->align = log2(resource->size);
147         resource->gran  = resource->align;
148 }
149
150 static void get_resources(device_t dev, struct pnp_info *info)
151 {
152         struct resource *resource;
153
154         if (info->flags & PNP_IO0) {
155                 pnp_get_ioresource(dev, PNP_IDX_IO0, &info->io0);
156         }
157         if (info->flags & PNP_IO1) {
158                 pnp_get_ioresource(dev, PNP_IDX_IO1, &info->io1);
159         }
160         if (info->flags & PNP_IO2) {
161                 pnp_get_ioresource(dev, PNP_IDX_IO2, &info->io2);
162         }
163         if (info->flags & PNP_IO3) {
164                 pnp_get_ioresource(dev, PNP_IDX_IO3, &info->io3);
165         }
166         if (info->flags & PNP_IRQ0) {
167                 resource = new_resource(dev, PNP_IDX_IRQ0);
168                 resource->size = 1;
169                 resource->flags |= IORESOURCE_IRQ;
170         }
171         if (info->flags & PNP_IRQ1) {
172                 resource = new_resource(dev, PNP_IDX_IRQ1);
173                 resource->size = 1;
174                 resource->flags |= IORESOURCE_IRQ;
175         }
176         if (info->flags & PNP_DRQ0) {
177                 resource = new_resource(dev, PNP_IDX_DRQ0);
178                 resource->size = 1;
179                 resource->flags |= IORESOURCE_DRQ;
180         }
181         if (info->flags & PNP_DRQ1) {
182                 resource = new_resource(dev, PNP_IDX_DRQ1);
183                 resource->size = 1;
184                 resource->flags |= IORESOURCE_DRQ;
185         }       
186
187
188 void pnp_enumerate(struct chip *chip, unsigned functions, 
189         struct device_operations *ops, struct pnp_info *info)
190 {
191         struct device_path path;
192         device_t dev;
193         int i;
194
195         chip_enumerate(chip);
196
197         path.type       = DEVICE_PATH_PNP;
198         path.u.pnp.port = chip->dev->path.u.pnp.port;
199         
200         /* Setup the ops and resources on the newly allocated devices */
201         for(i = 0; i < functions; i++) {
202                 path.u.pnp.device = info[i].function;
203                 dev = alloc_find_dev(chip->bus, &path);
204
205                 if (info[i].ops == 0) {
206                         dev->ops = ops;
207                 } else {
208                         dev->ops = info[i].ops;
209                 }
210                 get_resources(dev, &info[i]);
211         }
212 }