0ec41c3346ccd2ceee8eeb79b795b530282b795c
[coreboot.git] / src / superio / NSC / pc87360 / superio.c
1 /* Copyright 2000  AG Electronics Ltd. */
2 /* This code is distributed without warranty under the GPL v2 (see COPYING) */
3
4 #include <arch/io.h>
5 #include <device/device.h>
6 #include <device/chip.h>
7 #include <console/console.h>
8 #include <string.h>
9 #include <bitops.h>
10 #include "chip.h"
11
12 void pnp_output(char address, char data)
13 {
14         outb(address, PNP_INDEX_REG);
15         outb(data, PNP_DATA_REG);
16 }
17
18 static void sio_enable(struct chip *chip, enum chip_pass pass)
19 {
20
21         struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
22
23         switch (pass) {
24         case CONF_PASS_PRE_CONSOLE:
25                 /* Enable Super IO Chip */
26                 pnp_output(0x07, 6); /* LD 6 = UART1 */
27                 pnp_output(0x30, 0); /* Dectivate */
28                 pnp_output(0x60, conf->port >> 8); /* IO Base */
29                 pnp_output(0x61, conf->port & 0xFF); /* IO Base */
30                 pnp_output(0x30, 1); /* Activate */
31                 break;
32         default:
33                 /* nothing yet */
34                 break;
35         }
36 }
37
38 static void pnp_write_config(device_t dev, unsigned char value, unsigned char reg)
39 {
40         outb(reg, dev->path.u.pnp.port);
41         outb(value, dev->path.u.pnp.port + 1);
42 }
43
44 static unsigned char pnp_read_config(device_t dev, unsigned char reg)
45 {
46         outb(reg, dev->path.u.pnp.port);
47         return inb(dev->path.u.pnp.port + 1);
48 }
49
50 static void pnp_set_logical_device(device_t dev)
51 {
52         pnp_write_config(dev, dev->path.u.pnp.device, 0x07);
53 }
54
55 static void pnp_set_enable(device_t dev, int enable)
56 {
57         pnp_write_config(dev, enable?0x1:0x0, 0x30);
58 }
59
60 static int pnp_read_enable(device_t dev)
61 {
62         return !!pnp_read_config(dev, 0x30);
63 }
64
65 #define FLOPPY_DEVICE   0
66 #define PARALLEL_DEVICE 1
67 #define COM2_DEVICE     2
68 #define COM1_DEVICE     3
69 #define SWC_DEVICE      4
70 #define MOUSE_DEVICE    5
71 #define KBC_DEVICE      6
72 #define GPIO_DEVICE     7
73 #define ACB_DEVICE      8
74 #define FSCM_DEVICE     9
75 #define WDT_DEVICE     10
76
77 struct io_info {
78         unsigned mask, set;
79 };
80 struct pnp_info {
81         unsigned flags;
82 #define PNP_IO0  0x01
83 #define PNP_IO1  0x02
84 #define PNP_IRQ0 0x04
85 #define PNP_IRQ1 0x08
86 #define PNP_DRQ0 0x10
87 #define PNP_DRQ1 0x20
88         struct io_info io0, io1;
89 };
90
91 static struct pnp_info pnp_dev_info[] = {
92         [ 0] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, },
93         [ 1] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, },
94         [ 2] = { PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, },
95         [ 3] = { PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
96         [ 4] = { PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, },
97         [ 5] = { PNP_IRQ0 },
98         [ 6] = { PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, },
99         [ 7] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
100         [ 8] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
101         [ 9] = { PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } },
102         [10] = { PNP_IO0 | PNP_IRQ0, { 0xfffc, 0 } },
103 };
104
105 static struct resource *get_resource(device_t dev, unsigned index)
106 {
107         struct resource *resource;
108         int i;
109         resource = 0;
110         for(i = 0; i < dev->resources; i++) {
111                 resource = &dev->resource[i];
112                 if (resource->index == index) {
113                         break;
114                 }
115         }
116         if (!resource || (resource->index != index)) {
117                 resource = &dev->resource[dev->resources];
118                 memset(resource, 0, sizeof(*resource));
119                 dev->resources++;
120         }
121         /* Initialize the resource values */
122         if (!(resource->flags & IORESOURCE_FIXED)) {
123                 resource->flags = 0;
124                 resource->base = 0;
125         }
126         resource->size  = 0;
127         resource->limit = 0;
128         resource->flags = 0;
129         resource->index = index;
130         resource->align = 0;
131         resource->gran  = 0;
132
133         return resource;
134 }
135
136 static void pnp_read_ioresource(device_t dev, unsigned index, struct io_info *info)
137 {
138         struct resource *resource;
139         uint32_t size;
140         resource = get_resource(dev, index);
141         
142         /* Initilize the resource */
143         resource->limit = 0xffff;
144         resource->flags |= IORESOURCE_IO;
145         
146         /* Set the resource size and alignment */
147         size = (0xffff & info->mask);
148         resource->size  = (~(size | 0xfffff800) + 1);
149         resource->align = log2(resource->size);
150         resource->gran  = resource->align;
151 }
152
153
154 static void pnp_read_resources(device_t dev)
155 {
156         struct pnp_info *info;
157         struct resource *resource;
158         pnp_set_logical_device(dev);
159
160         info = &pnp_dev_info[dev->path.u.pnp.device];
161
162         if (info->flags & PNP_IO0) {
163                 pnp_read_ioresource(dev, 0x60, &info->io0);
164         }
165         if (info->flags & PNP_IO1) {
166                 pnp_read_ioresource(dev, 0x62, &info->io1);
167         }
168         if (info->flags & PNP_IRQ0) {
169                 resource = get_resource(dev, 0x70);
170                 resource->size = 1;
171                 resource->flags |= IORESOURCE_IRQ;
172         }
173         if (info->flags & PNP_IRQ1) {
174                 resource = get_resource(dev, 0x72);
175                 resource->size = 1;
176                 resource->flags |= IORESOURCE_IRQ;
177         }
178         if (info->flags & PNP_DRQ0) {
179                 resource = get_resource(dev, 0x74);
180                 resource->size = 1;
181                 resource->flags |= IORESOURCE_DRQ;
182         }
183         if (info->flags & PNP_DRQ1) {
184                 resource = get_resource(dev, 0x75);
185                 resource->size = 1;
186                 resource->flags |= IORESOURCE_DRQ;
187         }
188 }
189
190 static void pnp_set_iobase(device_t dev, unsigned iobase, unsigned index)
191 {
192         /* Index == 0x60 or 0x62 */
193         pnp_write_config(dev, (iobase >> 8) & 0xff, index);
194         pnp_write_config(dev, iobase & 0xff, index + 1);
195 }
196
197 static void pnp_set_irq(device_t dev, unsigned irq, unsigned index)
198 {
199         /* Index == 0x70 or 0x72 */
200         pnp_write_config(dev, irq, index);
201 }
202
203 static void pnp_set_drq(device_t dev, unsigned drq, unsigned index)
204 {
205         /* Index == 0x74 */
206         pnp_write_config(dev, drq & 0xff, index);
207 }
208
209
210 static void pnp_set_resource(device_t dev, struct resource *resource)
211 {
212         if (!(resource->flags & IORESOURCE_SET)) {
213 #if 1
214                 printk_err("ERROR: %s %02x not allocated\n",
215                         dev_path(dev), resource->index);
216 #endif
217                 return;
218         }
219         if (resource->flags & IORESOURCE_IO) {
220                 pnp_set_iobase(dev, resource->base, resource->index);
221         }
222         else if (resource->flags & IORESOURCE_DRQ) {
223                 pnp_set_drq(dev, resource->base, resource->index);
224         }
225         else if (resource->flags  & IORESOURCE_IRQ) {
226                 pnp_set_irq(dev, resource->base, resource->index);
227         }
228         else {
229                 printk_err("ERROR: %s %02x unknown resource type\n",
230                         dev_path(dev), resource->index);
231                 return;
232         }
233         printk_debug(
234                 "%s %02x <- [0x%08lx - 0x%08lx %s\n",
235                 dev_path(dev),
236                 resource->index,
237                 resource->base,  resource->base + resource->size - 1,
238                 (resource->flags & IORESOURCE_IO)? "io":
239                 (resource->flags & IORESOURCE_DRQ)? "drq":
240                 (resource->flags & IORESOURCE_IRQ)? "irq":
241                 (resource->flags & IORESOURCE_MEM)? "mem":
242                 "???");
243 }
244
245 static void pnp_set_resources(device_t dev)
246 {
247         int i;
248         pnp_set_logical_device(dev);
249         for(i = 0; i < dev->resources; i++) {
250                 pnp_set_resource(dev, &dev->resource[i]);
251         }
252
253 }
254 static void pnp_enable_resources(device_t dev)
255 {
256         pnp_set_logical_device(dev);
257         pnp_set_enable(dev, 1);
258
259 }
260 static void pnp_enable(device_t dev)
261 {
262         pnp_set_logical_device(dev);
263         if (!dev->enable) {
264                 pnp_set_enable(dev, 0);
265         }
266 }
267
268 static struct device_operations pnp_ops = {
269         .read_resources   = pnp_read_resources,
270         .set_resources    = pnp_set_resources,
271         .enable_resources = pnp_enable_resources,
272         .enable           = pnp_enable,
273 };
274
275 #define MAX_FUNCTION 10
276 static void enumerate(struct chip *chip)
277 {
278         struct superio_NSC_pc87360_config *conf = (struct superio_NSC_pc87360_config *)chip->chip_info;
279         struct resource *resource;
280         struct device_path path;
281         device_t dev;
282         int i;
283
284         chip_enumerate(chip);
285         path.type       = DEVICE_PATH_PNP;
286         path.u.pnp.port = chip->dev->path.u.pnp.port;
287
288         /* Set the ops on the newly allocated devices */
289         for(i = 0; i <= WDT_DEVICE; i++) {
290                 path.u.pnp.device = i;
291                 dev = alloc_find_dev(chip->bus, &path);
292                 dev->ops = &pnp_ops;
293         }
294
295         /* Processes the hard codes for com1 */
296         path.u.pnp.device = COM1_DEVICE;
297         dev = alloc_find_dev(chip->bus, &path);
298         resource = get_resource(dev, 0x60);
299         if (conf->com1.base) {
300                 resource->base = conf->com1.base;
301                 resource->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_SET;
302         }
303         resource = get_resource(dev, 0x70);
304         if (conf->com1.irq) {
305                 resource->base = conf->com1.irq;
306                 resource->flags = IORESOURCE_IRQ | IORESOURCE_FIXED | IORESOURCE_SET;
307         }
308                 
309 }
310
311 struct chip_control superio_NSC_pc87360_control = {
312         .enable    = sio_enable,
313         .enumerate = enumerate,
314         .name      = "NSC 87360"
315 };