blob: e052150abad5418989b71006a35134784edbe4f9 [file] [log] [blame]
Stefan Reinauer8e073822012-04-04 00:07:22 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Stefan Reinauer8e073822012-04-04 00:07:22 +020019 */
20
21#include <console/console.h>
22#include <device/device.h>
23#include <device/pci.h>
24#include <device/pci_ids.h>
25#include <pc80/mc146818rtc.h>
26#include <pc80/isa-dma.h>
27#include <pc80/i8259.h>
28#include <arch/io.h>
29#include <arch/ioapic.h>
30#include <arch/acpi.h>
31#include <cpu/cpu.h>
Duncan Laurie800e9502012-06-23 17:06:47 -070032#include <elog.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020033#include "pch.h"
34
35#define NMI_OFF 0
36
37#define ENABLE_ACPI_MODE_IN_COREBOOT 0
38#define TEST_SMM_FLASH_LOCKDOWN 0
39
40typedef struct southbridge_intel_bd82x6x_config config_t;
41
Paul Menzel9c50e6a2013-05-03 12:23:39 +020042/**
43 * Set miscellanous static southbridge features.
44 *
45 * @param dev PCI device with I/O APIC control registers
46 */
47static void pch_enable_ioapic(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020048{
Stefan Reinauer8e073822012-04-04 00:07:22 +020049 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +020050
Paul Menzel9c50e6a2013-05-03 12:23:39 +020051 /* Enable ACPI I/O range decode */
52 pci_write_config8(dev, ACPI_CNTL, ACPI_EN);
Stefan Reinauer8e073822012-04-04 00:07:22 +020053
Paul Menzel9c50e6a2013-05-03 12:23:39 +020054 set_ioapic_id(IO_APIC_ADDR, 0x02);
Stefan Reinauer8e073822012-04-04 00:07:22 +020055
56 /* affirm full set of redirection table entries ("write once") */
Paul Menzel9c50e6a2013-05-03 12:23:39 +020057 reg32 = io_apic_read(IO_APIC_ADDR, 0x01);
58 io_apic_write(IO_APIC_ADDR, 0x01, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +020059
Paul Menzel9c50e6a2013-05-03 12:23:39 +020060 /*
61 * Select Boot Configuration register (0x03) and
62 * use Processor System Bus (0x01) to deliver interrupts.
63 */
64 io_apic_write(IO_APIC_ADDR, 0x03, 0x01);
Stefan Reinauer8e073822012-04-04 00:07:22 +020065}
66
67static void pch_enable_serial_irqs(struct device *dev)
68{
69 /* Set packet length and toggle silent mode bit for one frame. */
70 pci_write_config8(dev, SERIRQ_CNTL,
71 (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0));
72#if !CONFIG_SERIRQ_CONTINUOUS_MODE
73 pci_write_config8(dev, SERIRQ_CNTL,
74 (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0));
75#endif
76}
77
78/* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control
79 * 0x00 - 0000 = Reserved
80 * 0x01 - 0001 = Reserved
81 * 0x02 - 0010 = Reserved
82 * 0x03 - 0011 = IRQ3
83 * 0x04 - 0100 = IRQ4
84 * 0x05 - 0101 = IRQ5
85 * 0x06 - 0110 = IRQ6
86 * 0x07 - 0111 = IRQ7
87 * 0x08 - 1000 = Reserved
88 * 0x09 - 1001 = IRQ9
89 * 0x0A - 1010 = IRQ10
90 * 0x0B - 1011 = IRQ11
91 * 0x0C - 1100 = IRQ12
92 * 0x0D - 1101 = Reserved
93 * 0x0E - 1110 = IRQ14
94 * 0x0F - 1111 = IRQ15
95 * PIRQ[n]_ROUT[7] - PIRQ Routing Control
96 * 0x80 - The PIRQ is not routed.
97 */
98
99static void pch_pirq_init(device_t dev)
100{
101 device_t irq_dev;
102 /* Get the chip configuration */
103 config_t *config = dev->chip_info;
104
105 pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
106 pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
107 pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
108 pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);
109
110 pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
111 pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
112 pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
113 pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);
114
115 /* Eric Biederman once said we should let the OS do this.
116 * I am not so sure anymore he was right.
117 */
118
119 for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
120 u8 int_pin=0, int_line=0;
121
122 if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI)
123 continue;
124
125 int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);
126
127 switch (int_pin) {
128 case 1: /* INTA# */ int_line = config->pirqa_routing; break;
129 case 2: /* INTB# */ int_line = config->pirqb_routing; break;
130 case 3: /* INTC# */ int_line = config->pirqc_routing; break;
131 case 4: /* INTD# */ int_line = config->pirqd_routing; break;
132 }
133
134 if (!int_line)
135 continue;
136
137 pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
138 }
139}
140
141static void pch_gpi_routing(device_t dev)
142{
143 /* Get the chip configuration */
144 config_t *config = dev->chip_info;
145 u32 reg32 = 0;
146
147 /* An array would be much nicer here, or some
148 * other method of doing this.
149 */
150 reg32 |= (config->gpi0_routing & 0x03) << 0;
151 reg32 |= (config->gpi1_routing & 0x03) << 2;
152 reg32 |= (config->gpi2_routing & 0x03) << 4;
153 reg32 |= (config->gpi3_routing & 0x03) << 6;
154 reg32 |= (config->gpi4_routing & 0x03) << 8;
155 reg32 |= (config->gpi5_routing & 0x03) << 10;
156 reg32 |= (config->gpi6_routing & 0x03) << 12;
157 reg32 |= (config->gpi7_routing & 0x03) << 14;
158 reg32 |= (config->gpi8_routing & 0x03) << 16;
159 reg32 |= (config->gpi9_routing & 0x03) << 18;
160 reg32 |= (config->gpi10_routing & 0x03) << 20;
161 reg32 |= (config->gpi11_routing & 0x03) << 22;
162 reg32 |= (config->gpi12_routing & 0x03) << 24;
163 reg32 |= (config->gpi13_routing & 0x03) << 26;
164 reg32 |= (config->gpi14_routing & 0x03) << 28;
165 reg32 |= (config->gpi15_routing & 0x03) << 30;
166
167 pci_write_config32(dev, 0xb8, reg32);
168}
169
170static void pch_power_options(device_t dev)
171{
172 u8 reg8;
173 u16 reg16, pmbase;
174 u32 reg32;
175 const char *state;
176 /* Get the chip configuration */
177 config_t *config = dev->chip_info;
178
179 int pwr_on=CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
180 int nmi_option;
181
182 /* Which state do we want to goto after g3 (power restored)?
183 * 0 == S0 Full On
184 * 1 == S5 Soft Off
185 *
186 * If the option is not existent (Laptops), use Kconfig setting.
187 */
188 get_option(&pwr_on, "power_on_after_fail");
189
190 reg16 = pci_read_config16(dev, GEN_PMCON_3);
191 reg16 &= 0xfffe;
192 switch (pwr_on) {
193 case MAINBOARD_POWER_OFF:
194 reg16 |= 1;
195 state = "off";
196 break;
197 case MAINBOARD_POWER_ON:
198 reg16 &= ~1;
199 state = "on";
200 break;
201 case MAINBOARD_POWER_KEEP:
202 reg16 &= ~1;
203 state = "state keep";
204 break;
205 default:
206 state = "undefined";
207 }
208
209 reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
210 reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
211
212 reg16 &= ~(1 << 10);
213 reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
214
215 reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
216
217 pci_write_config16(dev, GEN_PMCON_3, reg16);
218 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
219
220 /* Set up NMI on errors. */
221 reg8 = inb(0x61);
222 reg8 &= 0x0f; /* Higher Nibble must be 0 */
223 reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
224 // reg8 &= ~(1 << 2); /* PCI SERR# Enable */
225 reg8 |= (1 << 2); /* PCI SERR# Disable for now */
226 outb(reg8, 0x61);
227
228 reg8 = inb(0x70);
229 nmi_option = NMI_OFF;
230 get_option(&nmi_option, "nmi");
231 if (nmi_option) {
232 printk(BIOS_INFO, "NMI sources enabled.\n");
233 reg8 &= ~(1 << 7); /* Set NMI. */
234 } else {
235 printk(BIOS_INFO, "NMI sources disabled.\n");
236 reg8 |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW */
237 }
238 outb(reg8, 0x70);
239
240 /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
241 reg16 = pci_read_config16(dev, GEN_PMCON_1);
242 reg16 &= ~(3 << 0); // SMI# rate 1 minute
243 reg16 &= ~(1 << 10); // Disable BIOS_PCI_EXP_EN for native PME
244#if DEBUG_PERIODIC_SMIS
245 /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using
246 * periodic SMIs.
247 */
248 reg16 |= (3 << 0); // Periodic SMI every 8s
249#endif
250 pci_write_config16(dev, GEN_PMCON_1, reg16);
251
252 // Set the board's GPI routing.
253 pch_gpi_routing(dev);
254
255 pmbase = pci_read_config16(dev, 0x40) & 0xfffe;
256
257 outl(config->gpe0_en, pmbase + GPE0_EN);
258 outw(config->alt_gp_smi_en, pmbase + ALT_GP_SMI_EN);
259
260 /* Set up power management block and determine sleep mode */
261 reg32 = inl(pmbase + 0x04); // PM1_CNT
262 reg32 &= ~(7 << 10); // SLP_TYP
263 reg32 |= (1 << 0); // SCI_EN
264 outl(reg32, pmbase + 0x04);
265
266 /* Clear magic status bits to prevent unexpected wake */
267 reg32 = RCBA32(0x3310);
268 reg32 |= (1 << 4)|(1 << 5)|(1 << 0);
269 RCBA32(0x3310) = reg32;
270
271 reg32 = RCBA32(0x3f02);
272 reg32 &= ~0xf;
273 RCBA32(0x3f02) = reg32;
274}
275
276static void pch_rtc_init(struct device *dev)
277{
278 u8 reg8;
279 int rtc_failed;
280
281 reg8 = pci_read_config8(dev, GEN_PMCON_3);
282 rtc_failed = reg8 & RTC_BATTERY_DEAD;
283 if (rtc_failed) {
284 reg8 &= ~RTC_BATTERY_DEAD;
285 pci_write_config8(dev, GEN_PMCON_3, reg8);
Duncan Laurie800e9502012-06-23 17:06:47 -0700286#if CONFIG_ELOG
287 elog_add_event(ELOG_TYPE_RTC_RESET);
288#endif
Stefan Reinauer8e073822012-04-04 00:07:22 +0200289 }
290 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
291
292 rtc_init(rtc_failed);
293}
294
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700295/* CougarPoint PCH Power Management init */
296static void cpt_pm_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200297{
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700298 printk(BIOS_DEBUG, "CougarPoint PM init\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200299 pci_write_config8(dev, 0xa9, 0x47);
300 RCBA32_AND_OR(0x2238, ~0UL, (1 << 6)|(1 << 0));
301 RCBA32_AND_OR(0x228c, ~0UL, (1 << 0));
302 RCBA16_AND_OR(0x1100, ~0UL, (1 << 13)|(1 << 14));
303 RCBA16_AND_OR(0x0900, ~0UL, (1 << 14));
304 RCBA32(0x2304) = 0xc0388400;
305 RCBA32_AND_OR(0x2314, ~0UL, (1 << 5)|(1 << 18));
306 RCBA32_AND_OR(0x2320, ~0UL, (1 << 15)|(1 << 1));
307 RCBA32_AND_OR(0x3314, ~0x1f, 0xf);
308 RCBA32(0x3318) = 0x050f0000;
309 RCBA32(0x3324) = 0x04000000;
310 RCBA32_AND_OR(0x3340, ~0UL, 0xfffff);
311 RCBA32_AND_OR(0x3344, ~0UL, (1 << 1));
312 RCBA32(0x3360) = 0x0001c000;
313 RCBA32(0x3368) = 0x00061100;
314 RCBA32(0x3378) = 0x7f8fdfff;
315 RCBA32(0x337c) = 0x000003fc;
316 RCBA32(0x3388) = 0x00001000;
317 RCBA32(0x3390) = 0x0001c000;
318 RCBA32(0x33a0) = 0x00000800;
319 RCBA32(0x33b0) = 0x00001000;
320 RCBA32(0x33c0) = 0x00093900;
321 RCBA32(0x33cc) = 0x24653002;
322 RCBA32(0x33d0) = 0x062108fe;
323 RCBA32_AND_OR(0x33d4, 0xf000f000, 0x00670060);
324 RCBA32(0x3a28) = 0x01010000;
325 RCBA32(0x3a2c) = 0x01010404;
326 RCBA32(0x3a80) = 0x01041041;
327 RCBA32_AND_OR(0x3a84, ~0x0000ffff, 0x00001001);
328 RCBA32_AND_OR(0x3a84, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
329 RCBA32_AND_OR(0x3a88, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
330 RCBA32(0x3a6c) = 0x00000001;
331 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
332 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
333 RCBA32(0x33c8) = 0;
334 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
335}
336
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700337/* PantherPoint PCH Power Management init */
338static void ppt_pm_init(struct device *dev)
339{
340 printk(BIOS_DEBUG, "PantherPoint PM init\n");
341 pci_write_config8(dev, 0xa9, 0x47);
342 RCBA32_AND_OR(0x2238, ~0UL, (1 << 0));
343 RCBA32_AND_OR(0x228c, ~0UL, (1 << 0));
344 RCBA16_AND_OR(0x1100, ~0UL, (1 << 13)|(1 << 14));
345 RCBA16_AND_OR(0x0900, ~0UL, (1 << 14));
346 RCBA32(0x2304) = 0xc03b8400;
347 RCBA32_AND_OR(0x2314, ~0UL, (1 << 5)|(1 << 18));
348 RCBA32_AND_OR(0x2320, ~0UL, (1 << 15)|(1 << 1));
349 RCBA32_AND_OR(0x3314, ~0x1f, 0xf);
350 RCBA32(0x3318) = 0x054f0000;
351 RCBA32(0x3324) = 0x04000000;
352 RCBA32_AND_OR(0x3340, ~0UL, 0xfffff);
353 RCBA32_AND_OR(0x3344, ~0UL, (1 << 1)|(1 << 0));
354 RCBA32(0x3360) = 0x0001c000;
355 RCBA32(0x3368) = 0x00061100;
356 RCBA32(0x3378) = 0x7f8fdfff;
357 RCBA32(0x337c) = 0x000003fd;
358 RCBA32(0x3388) = 0x00001000;
359 RCBA32(0x3390) = 0x0001c000;
360 RCBA32(0x33a0) = 0x00000800;
361 RCBA32(0x33b0) = 0x00001000;
362 RCBA32(0x33c0) = 0x00093900;
363 RCBA32(0x33cc) = 0x24653002;
364 RCBA32(0x33d0) = 0x067388fe;
365 RCBA32_AND_OR(0x33d4, 0xf000f000, 0x00670060);
366 RCBA32(0x3a28) = 0x01010000;
367 RCBA32(0x3a2c) = 0x01010404;
368 RCBA32(0x3a80) = 0x01040000;
369 RCBA32_AND_OR(0x3a84, ~0x0000ffff, 0x00001001);
370 RCBA32_AND_OR(0x3a84, ~0UL, (1 << 24)); /* SATA 2/3 disabled */
371 RCBA32_AND_OR(0x3a88, ~0UL, (1 << 0)); /* SATA 4/5 disabled */
372 RCBA32(0x3a6c) = 0x00000001;
373 RCBA32_AND_OR(0x2344, 0x00ffff00, 0xff00000c);
374 RCBA32_AND_OR(0x80c, ~(0xff << 20), 0x11 << 20);
375 RCBA32_AND_OR(0x33a4, ~0UL, (1 << 0));
376 RCBA32(0x33c8) = 0;
377 RCBA32_AND_OR(0x21b0, ~0UL, 0xf);
378}
379
Stefan Reinauer8e073822012-04-04 00:07:22 +0200380static void enable_hpet(void)
381{
382 u32 reg32;
383
384 /* Move HPET to default address 0xfed00000 and enable it */
385 reg32 = RCBA32(HPTC);
386 reg32 |= (1 << 7); // HPET Address Enable
387 reg32 &= ~(3 << 0);
388 RCBA32(HPTC) = reg32;
389}
390
391static void enable_clock_gating(device_t dev)
392{
393 u32 reg32;
394 u16 reg16;
395
396 RCBA32_AND_OR(0x2234, ~0UL, 0xf);
397
398 reg16 = pci_read_config16(dev, GEN_PMCON_1);
399 reg16 |= (1 << 2) | (1 << 11);
400 pci_write_config16(dev, GEN_PMCON_1, reg16);
401
402 pch_iobp_update(0xEB007F07, ~0UL, (1 << 31));
403 pch_iobp_update(0xEB004000, ~0UL, (1 << 7));
404 pch_iobp_update(0xEC007F07, ~0UL, (1 << 31));
405 pch_iobp_update(0xEC004000, ~0UL, (1 << 7));
406
407 reg32 = RCBA32(CG);
408 reg32 |= (1 << 31);
409 reg32 |= (1 << 29) | (1 << 28);
410 reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
411 reg32 |= (1 << 16);
412 reg32 |= (1 << 17);
413 reg32 |= (1 << 18);
414 reg32 |= (1 << 22);
415 reg32 |= (1 << 23);
416 reg32 &= ~(1 << 20);
417 reg32 |= (1 << 19);
418 reg32 |= (1 << 0);
419 reg32 |= (0xf << 1);
420 RCBA32(CG) = reg32;
421
422 RCBA32_OR(0x38c0, 0x7);
423 RCBA32_OR(0x36d4, 0x6680c004);
424 RCBA32_OR(0x3564, 0x3);
425}
426
427#if CONFIG_HAVE_SMI_HANDLER
428static void pch_lock_smm(struct device *dev)
429{
430#if TEST_SMM_FLASH_LOCKDOWN
431 u8 reg8;
432#endif
433
Duncan Laurie95be1d62012-04-09 12:31:43 -0700434 if (acpi_slp_type != 3) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200435#if ENABLE_ACPI_MODE_IN_COREBOOT
Duncan Laurie95be1d62012-04-09 12:31:43 -0700436 printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n");
437 outb(0xe1, 0xb2); // Enable ACPI mode
438 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200439#else
Duncan Laurie95be1d62012-04-09 12:31:43 -0700440 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
441 outb(0x1e, 0xb2); // Disable ACPI mode
442 printk(BIOS_DEBUG, "done.\n");
Stefan Reinauer8e073822012-04-04 00:07:22 +0200443#endif
Duncan Laurie95be1d62012-04-09 12:31:43 -0700444 }
445
Stefan Reinauer8e073822012-04-04 00:07:22 +0200446 /* Don't allow evil boot loaders, kernels, or
447 * userspace applications to deceive us:
448 */
449 smm_lock();
450
451#if TEST_SMM_FLASH_LOCKDOWN
452 /* Now try this: */
453 printk(BIOS_DEBUG, "Locking BIOS to RO... ");
454 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
455 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
456 (reg8&1)?"rw":"ro");
457 reg8 &= ~(1 << 0); /* clear BIOSWE */
458 pci_write_config8(dev, 0xdc, reg8);
459 reg8 |= (1 << 1); /* set BLE */
460 pci_write_config8(dev, 0xdc, reg8);
461 printk(BIOS_DEBUG, "ok.\n");
462 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
463 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
464 (reg8&1)?"rw":"ro");
465
466 printk(BIOS_DEBUG, "Writing:\n");
467 *(volatile u8 *)0xfff00000 = 0x00;
468 printk(BIOS_DEBUG, "Testing:\n");
469 reg8 |= (1 << 0); /* set BIOSWE */
470 pci_write_config8(dev, 0xdc, reg8);
471
472 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
473 printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off",
474 (reg8&1)?"rw":"ro");
475 printk(BIOS_DEBUG, "Done.\n");
476#endif
477}
478#endif
479
480static void pch_disable_smm_only_flashing(struct device *dev)
481{
482 u8 reg8;
483
484 printk(BIOS_SPEW, "Enabling BIOS updates outside of SMM... ");
485 reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */
486 reg8 &= ~(1 << 5);
487 pci_write_config8(dev, 0xdc, reg8);
488}
489
490static void pch_fixups(struct device *dev)
491{
492 u8 gen_pmcon_2;
493
494 /* Indicate DRAM init done for MRC S3 to know it can resume */
495 gen_pmcon_2 = pci_read_config8(dev, GEN_PMCON_2);
496 gen_pmcon_2 |= (1 << 7);
497 pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2);
498
499 /*
500 * Enable DMI ASPM in the PCH
501 */
502 RCBA32_AND_OR(0x2304, ~(1 << 10), 0);
503 RCBA32_OR(0x21a4, (1 << 11)|(1 << 10));
504 RCBA32_OR(0x21a8, 0x3);
505}
506
507static void pch_decode_init(struct device *dev)
508{
509 config_t *config = dev->chip_info;
510
511 printk(BIOS_DEBUG, "pch_decode_init\n");
512
513 pci_write_config32(dev, LPC_GEN1_DEC, config->gen1_dec);
514 pci_write_config32(dev, LPC_GEN2_DEC, config->gen2_dec);
515 pci_write_config32(dev, LPC_GEN3_DEC, config->gen3_dec);
516 pci_write_config32(dev, LPC_GEN4_DEC, config->gen4_dec);
517}
518
519static void lpc_init(struct device *dev)
520{
521 printk(BIOS_DEBUG, "pch: lpc_init\n");
522
523 /* Set the value for PCI command register. */
524 pci_write_config16(dev, PCI_COMMAND, 0x000f);
525
526 /* IO APIC initialization. */
Paul Menzel9c50e6a2013-05-03 12:23:39 +0200527 pch_enable_ioapic(dev);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200528
529 pch_enable_serial_irqs(dev);
530
531 /* Setup the PIRQ. */
532 pch_pirq_init(dev);
533
534 /* Setup power options. */
535 pch_power_options(dev);
536
537 /* Initialize power management */
Duncan Laurie3f6a4d72012-06-28 13:03:40 -0700538 switch (pch_silicon_type()) {
539 case PCH_TYPE_CPT: /* CougarPoint */
540 cpt_pm_init(dev);
541 break;
542 case PCH_TYPE_PPT: /* PantherPoint */
543 ppt_pm_init(dev);
544 break;
545 default:
546 printk(BIOS_ERR, "Unknown Chipset: 0x%04x\n", dev->device);
547 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200548
549 /* Set the state of the GPIO lines. */
550 //gpio_init(dev);
551
552 /* Initialize the real time clock. */
553 pch_rtc_init(dev);
554
555 /* Initialize ISA DMA. */
556 isa_dma_init();
557
558 /* Initialize the High Precision Event Timers, if present. */
559 enable_hpet();
560
561 /* Initialize Clock Gating */
562 enable_clock_gating(dev);
563
564 setup_i8259();
565
566 /* The OS should do this? */
567 /* Interrupt 9 should be level triggered (SCI) */
568 i8259_configure_irq_trigger(9, 1);
569
570 pch_disable_smm_only_flashing(dev);
571
572#if CONFIG_HAVE_SMI_HANDLER
573 pch_lock_smm(dev);
574#endif
575
576 pch_fixups(dev);
577}
578
579static void pch_lpc_read_resources(device_t dev)
580{
581 struct resource *res;
Marc Jonesa0bec172012-07-13 14:14:34 -0600582 config_t *config = dev->chip_info;
583 u8 io_index = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200584
585 /* Get the normal PCI resources of this device. */
586 pci_dev_read_resources(dev);
587
588 /* Add an extra subtractive resource for both memory and I/O. */
Marc Jonesa0bec172012-07-13 14:14:34 -0600589 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200590 res->base = 0;
591 res->size = 0x1000;
592 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
593 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
594
Marc Jonesa0bec172012-07-13 14:14:34 -0600595 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200596 res->base = 0xff800000;
597 res->size = 0x00800000; /* 8 MB for flash */
598 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
599 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
600
601 res = new_resource(dev, 3); /* IOAPIC */
602 res->base = IO_APIC_ADDR;
603 res->size = 0x00001000;
604 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Marc Jonesa0bec172012-07-13 14:14:34 -0600605
606 /* Set PCH IO decode ranges if required.*/
607 if ((config->gen1_dec & 0xFFFC) > 0x1000) {
608 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
609 res->base = config->gen1_dec & 0xFFFC;
610 res->size = (config->gen1_dec >> 16) & 0xFC;
611 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
612 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
613 }
614
615 if ((config->gen2_dec & 0xFFFC) > 0x1000) {
616 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
617 res->base = config->gen2_dec & 0xFFFC;
618 res->size = (config->gen2_dec >> 16) & 0xFC;
619 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
620 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
621 }
622
623 if ((config->gen3_dec & 0xFFFC) > 0x1000) {
624 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
625 res->base = config->gen3_dec & 0xFFFC;
626 res->size = (config->gen3_dec >> 16) & 0xFC;
627 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
628 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
629 }
630
631 if ((config->gen4_dec & 0xFFFC) > 0x1000) {
632 res = new_resource(dev, IOINDEX_SUBTRACTIVE(io_index++, 0));
633 res->base = config->gen4_dec & 0xFFFC;
634 res->size = (config->gen4_dec >> 16) & 0xFC;
635 res->flags = IORESOURCE_IO| IORESOURCE_SUBTRACTIVE |
636 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
637 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200638}
639
640static void pch_lpc_enable_resources(device_t dev)
641{
642 pch_decode_init(dev);
643 return pci_dev_enable_resources(dev);
644}
645
646static void pch_lpc_enable(device_t dev)
647{
648 /* Enable PCH Display Port */
649 RCBA16(DISPBDF) = 0x0010;
650 RCBA32_OR(FD2, PCH_ENABLE_DBDF);
651
652 pch_enable(dev);
653}
654
655static void set_subsystem(device_t dev, unsigned vendor, unsigned device)
656{
657 if (!vendor || !device) {
658 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
659 pci_read_config32(dev, PCI_VENDOR_ID));
660 } else {
661 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
662 ((device & 0xffff) << 16) | (vendor & 0xffff));
663 }
664}
665
666static struct pci_operations pci_ops = {
667 .set_subsystem = set_subsystem,
668};
669
670static struct device_operations device_ops = {
671 .read_resources = pch_lpc_read_resources,
672 .set_resources = pci_dev_set_resources,
673 .enable_resources = pch_lpc_enable_resources,
674 .init = lpc_init,
675 .enable = pch_lpc_enable,
676 .scan_bus = scan_static_bus,
677 .ops_pci = &pci_ops,
678};
679
680
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600681/* IDs for LPC device of Intel 6 Series Chipset, Intel 7 Series Chipset, and
682 * Intel C200 Series Chipset
Stefan Reinauer8e073822012-04-04 00:07:22 +0200683 */
684
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700685static const unsigned short pci_device_ids[] = { 0x1c46, 0x1c47, 0x1c49, 0x1c4a,
686 0x1c4b, 0x1c4c, 0x1c4d, 0x1c4e,
687 0x1c4f, 0x1c50, 0x1c52, 0x1c54,
Kimarie Hoote6f459c2012-07-14 08:26:08 -0600688 0x1e55, 0x1c56, 0x1e57, 0x1c5c,
689 0x1e5d, 0x1e5e, 0x1e5f,
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700690 0 };
691
692static const struct pci_driver pch_lpc __pci_driver = {
693 .ops = &device_ops,
694 .vendor = PCI_VENDOR_ID_INTEL,
695 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200696};
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700697
698