blob: b97af3860a5e02fa1fd96b338514b1b9407538ee [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 Reinauer0401bd82010-01-16 18:31:34 +000012#include <arch/ioapic.h>
Stefan Reinauer138be832010-02-27 01:50:21 +000013#include "i82801ex.h"
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000014
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
Stefan Reinauer08670622009-06-30 15:17:49 +000022#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
23#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000024#endif
25
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000026#define SERIRQ_CNTL 0x64
Stefan Reinauer138be832010-02-27 01:50:21 +000027static void i82801ex_enable_serial_irqs(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000028{
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
Stefan Reinauer138be832010-02-27 01:50:21 +000035static void i82801ex_pci_dma_cfg(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000036{
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
Stefan Reinauer138be832010-02-27 01:50:21 +000042static void i82801ex_enable_lpc(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000043{
44 /* lpc i/f enable */
45 pci_write_config8(dev, LPC_EN, 0x0d);
46}
47
Stefan Reinauer138be832010-02-27 01:50:21 +000048typedef struct southbridge_intel_i82801ex_config config_t;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000049
Stefan Reinauer138be832010-02-27 01:50:21 +000050static void set_i82801ex_gpio_use_sel(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000051 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
Stefan Reinauer138be832010-02-27 01:50:21 +000079static void set_i82801ex_gpio_direction(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000080 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
Stefan Reinauer138be832010-02-27 01:50:21 +0000108static void set_i82801ex_gpio_level(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000109 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
Stefan Reinauer138be832010-02-27 01:50:21 +0000143static void set_i82801ex_gpio_inv(
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000144 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
Stefan Reinauer138be832010-02-27 01:50:21 +0000164static void i82801ex_pirq_init(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000165{
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
Stefan Reinauer138be832010-02-27 01:50:21 +0000180static void i82801ex_gpio_init(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000181{
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 */
Stefan Reinauer138be832010-02-27 01:50:21 +0000202 set_i82801ex_gpio_use_sel(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000203
204 /* Set the IO direction */
Stefan Reinauer138be832010-02-27 01:50:21 +0000205 set_i82801ex_gpio_direction(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000206
207 /* Setup the input inverters */
Stefan Reinauer138be832010-02-27 01:50:21 +0000208 set_i82801ex_gpio_inv(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000209
210 /* Set the value on the GPIO output pins */
Stefan Reinauer138be832010-02-27 01:50:21 +0000211 set_i82801ex_gpio_level(dev, res, config);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000212
213}
214
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000215static void enable_hpet(struct device *dev)
216{
Stefan Reinauerb319b172010-03-17 03:14:28 +0000217 const unsigned long hpet_address = 0xfed00000;
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000218
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);
Stefan Reinauer07190472010-03-17 17:50:48 +0000234 pci_write_config32(dev, GEN_CNTL, dword);
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000235
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000236 printk(BIOS_DEBUG, "enabling HPET @0x%lx\n", hpet_address | (code <<12) );
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000237}
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000238
239static void lpc_init(struct device *dev)
240{
241 uint8_t byte;
242 uint32_t value;
Stefan Reinauer08670622009-06-30 15:17:49 +0000243 int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000244
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);
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000252 setup_ioapic(IO_APIC_ADDR, 0); // Don't rename IO APIC ID.
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000253
Stefan Reinauer138be832010-02-27 01:50:21 +0000254 i82801ex_enable_serial_irqs(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000255
Stefan Reinauer138be832010-02-27 01:50:21 +0000256 i82801ex_pci_dma_cfg(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000257
Stefan Reinauer138be832010-02-27 01:50:21 +0000258 i82801ex_enable_lpc(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000259
260 /* Clear SATA to non raid */
261 pci_write_config8(dev, 0xae, 0x00);
262
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000263 get_option(&pwr_on, "power_on_after_fail");
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000264 byte = pci_read_config8(dev, 0xa4);
265 byte &= 0xfe;
266 if (!pwr_on) {
267 byte |= 1;
268 }
269 pci_write_config8(dev, 0xa4, byte);
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000270 printk(BIOS_INFO, "set power %s after power fail\n", pwr_on?"on":"off");
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000271
272 /* Set up the PIRQ */
Stefan Reinauer138be832010-02-27 01:50:21 +0000273 i82801ex_pirq_init(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000274
275 /* Set the state of the gpio lines */
Stefan Reinauer138be832010-02-27 01:50:21 +0000276 i82801ex_gpio_init(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000277
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
Stefan Reinauer966d0e62006-04-06 21:37:10 +0000287 enable_hpet(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000288}
289
Stefan Reinauer138be832010-02-27 01:50:21 +0000290static void i82801ex_lpc_read_resources(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000291{
292 struct resource *res;
293
Myles Watson29cc9ed2009-07-02 18:56:24 +0000294 /* Get the normal PCI resources of this device. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000295 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
Myles Watson29cc9ed2009-07-02 18:56:24 +0000303 /* Add an extra subtractive resource for both memory and I/O. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000304 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
Myles Watson29cc9ed2009-07-02 18:56:24 +0000305 res->base = 0;
306 res->size = 0x1000;
307 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
308 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000309
310 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
Myles Watson29cc9ed2009-07-02 18:56:24 +0000311 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;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000320}
321
Stefan Reinauer138be832010-02-27 01:50:21 +0000322static void i82801ex_lpc_enable_resources(device_t dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000323{
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 enable_childrens_resources(dev);
340}
341
342static struct pci_operations lops_pci = {
343 .set_subsystem = 0,
344};
345
346static struct device_operations lpc_ops = {
Stefan Reinauer138be832010-02-27 01:50:21 +0000347 .read_resources = i82801ex_lpc_read_resources,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000348 .set_resources = pci_dev_set_resources,
Stefan Reinauer138be832010-02-27 01:50:21 +0000349 .enable_resources = i82801ex_lpc_enable_resources,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000350 .init = lpc_init,
351 .scan_bus = scan_static_bus,
Stefan Reinauer138be832010-02-27 01:50:21 +0000352 .enable = i82801ex_enable,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000353 .ops_pci = &lops_pci,
354};
355
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000356static const struct pci_driver lpc_driver __pci_driver = {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000357 .ops = &lpc_ops,
358 .vendor = PCI_VENDOR_ID_INTEL,
Uwe Hermanna29ec062007-11-04 03:21:37 +0000359 .device = PCI_DEVICE_ID_INTEL_82801ER_LPC,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000360};