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