df05cc85b797acc3b52afbe87c7c4b7e49aeb533
[coreboot.git] / src / southbridge / intel / i82801ex / i82801ex_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 "i82801ex.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 i82801ex_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 i82801ex_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 i82801ex_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_i82801ex_config config_t;
49
50 static void set_i82801ex_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_i82801ex_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_i82801ex_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_i82801ex_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 i82801ex_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 i82801ex_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_i82801ex_gpio_use_sel(dev, res, config);
203
204         /* Set the IO direction */
205         set_i82801ex_gpio_direction(dev, res, config);
206
207         /* Setup the input inverters */
208         set_i82801ex_gpio_inv(dev, res, config);
209
210         /* Set the value on the GPIO output pins */
211         set_i82801ex_gpio_level(dev, res, config);
212
213 }
214
215 static void enable_hpet(struct device *dev)
216 {
217         const unsigned long hpet_address = 0xfed00000;
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         pci_write_config32(dev, GEN_CNTL, dword);
235
236         printk(BIOS_DEBUG, "enabling HPET @0x%lx\n", hpet_address | (code <<12) );
237 }
238
239 static void lpc_init(struct device *dev)
240 {
241         uint8_t byte;
242         uint32_t value;
243         int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
244
245         /* IO APIC initialization */
246         value = pci_read_config32(dev, 0xd0);
247         value |= (1 << 8)|(1<<7)|(1<<1);
248         pci_write_config32(dev, 0xd0, value);
249         value = pci_read_config32(dev, 0xd4);
250         value |= (1<<1);
251         pci_write_config32(dev, 0xd4, value);
252         setup_ioapic(IO_APIC_ADDR, 0); // Don't rename IO APIC ID.
253
254         i82801ex_enable_serial_irqs(dev);
255
256         i82801ex_pci_dma_cfg(dev);
257
258         i82801ex_enable_lpc(dev);
259
260         /* Clear SATA to non raid */
261         pci_write_config8(dev, 0xae, 0x00);
262
263         get_option(&pwr_on, "power_on_after_fail");
264         byte = pci_read_config8(dev, 0xa4);
265         byte &= 0xfe;
266         if (!pwr_on) {
267                 byte |= 1;
268         }
269         pci_write_config8(dev, 0xa4, byte);
270         printk(BIOS_INFO, "set power %s after power fail\n", pwr_on?"on":"off");
271
272         /* Set up the PIRQ */
273         i82801ex_pirq_init(dev);
274
275         /* Set the state of the gpio lines */
276         i82801ex_gpio_init(dev);
277
278         /* Initialize the real time clock */
279         rtc_init(0);
280
281         /* Initialize isa dma */
282         isa_dma_init();
283
284         /* Disable IDE (needed when sata is enabled) */
285         pci_write_config8(dev, 0xf2, 0x60);
286
287         enable_hpet(dev);
288 }
289
290 static void i82801ex_lpc_read_resources(device_t dev)
291 {
292         struct resource *res;
293
294         /* Get the normal PCI resources of this device. */
295         pci_dev_read_resources(dev);
296
297         /* Add the ACPI BAR */
298         res = pci_get_resource(dev, ACPI_BAR);
299
300         /* Add the GPIO BAR */
301         res = pci_get_resource(dev, GPIO_BAR);
302
303         /* Add an extra subtractive resource for both memory and I/O. */
304         res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
305         res->base = 0;
306         res->size = 0x1000;
307         res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
308                      IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
309
310         res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
311         res->base = 0xff800000;
312         res->size = 0x00800000; /* 8 MB for flash */
313         res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
314                      IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
315
316         res = new_resource(dev, 3); /* IOAPIC */
317         res->base = 0xfec00000;
318         res->size = 0x00001000;
319         res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
320 }
321
322 static void i82801ex_lpc_enable_resources(device_t dev)
323 {
324         uint8_t acpi_cntl, gpio_cntl;
325
326         /* Enable the normal pci resources */
327         pci_dev_enable_resources(dev);
328
329         /* Enable the ACPI bar */
330         acpi_cntl = pci_read_config8(dev, 0x44);
331         acpi_cntl |= (1 << 4);
332         pci_write_config8(dev, 0x44, acpi_cntl);
333
334         /* Enable the GPIO bar */
335         gpio_cntl = pci_read_config8(dev, 0x5c);
336         gpio_cntl |= (1 << 4);
337         pci_write_config8(dev, 0x5c, gpio_cntl);
338 }
339
340 static struct pci_operations lops_pci = {
341         .set_subsystem = 0,
342 };
343
344 static struct device_operations lpc_ops  = {
345         .read_resources   = i82801ex_lpc_read_resources,
346         .set_resources    = pci_dev_set_resources,
347         .enable_resources = i82801ex_lpc_enable_resources,
348         .init             = lpc_init,
349         .scan_bus         = scan_static_bus,
350         .enable           = i82801ex_enable,
351         .ops_pci          = &lops_pci,
352 };
353
354 static const struct pci_driver lpc_driver __pci_driver = {
355         .ops    = &lpc_ops,
356         .vendor = PCI_VENDOR_ID_INTEL,
357         .device = PCI_DEVICE_ID_INTEL_82801ER_LPC,
358 };