1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * From coreboot southbridge/intel/bd82x6x/lpc.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2008-2009 coresystems GmbH
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun #include <fdtdec.h>
13*4882a593Smuzhiyun #include <rtc.h>
14*4882a593Smuzhiyun #include <pci.h>
15*4882a593Smuzhiyun #include <asm/intel_regs.h>
16*4882a593Smuzhiyun #include <asm/interrupt.h>
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <asm/ioapic.h>
19*4882a593Smuzhiyun #include <asm/lpc_common.h>
20*4882a593Smuzhiyun #include <asm/pci.h>
21*4882a593Smuzhiyun #include <asm/arch/pch.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define NMI_OFF 0
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define ENABLE_ACPI_MODE_IN_COREBOOT 0
28*4882a593Smuzhiyun #define TEST_SMM_FLASH_LOCKDOWN 0
29*4882a593Smuzhiyun
pch_enable_apic(struct udevice * pch)30*4882a593Smuzhiyun static int pch_enable_apic(struct udevice *pch)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun u32 reg32;
33*4882a593Smuzhiyun int i;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Enable ACPI I/O and power management. Set SCI IRQ to IRQ9 */
36*4882a593Smuzhiyun dm_pci_write_config8(pch, ACPI_CNTL, 0x80);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun writel(0, IO_APIC_INDEX);
39*4882a593Smuzhiyun writel(1 << 25, IO_APIC_DATA);
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* affirm full set of redirection table entries ("write once") */
42*4882a593Smuzhiyun writel(1, IO_APIC_INDEX);
43*4882a593Smuzhiyun reg32 = readl(IO_APIC_DATA);
44*4882a593Smuzhiyun writel(1, IO_APIC_INDEX);
45*4882a593Smuzhiyun writel(reg32, IO_APIC_DATA);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun writel(0, IO_APIC_INDEX);
48*4882a593Smuzhiyun reg32 = readl(IO_APIC_DATA);
49*4882a593Smuzhiyun debug("PCH APIC ID = %x\n", (reg32 >> 24) & 0x0f);
50*4882a593Smuzhiyun if (reg32 != (1 << 25)) {
51*4882a593Smuzhiyun printf("APIC Error - cannot write to registers\n");
52*4882a593Smuzhiyun return -EPERM;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun debug("Dumping IOAPIC registers\n");
56*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
57*4882a593Smuzhiyun writel(i, IO_APIC_INDEX);
58*4882a593Smuzhiyun debug(" reg 0x%04x:", i);
59*4882a593Smuzhiyun reg32 = readl(IO_APIC_DATA);
60*4882a593Smuzhiyun debug(" 0x%08x\n", reg32);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* Select Boot Configuration register. */
64*4882a593Smuzhiyun writel(3, IO_APIC_INDEX);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* Use Processor System Bus to deliver interrupts. */
67*4882a593Smuzhiyun writel(1, IO_APIC_DATA);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
pch_enable_serial_irqs(struct udevice * pch)72*4882a593Smuzhiyun static void pch_enable_serial_irqs(struct udevice *pch)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun u32 value;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* Set packet length and toggle silent mode bit for one frame. */
77*4882a593Smuzhiyun value = (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0);
78*4882a593Smuzhiyun #ifdef CONFIG_SERIRQ_CONTINUOUS_MODE
79*4882a593Smuzhiyun dm_pci_write_config8(pch, SERIRQ_CNTL, value);
80*4882a593Smuzhiyun #else
81*4882a593Smuzhiyun dm_pci_write_config8(pch, SERIRQ_CNTL, value | (1 << 6));
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
pch_pirq_init(struct udevice * pch)85*4882a593Smuzhiyun static int pch_pirq_init(struct udevice *pch)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun uint8_t route[8], *ptr;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (fdtdec_get_byte_array(gd->fdt_blob, dev_of_offset(pch),
90*4882a593Smuzhiyun "intel,pirq-routing", route, sizeof(route)))
91*4882a593Smuzhiyun return -EINVAL;
92*4882a593Smuzhiyun ptr = route;
93*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQA_ROUT, *ptr++);
94*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQB_ROUT, *ptr++);
95*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQC_ROUT, *ptr++);
96*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQD_ROUT, *ptr++);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQE_ROUT, *ptr++);
99*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQF_ROUT, *ptr++);
100*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQG_ROUT, *ptr++);
101*4882a593Smuzhiyun dm_pci_write_config8(pch, PIRQH_ROUT, *ptr++);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun * TODO(sjg@chromium.org): U-Boot does not set up the interrupts
105*4882a593Smuzhiyun * here. It's unclear if it is needed
106*4882a593Smuzhiyun */
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
pch_gpi_routing(struct udevice * pch)110*4882a593Smuzhiyun static int pch_gpi_routing(struct udevice *pch)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun u8 route[16];
113*4882a593Smuzhiyun u32 reg;
114*4882a593Smuzhiyun int gpi;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (fdtdec_get_byte_array(gd->fdt_blob, dev_of_offset(pch),
117*4882a593Smuzhiyun "intel,gpi-routing", route, sizeof(route)))
118*4882a593Smuzhiyun return -EINVAL;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun for (reg = 0, gpi = 0; gpi < ARRAY_SIZE(route); gpi++)
121*4882a593Smuzhiyun reg |= route[gpi] << (gpi * 2);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun dm_pci_write_config32(pch, 0xb8, reg);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
pch_power_options(struct udevice * pch)128*4882a593Smuzhiyun static int pch_power_options(struct udevice *pch)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
131*4882a593Smuzhiyun int node = dev_of_offset(pch);
132*4882a593Smuzhiyun u8 reg8;
133*4882a593Smuzhiyun u16 reg16, pmbase;
134*4882a593Smuzhiyun u32 reg32;
135*4882a593Smuzhiyun const char *state;
136*4882a593Smuzhiyun int pwr_on;
137*4882a593Smuzhiyun int nmi_option;
138*4882a593Smuzhiyun int ret;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * Which state do we want to goto after g3 (power restored)?
142*4882a593Smuzhiyun * 0 == S0 Full On
143*4882a593Smuzhiyun * 1 == S5 Soft Off
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * If the option is not existent (Laptops), use Kconfig setting.
146*4882a593Smuzhiyun * TODO(sjg@chromium.org): Make this configurable
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun pwr_on = MAINBOARD_POWER_ON;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun dm_pci_read_config16(pch, GEN_PMCON_3, ®16);
151*4882a593Smuzhiyun reg16 &= 0xfffe;
152*4882a593Smuzhiyun switch (pwr_on) {
153*4882a593Smuzhiyun case MAINBOARD_POWER_OFF:
154*4882a593Smuzhiyun reg16 |= 1;
155*4882a593Smuzhiyun state = "off";
156*4882a593Smuzhiyun break;
157*4882a593Smuzhiyun case MAINBOARD_POWER_ON:
158*4882a593Smuzhiyun reg16 &= ~1;
159*4882a593Smuzhiyun state = "on";
160*4882a593Smuzhiyun break;
161*4882a593Smuzhiyun case MAINBOARD_POWER_KEEP:
162*4882a593Smuzhiyun reg16 &= ~1;
163*4882a593Smuzhiyun state = "state keep";
164*4882a593Smuzhiyun break;
165*4882a593Smuzhiyun default:
166*4882a593Smuzhiyun state = "undefined";
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */
170*4882a593Smuzhiyun reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun reg16 &= ~(1 << 10);
173*4882a593Smuzhiyun reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun dm_pci_write_config16(pch, GEN_PMCON_3, reg16);
178*4882a593Smuzhiyun debug("Set power %s after power failure.\n", state);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Set up NMI on errors. */
181*4882a593Smuzhiyun reg8 = inb(0x61);
182*4882a593Smuzhiyun reg8 &= 0x0f; /* Higher Nibble must be 0 */
183*4882a593Smuzhiyun reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */
184*4882a593Smuzhiyun reg8 |= (1 << 2); /* PCI SERR# Disable for now */
185*4882a593Smuzhiyun outb(reg8, 0x61);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun reg8 = inb(0x70);
188*4882a593Smuzhiyun /* TODO(sjg@chromium.org): Make this configurable */
189*4882a593Smuzhiyun nmi_option = NMI_OFF;
190*4882a593Smuzhiyun if (nmi_option) {
191*4882a593Smuzhiyun debug("NMI sources enabled.\n");
192*4882a593Smuzhiyun reg8 &= ~(1 << 7); /* Set NMI. */
193*4882a593Smuzhiyun } else {
194*4882a593Smuzhiyun debug("NMI sources disabled.\n");
195*4882a593Smuzhiyun /* Can't mask NMI from PCI-E and NMI_NOW */
196*4882a593Smuzhiyun reg8 |= (1 << 7);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun outb(reg8, 0x70);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */
201*4882a593Smuzhiyun dm_pci_read_config16(pch, GEN_PMCON_1, ®16);
202*4882a593Smuzhiyun reg16 &= ~(3 << 0); /* SMI# rate 1 minute */
203*4882a593Smuzhiyun reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */
204*4882a593Smuzhiyun #if DEBUG_PERIODIC_SMIS
205*4882a593Smuzhiyun /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */
206*4882a593Smuzhiyun reg16 |= (3 << 0); /* Periodic SMI every 8s */
207*4882a593Smuzhiyun #endif
208*4882a593Smuzhiyun dm_pci_write_config16(pch, GEN_PMCON_1, reg16);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* Set the board's GPI routing. */
211*4882a593Smuzhiyun ret = pch_gpi_routing(pch);
212*4882a593Smuzhiyun if (ret)
213*4882a593Smuzhiyun return ret;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun dm_pci_read_config16(pch, 0x40, &pmbase);
216*4882a593Smuzhiyun pmbase &= 0xfffe;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun writel(fdtdec_get_int(blob, node, "intel,gpe0-enable", 0),
219*4882a593Smuzhiyun (ulong)pmbase + GPE0_EN);
220*4882a593Smuzhiyun writew(fdtdec_get_int(blob, node, "intel,alt-gp-smi-enable", 0),
221*4882a593Smuzhiyun (ulong)pmbase + ALT_GP_SMI_EN);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Set up power management block and determine sleep mode */
224*4882a593Smuzhiyun reg32 = inl(pmbase + 0x04); /* PM1_CNT */
225*4882a593Smuzhiyun reg32 &= ~(7 << 10); /* SLP_TYP */
226*4882a593Smuzhiyun reg32 |= (1 << 0); /* SCI_EN */
227*4882a593Smuzhiyun outl(reg32, pmbase + 0x04);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* Clear magic status bits to prevent unexpected wake */
230*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3310), (1 << 4) | (1 << 5) | (1 << 0));
231*4882a593Smuzhiyun clrbits_le32(RCB_REG(0x3f02), 0xf);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun return 0;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
pch_rtc_init(struct udevice * pch)236*4882a593Smuzhiyun static void pch_rtc_init(struct udevice *pch)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun int rtc_failed;
239*4882a593Smuzhiyun u8 reg8;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun dm_pci_read_config8(pch, GEN_PMCON_3, ®8);
242*4882a593Smuzhiyun rtc_failed = reg8 & RTC_BATTERY_DEAD;
243*4882a593Smuzhiyun if (rtc_failed) {
244*4882a593Smuzhiyun reg8 &= ~RTC_BATTERY_DEAD;
245*4882a593Smuzhiyun dm_pci_write_config8(pch, GEN_PMCON_3, reg8);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun debug("rtc_failed = 0x%x\n", rtc_failed);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* TODO: Handle power failure */
250*4882a593Smuzhiyun if (rtc_failed)
251*4882a593Smuzhiyun printf("RTC power failed\n");
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* CougarPoint PCH Power Management init */
cpt_pm_init(struct udevice * pch)255*4882a593Smuzhiyun static void cpt_pm_init(struct udevice *pch)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun debug("CougarPoint PM init\n");
258*4882a593Smuzhiyun dm_pci_write_config8(pch, 0xa9, 0x47);
259*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2238), (1 << 6) | (1 << 0));
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun setbits_le32(RCB_REG(0x228c), 1 << 0);
262*4882a593Smuzhiyun setbits_le32(RCB_REG(0x1100), (1 << 13) | (1 << 14));
263*4882a593Smuzhiyun setbits_le32(RCB_REG(0x0900), 1 << 14);
264*4882a593Smuzhiyun writel(0xc0388400, RCB_REG(0x2304));
265*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18));
266*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1));
267*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x3314), ~0x1f, 0xf);
268*4882a593Smuzhiyun writel(0x050f0000, RCB_REG(0x3318));
269*4882a593Smuzhiyun writel(0x04000000, RCB_REG(0x3324));
270*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3340), 0xfffff);
271*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3344), 1 << 1);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun writel(0x0001c000, RCB_REG(0x3360));
274*4882a593Smuzhiyun writel(0x00061100, RCB_REG(0x3368));
275*4882a593Smuzhiyun writel(0x7f8fdfff, RCB_REG(0x3378));
276*4882a593Smuzhiyun writel(0x000003fc, RCB_REG(0x337c));
277*4882a593Smuzhiyun writel(0x00001000, RCB_REG(0x3388));
278*4882a593Smuzhiyun writel(0x0001c000, RCB_REG(0x3390));
279*4882a593Smuzhiyun writel(0x00000800, RCB_REG(0x33a0));
280*4882a593Smuzhiyun writel(0x00001000, RCB_REG(0x33b0));
281*4882a593Smuzhiyun writel(0x00093900, RCB_REG(0x33c0));
282*4882a593Smuzhiyun writel(0x24653002, RCB_REG(0x33cc));
283*4882a593Smuzhiyun writel(0x062108fe, RCB_REG(0x33d0));
284*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060);
285*4882a593Smuzhiyun writel(0x01010000, RCB_REG(0x3a28));
286*4882a593Smuzhiyun writel(0x01010404, RCB_REG(0x3a2c));
287*4882a593Smuzhiyun writel(0x01041041, RCB_REG(0x3a80));
288*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001);
289*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3a84), 1 << 24); /* SATA 2/3 disabled */
290*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3a88), 1 << 0); /* SATA 4/5 disabled */
291*4882a593Smuzhiyun writel(0x00000001, RCB_REG(0x3a6c));
292*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x2344), ~0x00ffff00, 0xff00000c);
293*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20);
294*4882a593Smuzhiyun writel(0, RCB_REG(0x33c8));
295*4882a593Smuzhiyun setbits_le32(RCB_REG(0x21b0), 0xf);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /* PantherPoint PCH Power Management init */
ppt_pm_init(struct udevice * pch)299*4882a593Smuzhiyun static void ppt_pm_init(struct udevice *pch)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun debug("PantherPoint PM init\n");
302*4882a593Smuzhiyun dm_pci_write_config8(pch, 0xa9, 0x47);
303*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2238), 1 << 0);
304*4882a593Smuzhiyun setbits_le32(RCB_REG(0x228c), 1 << 0);
305*4882a593Smuzhiyun setbits_le16(RCB_REG(0x1100), (1 << 13) | (1 << 14));
306*4882a593Smuzhiyun setbits_le16(RCB_REG(0x0900), 1 << 14);
307*4882a593Smuzhiyun writel(0xc03b8400, RCB_REG(0x2304));
308*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2314), (1 << 5) | (1 << 18));
309*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2320), (1 << 15) | (1 << 1));
310*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x3314), 0x1f, 0xf);
311*4882a593Smuzhiyun writel(0x054f0000, RCB_REG(0x3318));
312*4882a593Smuzhiyun writel(0x04000000, RCB_REG(0x3324));
313*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3340), 0xfffff);
314*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3344), (1 << 1) | (1 << 0));
315*4882a593Smuzhiyun writel(0x0001c000, RCB_REG(0x3360));
316*4882a593Smuzhiyun writel(0x00061100, RCB_REG(0x3368));
317*4882a593Smuzhiyun writel(0x7f8fdfff, RCB_REG(0x3378));
318*4882a593Smuzhiyun writel(0x000003fd, RCB_REG(0x337c));
319*4882a593Smuzhiyun writel(0x00001000, RCB_REG(0x3388));
320*4882a593Smuzhiyun writel(0x0001c000, RCB_REG(0x3390));
321*4882a593Smuzhiyun writel(0x00000800, RCB_REG(0x33a0));
322*4882a593Smuzhiyun writel(0x00001000, RCB_REG(0x33b0));
323*4882a593Smuzhiyun writel(0x00093900, RCB_REG(0x33c0));
324*4882a593Smuzhiyun writel(0x24653002, RCB_REG(0x33cc));
325*4882a593Smuzhiyun writel(0x067388fe, RCB_REG(0x33d0));
326*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x33d4), 0x0fff0fff, 0x00670060);
327*4882a593Smuzhiyun writel(0x01010000, RCB_REG(0x3a28));
328*4882a593Smuzhiyun writel(0x01010404, RCB_REG(0x3a2c));
329*4882a593Smuzhiyun writel(0x01040000, RCB_REG(0x3a80));
330*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x3a84), 0x0000ffff, 0x00001001);
331*4882a593Smuzhiyun /* SATA 2/3 disabled */
332*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3a84), 1 << 24);
333*4882a593Smuzhiyun /* SATA 4/5 disabled */
334*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3a88), 1 << 0);
335*4882a593Smuzhiyun writel(0x00000001, RCB_REG(0x3a6c));
336*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x2344), 0xff0000ff, 0xff00000c);
337*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(0x80c), 0xff << 20, 0x11 << 20);
338*4882a593Smuzhiyun setbits_le32(RCB_REG(0x33a4), (1 << 0));
339*4882a593Smuzhiyun writel(0, RCB_REG(0x33c8));
340*4882a593Smuzhiyun setbits_le32(RCB_REG(0x21b0), 0xf);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
enable_hpet(void)343*4882a593Smuzhiyun static void enable_hpet(void)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun /* Move HPET to default address 0xfed00000 and enable it */
346*4882a593Smuzhiyun clrsetbits_le32(RCB_REG(HPTC), 3 << 0, 1 << 7);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
enable_clock_gating(struct udevice * pch)349*4882a593Smuzhiyun static void enable_clock_gating(struct udevice *pch)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun u32 reg32;
352*4882a593Smuzhiyun u16 reg16;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun setbits_le32(RCB_REG(0x2234), 0xf);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun dm_pci_read_config16(pch, GEN_PMCON_1, ®16);
357*4882a593Smuzhiyun reg16 |= (1 << 2) | (1 << 11);
358*4882a593Smuzhiyun dm_pci_write_config16(pch, GEN_PMCON_1, reg16);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun pch_iobp_update(pch, 0xeb007f07, ~0U, 1 << 31);
361*4882a593Smuzhiyun pch_iobp_update(pch, 0xeb004000, ~0U, 1 << 7);
362*4882a593Smuzhiyun pch_iobp_update(pch, 0xec007f07, ~0U, 1 << 31);
363*4882a593Smuzhiyun pch_iobp_update(pch, 0xec004000, ~0U, 1 << 7);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun reg32 = readl(RCB_REG(CG));
366*4882a593Smuzhiyun reg32 |= (1 << 31);
367*4882a593Smuzhiyun reg32 |= (1 << 29) | (1 << 28);
368*4882a593Smuzhiyun reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24);
369*4882a593Smuzhiyun reg32 |= (1 << 16);
370*4882a593Smuzhiyun reg32 |= (1 << 17);
371*4882a593Smuzhiyun reg32 |= (1 << 18);
372*4882a593Smuzhiyun reg32 |= (1 << 22);
373*4882a593Smuzhiyun reg32 |= (1 << 23);
374*4882a593Smuzhiyun reg32 &= ~(1 << 20);
375*4882a593Smuzhiyun reg32 |= (1 << 19);
376*4882a593Smuzhiyun reg32 |= (1 << 0);
377*4882a593Smuzhiyun reg32 |= (0xf << 1);
378*4882a593Smuzhiyun writel(reg32, RCB_REG(CG));
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun setbits_le32(RCB_REG(0x38c0), 0x7);
381*4882a593Smuzhiyun setbits_le32(RCB_REG(0x36d4), 0x6680c004);
382*4882a593Smuzhiyun setbits_le32(RCB_REG(0x3564), 0x3);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
pch_disable_smm_only_flashing(struct udevice * pch)385*4882a593Smuzhiyun static void pch_disable_smm_only_flashing(struct udevice *pch)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun u8 reg8;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun debug("Enabling BIOS updates outside of SMM... ");
390*4882a593Smuzhiyun dm_pci_read_config8(pch, 0xdc, ®8); /* BIOS_CNTL */
391*4882a593Smuzhiyun reg8 &= ~(1 << 5);
392*4882a593Smuzhiyun dm_pci_write_config8(pch, 0xdc, reg8);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
pch_fixups(struct udevice * pch)395*4882a593Smuzhiyun static void pch_fixups(struct udevice *pch)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun u8 gen_pmcon_2;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun /* Indicate DRAM init done for MRC S3 to know it can resume */
400*4882a593Smuzhiyun dm_pci_read_config8(pch, GEN_PMCON_2, &gen_pmcon_2);
401*4882a593Smuzhiyun gen_pmcon_2 |= (1 << 7);
402*4882a593Smuzhiyun dm_pci_write_config8(pch, GEN_PMCON_2, gen_pmcon_2);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun /* Enable DMI ASPM in the PCH */
405*4882a593Smuzhiyun clrbits_le32(RCB_REG(0x2304), 1 << 10);
406*4882a593Smuzhiyun setbits_le32(RCB_REG(0x21a4), (1 << 11) | (1 << 10));
407*4882a593Smuzhiyun setbits_le32(RCB_REG(0x21a8), 0x3);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
set_spi_speed(void)410*4882a593Smuzhiyun static void set_spi_speed(void)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun u32 fdod;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /* Observe SPI Descriptor Component Section 0 */
415*4882a593Smuzhiyun writel(0x1000, RCB_REG(SPI_DESC_COMP0));
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* Extract the1 Write/Erase SPI Frequency from descriptor */
418*4882a593Smuzhiyun fdod = readl(RCB_REG(SPI_FREQ_WR_ERA));
419*4882a593Smuzhiyun fdod >>= 24;
420*4882a593Smuzhiyun fdod &= 7;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* Set Software Sequence frequency to match */
423*4882a593Smuzhiyun clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
lpc_init_extra(struct udevice * dev)426*4882a593Smuzhiyun static int lpc_init_extra(struct udevice *dev)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun struct udevice *pch = dev->parent;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun debug("pch: lpc_init\n");
431*4882a593Smuzhiyun dm_pci_write_bar32(pch, 0, 0);
432*4882a593Smuzhiyun dm_pci_write_bar32(pch, 1, 0xff800000);
433*4882a593Smuzhiyun dm_pci_write_bar32(pch, 2, 0xfec00000);
434*4882a593Smuzhiyun dm_pci_write_bar32(pch, 3, 0x800);
435*4882a593Smuzhiyun dm_pci_write_bar32(pch, 4, 0x900);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Set the value for PCI command register. */
438*4882a593Smuzhiyun dm_pci_write_config16(pch, PCI_COMMAND, 0x000f);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun /* IO APIC initialization. */
441*4882a593Smuzhiyun pch_enable_apic(pch);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun pch_enable_serial_irqs(pch);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /* Setup the PIRQ. */
446*4882a593Smuzhiyun pch_pirq_init(pch);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* Setup power options. */
449*4882a593Smuzhiyun pch_power_options(pch);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* Initialize power management */
452*4882a593Smuzhiyun switch (pch_silicon_type(pch)) {
453*4882a593Smuzhiyun case PCH_TYPE_CPT: /* CougarPoint */
454*4882a593Smuzhiyun cpt_pm_init(pch);
455*4882a593Smuzhiyun break;
456*4882a593Smuzhiyun case PCH_TYPE_PPT: /* PantherPoint */
457*4882a593Smuzhiyun ppt_pm_init(pch);
458*4882a593Smuzhiyun break;
459*4882a593Smuzhiyun default:
460*4882a593Smuzhiyun printf("Unknown Chipset: %s\n", pch->name);
461*4882a593Smuzhiyun return -ENOSYS;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun /* Initialize the real time clock. */
465*4882a593Smuzhiyun pch_rtc_init(pch);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* Initialize the High Precision Event Timers, if present. */
468*4882a593Smuzhiyun enable_hpet();
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun /* Initialize Clock Gating */
471*4882a593Smuzhiyun enable_clock_gating(pch);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun pch_disable_smm_only_flashing(pch);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun pch_fixups(pch);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
bd82x6x_lpc_early_init(struct udevice * dev)480*4882a593Smuzhiyun static int bd82x6x_lpc_early_init(struct udevice *dev)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun set_spi_speed();
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun /* Setting up Southbridge. In the northbridge code. */
485*4882a593Smuzhiyun debug("Setting up static southbridge registers\n");
486*4882a593Smuzhiyun dm_pci_write_config32(dev->parent, PCH_RCBA_BASE,
487*4882a593Smuzhiyun RCB_BASE_ADDRESS | 1);
488*4882a593Smuzhiyun dm_pci_write_config32(dev->parent, PMBASE, DEFAULT_PMBASE | 1);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /* Enable ACPI BAR */
491*4882a593Smuzhiyun dm_pci_write_config8(dev->parent, ACPI_CNTL, 0x80);
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun debug("Disabling watchdog reboot\n");
494*4882a593Smuzhiyun setbits_le32(RCB_REG(GCS), 1 >> 5); /* No reset */
495*4882a593Smuzhiyun outw(1 << 11, DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun dm_pci_write_config32(dev->parent, GPIO_BASE, DEFAULT_GPIOBASE | 1);
498*4882a593Smuzhiyun dm_pci_write_config32(dev->parent, GPIO_CNTL, 0x10);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun return 0;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
bd82x6x_lpc_probe(struct udevice * dev)503*4882a593Smuzhiyun static int bd82x6x_lpc_probe(struct udevice *dev)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun int ret;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun if (!(gd->flags & GD_FLG_RELOC)) {
508*4882a593Smuzhiyun ret = lpc_common_early_init(dev);
509*4882a593Smuzhiyun if (ret) {
510*4882a593Smuzhiyun debug("%s: lpc_early_init() failed\n", __func__);
511*4882a593Smuzhiyun return ret;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun return bd82x6x_lpc_early_init(dev);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun return lpc_init_extra(dev);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun static const struct udevice_id bd82x6x_lpc_ids[] = {
521*4882a593Smuzhiyun { .compatible = "intel,bd82x6x-lpc" },
522*4882a593Smuzhiyun { }
523*4882a593Smuzhiyun };
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun U_BOOT_DRIVER(bd82x6x_lpc_drv) = {
526*4882a593Smuzhiyun .name = "lpc",
527*4882a593Smuzhiyun .id = UCLASS_LPC,
528*4882a593Smuzhiyun .of_match = bd82x6x_lpc_ids,
529*4882a593Smuzhiyun .probe = bd82x6x_lpc_probe,
530*4882a593Smuzhiyun };
531