CMOS: Add set_option and rework get_option.
[coreboot.git] / src / southbridge / intel / i82801er / i82801er_lpc.c
1 /*
2  * (C) 2004 Linux Networx
3  */
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <device/pci_ops.h>
9 #include <pc80/mc146818rtc.h>
10 #include <pc80/isa-dma.h>
11 #include <arch/io.h>
12 #include "i82801er.h"
13
14 #define ACPI_BAR 0x40
15 #define GPIO_BAR 0x58
16
17 #define NMI_OFF 0
18 #define MAINBOARD_POWER_OFF 0
19 #define MAINBOARD_POWER_ON  1
20
21 #ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL
22 #define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
23 #endif
24
25 #define ALL             (0xff << 24)
26 #define NONE            (0)
27 #define DISABLED        (1 << 16)
28 #define ENABLED         (0 << 16)
29 #define TRIGGER_EDGE    (0 << 15)
30 #define TRIGGER_LEVEL   (1 << 15)
31 #define POLARITY_HIGH   (0 << 13)
32 #define POLARITY_LOW    (1 << 13)
33 #define PHYSICAL_DEST   (0 << 11)
34 #define LOGICAL_DEST    (1 << 11)
35 #define ExtINT          (7 << 8)
36 #define NMI             (4 << 8)
37 #define SMI             (2 << 8)
38 #define INT             (1 << 8)
39
40 static void setup_ioapic(void)
41 {
42         int i;
43         unsigned long value_low, value_high;
44         unsigned long ioapic_base = 0xfec00000;
45         volatile unsigned long *l;
46         unsigned interrupts;
47
48         l = (unsigned long *) ioapic_base;
49
50         l[0] = 0x01;
51         interrupts = (l[04] >> 16) & 0xff;
52         for (i = 0; i < interrupts; i++) {
53                 l[0] = (i * 2) + 0x10;
54                 l[4] = DISABLED;
55                 value_low = l[4];
56                 l[0] = (i * 2) + 0x11;
57                 l[4] = NONE; /* Should this be an address? */
58                 value_high = l[4];
59                 if (value_low == 0xffffffff) {
60                         printk_warning("IO APIC not responding.\n");
61                         return;
62                 }
63         }
64
65         /* Put the ioapic in virtual wire mode */
66         l[0] = 0 + 0x10;
67         l[4] = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
68 }
69
70 #define SERIRQ_CNTL 0x64
71 static void i82801er_enable_serial_irqs(device_t dev)
72 {
73         /* set packet length and toggle silent mode bit */
74         pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(1 << 6)|((21 - 17) << 2)|(0 << 0));
75         pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(0 << 6)|((21 - 17) << 2)|(0 << 0));
76 }
77
78 #define PCI_DMA_CFG 0x90
79 static void i82801er_pci_dma_cfg(device_t dev)
80 {
81         /* Set PCI DMA CFG to lpc I/F DMA */
82         pci_write_config16(dev, PCI_DMA_CFG, 0xfcff);
83 }
84
85 #define LPC_EN 0xe6
86 static void i82801er_enable_lpc(device_t dev)
87 {
88         /* lpc i/f enable */
89         pci_write_config8(dev, LPC_EN, 0x0d);
90 }
91
92 typedef struct southbridge_intel_i82801er_config config_t;
93
94 static void set_i82801er_gpio_use_sel(
95         device_t dev, struct resource *res, config_t *config)
96 {
97         uint32_t gpio_use_sel, gpio_use_sel2;
98         int i;
99
100         gpio_use_sel  = 0x1A003180;
101         gpio_use_sel2 = 0x00000007;
102         for(i = 0; i < 64; i++) {
103                 int val;
104                 switch(config->gpio[i] & ICH5R_GPIO_USE_MASK) {
105                 case ICH5R_GPIO_USE_AS_NATIVE: val = 0; break;
106                 case ICH5R_GPIO_USE_AS_GPIO:   val = 1; break;
107                 default:
108                         continue;
109                 }
110                 /* The caller is responsible for not playing with unimplemented bits */
111                 if (i < 32) {
112                         gpio_use_sel  &= ~( 1 << i);
113                         gpio_use_sel  |= (val << i);
114                 } else {
115                         gpio_use_sel2 &= ~( 1 << (i - 32));
116                         gpio_use_sel2 |= (val << (i - 32));
117                 }
118         }
119         outl(gpio_use_sel,  res->base + 0x00);
120         outl(gpio_use_sel2, res->base + 0x30);
121 }
122
123 static void set_i82801er_gpio_direction(
124         device_t dev, struct resource *res, config_t *config)
125 {
126         uint32_t gpio_io_sel, gpio_io_sel2;
127         int i;
128
129         gpio_io_sel  = 0x0000ffff;
130         gpio_io_sel2 = 0x00000300;
131         for(i = 0; i < 64; i++) {
132                 int val;
133                 switch(config->gpio[i] & ICH5R_GPIO_SEL_MASK) {
134                 case ICH5R_GPIO_SEL_OUTPUT: val = 0; break;
135                 case ICH5R_GPIO_SEL_INPUT:  val = 1; break;
136                 default: 
137                         continue;
138                 }
139                 /* The caller is responsible for not playing with unimplemented bits */
140                 if (i < 32) {
141                         gpio_io_sel  &= ~( 1 << i);
142                         gpio_io_sel  |= (val << i);
143                 } else {
144                         gpio_io_sel2 &= ~( 1 << (i - 32));
145                         gpio_io_sel2 |= (val << (i - 32));
146                 }
147         }
148         outl(gpio_io_sel,  res->base + 0x04);
149         outl(gpio_io_sel2, res->base + 0x34);
150 }
151
152 static void set_i82801er_gpio_level(
153         device_t dev, struct resource *res, config_t *config)
154 {
155         uint32_t gpio_lvl, gpio_lvl2;
156         uint32_t gpio_blink;
157         int i;
158
159         gpio_lvl   = 0x1b3f0000;
160         gpio_blink = 0x00040000;
161         gpio_lvl2  = 0x00030207;
162         for(i = 0; i < 64; i++) {
163                 int val, blink;
164                 switch(config->gpio[i] & ICH5R_GPIO_LVL_MASK) {
165                 case ICH5R_GPIO_LVL_LOW:   val = 0; blink = 0; break;
166                 case ICH5R_GPIO_LVL_HIGH:  val = 1; blink = 0; break;
167                 case ICH5R_GPIO_LVL_BLINK: val = 1; blink = 1; break;
168                 default: 
169                         continue;
170                 }
171                 /* The caller is responsible for not playing with unimplemented bits */
172                 if (i < 32) {
173                         gpio_lvl   &= ~(   1 << i);
174                         gpio_blink &= ~(   1 << i);
175                         gpio_lvl   |= (  val << i);
176                         gpio_blink |= (blink << i);
177                 } else {
178                         gpio_lvl2  &= ~( 1 << (i - 32));
179                         gpio_lvl2  |= (val << (i - 32));
180                 }
181         }
182         outl(gpio_lvl,   res->base + 0x0c);
183         outl(gpio_blink, res->base + 0x18);
184         outl(gpio_lvl2,  res->base + 0x38);
185 }
186
187 static void set_i82801er_gpio_inv(
188         device_t dev, struct resource *res, config_t *config)
189 {
190         uint32_t gpio_inv;
191         int i;
192
193         gpio_inv   = 0x00000000;
194         for(i = 0; i < 32; i++) {
195                 int val;
196                 switch(config->gpio[i] & ICH5R_GPIO_INV_MASK) {
197                 case ICH5R_GPIO_INV_OFF: val = 0; break;
198                 case ICH5R_GPIO_INV_ON:  val = 1; break;
199                 default: 
200                         continue;
201                 }
202                 gpio_inv &= ~( 1 << i);
203                 gpio_inv |= (val << i);
204         }
205         outl(gpio_inv,   res->base + 0x2c);
206 }
207
208 static void i82801er_pirq_init(device_t dev)
209 {
210         config_t *config;
211
212         /* Get the chip configuration */
213         config = dev->chip_info;
214
215         if(config->pirq_a_d) {
216                 pci_write_config32(dev, 0x60, config->pirq_a_d);
217         }
218         if(config->pirq_e_h) {
219                 pci_write_config32(dev, 0x68, config->pirq_e_h);
220         }
221 }
222
223
224 static void i82801er_gpio_init(device_t dev)
225 {
226         struct resource *res;
227         config_t *config;
228
229         /* Skip if I don't have any configuration */
230         if (!dev->chip_info) {
231                 return;
232         }
233         /* The programmer is responsible for ensuring
234          * a valid gpio configuration.
235          */
236
237         /* Get the chip configuration */
238         config = dev->chip_info;
239         /* Find the GPIO bar */
240         res = find_resource(dev, GPIO_BAR);
241         if (!res) {
242                 return; 
243         }
244
245         /* Set the use selects */
246         set_i82801er_gpio_use_sel(dev, res, config);
247
248         /* Set the IO direction */
249         set_i82801er_gpio_direction(dev, res, config);
250
251         /* Setup the input inverters */
252         set_i82801er_gpio_inv(dev, res, config);
253
254         /* Set the value on the GPIO output pins */
255         set_i82801er_gpio_level(dev, res, config);
256
257 }
258
259 static void enable_hpet(struct device *dev)
260 {
261 const unsigned long hpet_address = 0xfed0000;
262
263         uint32_t dword;
264         uint32_t code = (0 & 0x3);
265
266         dword = pci_read_config32(dev, GEN_CNTL);
267         dword |= (1 << 17); /* enable hpet */
268
269         /* Bits [16:15]  Memory Address Range
270          *          00   FED0_0000h - FED0_03FFh
271          *          01   FED0_1000h - FED0_13FFh
272          *          10   FED0_2000h - FED0_23FFh
273          *          11   FED0_3000h - FED0_33FFh
274          */
275
276         dword &= ~(3 << 15); /* clear it */
277         dword |= (code<<15);
278
279         printk_debug("enabling HPET @0x%x\n", hpet_address | (code <<12) );
280 }
281
282 static void lpc_init(struct device *dev)
283 {
284         uint8_t byte;
285         uint32_t value;
286         uint32_t pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
287
288         /* IO APIC initialization */
289         value = pci_read_config32(dev, 0xd0);
290         value |= (1 << 8)|(1<<7)|(1<<1);
291         pci_write_config32(dev, 0xd0, value);
292         value = pci_read_config32(dev, 0xd4);
293         value |= (1<<1);
294         pci_write_config32(dev, 0xd4, value);
295         setup_ioapic();
296
297         i82801er_enable_serial_irqs(dev);
298
299         i82801er_pci_dma_cfg(dev);
300
301         i82801er_enable_lpc(dev);
302
303         /* Clear SATA to non raid */
304         pci_write_config8(dev, 0xae, 0x00);
305
306         get_option("power_on_after_fail", &pwr_on);
307         byte = pci_read_config8(dev, 0xa4);
308         byte &= 0xfe;
309         if (!pwr_on) {
310                 byte |= 1;
311         }
312         pci_write_config8(dev, 0xa4, byte);
313         printk_info("set power %s after power fail\n", pwr_on?"on":"off");
314
315         /* Set up the PIRQ */
316         i82801er_pirq_init(dev);
317         
318         /* Set the state of the gpio lines */
319         i82801er_gpio_init(dev);
320
321         /* Initialize the real time clock */
322         rtc_init(0);
323
324         /* Initialize isa dma */
325         isa_dma_init();
326
327         /* Disable IDE (needed when sata is enabled) */
328         pci_write_config8(dev, 0xf2, 0x60);
329         
330         enable_hpet(dev);
331 }
332
333 static void i82801er_lpc_read_resources(device_t dev)
334 {
335         struct resource *res;
336
337         /* Get the normal pci resources of this device */
338         pci_dev_read_resources(dev);
339
340         /* Add the ACPI BAR */
341         res = pci_get_resource(dev, ACPI_BAR);
342
343         /* Add the GPIO BAR */
344         res = pci_get_resource(dev, GPIO_BAR);
345
346         /* Add an extra subtractive resource for both memory and I/O */
347         res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
348         res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
349
350         res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
351         res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
352 }
353
354 static void i82801er_lpc_enable_resources(device_t dev)
355 {
356         uint8_t acpi_cntl, gpio_cntl;
357
358         /* Enable the normal pci resources */
359         pci_dev_enable_resources(dev);
360
361         /* Enable the ACPI bar */
362         acpi_cntl = pci_read_config8(dev, 0x44);
363         acpi_cntl |= (1 << 4);
364         pci_write_config8(dev, 0x44, acpi_cntl);
365         
366         /* Enable the GPIO bar */
367         gpio_cntl = pci_read_config8(dev, 0x5c);
368         gpio_cntl |= (1 << 4);
369         pci_write_config8(dev, 0x5c, gpio_cntl);
370
371         enable_childrens_resources(dev);
372 }
373
374 static struct pci_operations lops_pci = {
375         .set_subsystem = 0,
376 };
377
378 static struct device_operations lpc_ops  = {
379         .read_resources   = i82801er_lpc_read_resources,
380         .set_resources    = pci_dev_set_resources,
381         .enable_resources = i82801er_lpc_enable_resources,
382         .init             = lpc_init,
383         .scan_bus         = scan_static_bus,
384         .enable           = i82801er_enable,
385         .ops_pci          = &lops_pci,
386 };
387
388 static const struct pci_driver lpc_driver __pci_driver = {
389         .ops    = &lpc_ops,
390         .vendor = PCI_VENDOR_ID_INTEL,
391         .device = PCI_DEVICE_ID_INTEL_82801ER_LPC,
392 };