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