xref: /OK3568_Linux_fs/u-boot/arch/x86/cpu/ivybridge/lpc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &reg16);
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, &reg16);
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, &reg8);
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, &reg16);
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, &reg8);	/* 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