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