blob: 02d474e8d5cd896e80032305dbfb0a4c2e40d85f [file] [log] [blame]
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001/*
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>
Stefan Reinauer966d0e62006-04-06 21:37:10 +000012#include "i82801er.h"
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000013
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
40static 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
Stefan Reinauer966d0e62006-04-06 21:37:10 +000071static void i82801er_enable_serial_irqs(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000072{
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +000079static void i82801er_pci_dma_cfg(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000080{
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +000086static void i82801er_enable_lpc(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000087{
88 /* lpc i/f enable */
89 pci_write_config8(dev, LPC_EN, 0x0d);
90}
91
Stefan Reinauer966d0e62006-04-06 21:37:10 +000092typedef struct southbridge_intel_i82801er_config config_t;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000093
Stefan Reinauer966d0e62006-04-06 21:37:10 +000094static void set_i82801er_gpio_use_sel(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000095 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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000123static void set_i82801er_gpio_direction(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000124 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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000152static void set_i82801er_gpio_level(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000153 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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000187static void set_i82801er_gpio_inv(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000188 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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000208static void i82801er_pirq_init(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000209{
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000224static void i82801er_gpio_init(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000225{
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 */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000246 set_i82801er_gpio_use_sel(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000247
248 /* Set the IO direction */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000249 set_i82801er_gpio_direction(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000250
251 /* Setup the input inverters */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000252 set_i82801er_gpio_inv(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000253
254 /* Set the value on the GPIO output pins */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000255 set_i82801er_gpio_level(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000256
257}
258
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000259static void enable_hpet(struct device *dev)
260{
261const 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}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000281
282static void lpc_init(struct device *dev)
283{
284 uint8_t byte;
285 uint32_t value;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000286 int pwr_on=MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000287
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000297 i82801er_enable_serial_irqs(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000298
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000299 i82801er_pci_dma_cfg(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000300
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000301 i82801er_enable_lpc(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000302
303 /* Clear SATA to non raid */
304 pci_write_config8(dev, 0xae, 0x00);
305
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000306 get_option(&pwr_on, "power_on_after_fail");
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000307 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 */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000316 i82801er_pirq_init(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000317
318 /* Set the state of the gpio lines */
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000319 i82801er_gpio_init(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000320
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000330 enable_hpet(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000331}
332
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000333static void i82801er_lpc_read_resources(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000334{
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000354static void i82801er_lpc_enable_resources(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000355{
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
374static struct pci_operations lops_pci = {
375 .set_subsystem = 0,
376};
377
378static struct device_operations lpc_ops = {
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000379 .read_resources = i82801er_lpc_read_resources,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000380 .set_resources = pci_dev_set_resources,
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000381 .enable_resources = i82801er_lpc_enable_resources,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000382 .init = lpc_init,
383 .scan_bus = scan_static_bus,
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000384 .enable = i82801er_enable,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000385 .ops_pci = &lops_pci,
386};
387
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000388static const struct pci_driver lpc_driver __pci_driver = {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000389 .ops = &lpc_ops,
390 .vendor = PCI_VENDOR_ID_INTEL,
Uwe Hermanna29ec062007-11-04 03:21:37 +0000391 .device = PCI_DEVICE_ID_INTEL_82801ER_LPC,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000392};