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