]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1e6f4e58 SG |
2 | /* |
3 | * Copyright (c) 2016 Google, Inc | |
1e6f4e58 SG |
4 | */ |
5 | ||
6 | #include <common.h> | |
7 | #include <dm.h> | |
f7ae49fc | 8 | #include <log.h> |
1e6f4e58 SG |
9 | #include <pch.h> |
10 | #include <asm/cpu.h> | |
401d1c4f | 11 | #include <asm/global_data.h> |
1e6f4e58 SG |
12 | #include <asm/gpio.h> |
13 | #include <asm/i8259.h> | |
14 | #include <asm/intel_regs.h> | |
15 | #include <asm/io.h> | |
16 | #include <asm/ioapic.h> | |
17 | #include <asm/lpc_common.h> | |
18 | #include <asm/pch_common.h> | |
19 | #include <asm/arch/cpu.h> | |
20 | #include <asm/arch/gpio.h> | |
21 | #include <asm/arch/iomap.h> | |
22 | #include <asm/arch/pch.h> | |
23 | #include <asm/arch/pm.h> | |
24 | #include <asm/arch/rcb.h> | |
3f3411eb | 25 | #include <asm/arch/serialio.h> |
1e6f4e58 | 26 | #include <asm/arch/spi.h> |
3f3411eb | 27 | #include <dm/uclass-internal.h> |
c05ed00a | 28 | #include <linux/delay.h> |
1e6f4e58 SG |
29 | |
30 | #define BIOS_CTRL 0xdc | |
31 | ||
32 | bool cpu_is_ult(void) | |
33 | { | |
34 | u32 fm = cpu_get_family_model(); | |
35 | ||
36 | return fm == BROADWELL_FAMILY_ULT || fm == HASWELL_FAMILY_ULT; | |
37 | } | |
38 | ||
39 | static int broadwell_pch_early_init(struct udevice *dev) | |
40 | { | |
41 | struct gpio_desc desc; | |
42 | struct udevice *bus; | |
43 | pci_dev_t bdf; | |
44 | int ret; | |
45 | ||
46 | dm_pci_write_config32(dev, PCH_RCBA, RCB_BASE_ADDRESS | 1); | |
47 | ||
48 | dm_pci_write_config32(dev, PMBASE, ACPI_BASE_ADDRESS | 1); | |
49 | dm_pci_write_config8(dev, ACPI_CNTL, ACPI_EN); | |
50 | dm_pci_write_config32(dev, GPIO_BASE, GPIO_BASE_ADDRESS | 1); | |
51 | dm_pci_write_config8(dev, GPIO_CNTL, GPIO_EN); | |
52 | ||
53 | /* Enable IOAPIC */ | |
54 | writew(0x1000, RCB_REG(OIC)); | |
55 | /* Read back for posted write */ | |
56 | readw(RCB_REG(OIC)); | |
57 | ||
58 | /* Set HPET address and enable it */ | |
59 | clrsetbits_le32(RCB_REG(HPTC), 3, 1 << 7); | |
60 | /* Read back for posted write */ | |
61 | readl(RCB_REG(HPTC)); | |
62 | /* Enable HPET to start counter */ | |
63 | setbits_le32(HPET_BASE_ADDRESS + 0x10, 1 << 0); | |
64 | ||
65 | setbits_le32(RCB_REG(GCS), 1 << 5); | |
66 | ||
67 | /* | |
68 | * Enable PP3300_AUTOBAHN_EN after initial GPIO setup | |
69 | * to prevent possible brownout. This will cause the GPIOs to be set | |
70 | * up if it has not been done already. | |
71 | */ | |
72 | ret = gpio_request_by_name(dev, "power-enable-gpio", 0, &desc, | |
73 | GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); | |
74 | if (ret) | |
75 | return ret; | |
76 | ||
77 | /* 8.14 Additional PCI Express Programming Steps, step #1 */ | |
78 | bdf = PCI_BDF(0, 0x1c, 0); | |
79 | bus = pci_get_controller(dev); | |
80 | pci_bus_clrset_config32(bus, bdf, 0xf4, 0x60, 0); | |
81 | pci_bus_clrset_config32(bus, bdf, 0xf4, 0x80, 0x80); | |
82 | pci_bus_clrset_config32(bus, bdf, 0xe2, 0x30, 0x30); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static void pch_misc_init(struct udevice *dev) | |
88 | { | |
89 | /* Setup SLP signal assertion, SLP_S4=4s, SLP_S3=50ms */ | |
90 | dm_pci_clrset_config8(dev, GEN_PMCON_3, 3 << 4 | 1 << 10, | |
91 | 1 << 3 | 1 << 11 | 1 << 12); | |
92 | /* Prepare sleep mode */ | |
93 | clrsetio_32(ACPI_BASE_ADDRESS + PM1_CNT, SLP_TYP, SCI_EN); | |
94 | ||
95 | /* Setup NMI on errors, disable SERR */ | |
96 | clrsetio_8(0x61, 0xf0, 1 << 2); | |
97 | /* Disable NMI sources */ | |
98 | setio_8(0x70, 1 << 7); | |
99 | /* Indicate DRAM init done for MRC */ | |
100 | dm_pci_clrset_config8(dev, GEN_PMCON_2, 0, 1 << 7); | |
101 | ||
102 | /* Clear status bits to prevent unexpected wake */ | |
103 | setbits_le32(RCB_REG(0x3310), 0x0000002f); | |
104 | clrsetbits_le32(RCB_REG(0x3f02), 0x0000000f, 0); | |
105 | /* Enable PCIe Relaxed Order */ | |
106 | setbits_le32(RCB_REG(0x2314), 1 << 31 | 1 << 7); | |
107 | setbits_le32(RCB_REG(0x1114), 1 << 15 | 1 << 14); | |
108 | /* Setup SERIRQ, enable continuous mode */ | |
109 | dm_pci_clrset_config8(dev, SERIRQ_CNTL, 0, 1 << 7 | 1 << 6); | |
110 | }; | |
111 | ||
112 | static void pch_enable_ioapic(void) | |
113 | { | |
114 | u32 reg32; | |
115 | ||
b813ea9a BM |
116 | /* Make sure this is a unique ID within system */ |
117 | io_apic_set_id(0x04); | |
1e6f4e58 SG |
118 | |
119 | /* affirm full set of redirection table entries ("write once") */ | |
120 | reg32 = io_apic_read(0x01); | |
121 | ||
122 | /* PCH-LP has 39 redirection entries */ | |
123 | reg32 &= ~0x00ff0000; | |
124 | reg32 |= 0x00270000; | |
125 | ||
126 | io_apic_write(0x01, reg32); | |
127 | ||
128 | /* | |
129 | * Select Boot Configuration register (0x03) and | |
130 | * use Processor System Bus (0x01) to deliver interrupts. | |
131 | */ | |
132 | io_apic_write(0x03, 0x01); | |
133 | } | |
134 | ||
135 | /* Enable all requested GPE */ | |
136 | void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4) | |
137 | { | |
138 | outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0)); | |
139 | outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32)); | |
140 | outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_94_64)); | |
141 | outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); | |
142 | } | |
143 | ||
144 | /* | |
145 | * Enable GPIO SMI events - it would be good to put this in the GPIO driver | |
146 | * but it would need a new driver operation. | |
147 | */ | |
148 | int enable_alt_smi(struct udevice *pch, u32 mask) | |
149 | { | |
150 | struct pch_lp_gpio_regs *regs; | |
151 | u32 gpiobase; | |
152 | int ret; | |
153 | ||
154 | ret = pch_get_gpio_base(pch, &gpiobase); | |
155 | if (ret) { | |
156 | debug("%s: invalid GPIOBASE address (%08x)\n", __func__, | |
157 | gpiobase); | |
158 | return -EINVAL; | |
159 | } | |
160 | ||
161 | regs = (struct pch_lp_gpio_regs *)gpiobase; | |
162 | setio_32(regs->alt_gpi_smi_en, mask); | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | static int pch_power_options(struct udevice *dev) | |
168 | { | |
169 | int pwr_on_after_power_fail = MAINBOARD_POWER_OFF; | |
170 | const char *state; | |
171 | u32 enable[4]; | |
172 | u16 reg16; | |
173 | int ret; | |
174 | ||
175 | dm_pci_read_config16(dev, GEN_PMCON_3, ®16); | |
176 | reg16 &= 0xfffe; | |
177 | switch (pwr_on_after_power_fail) { | |
178 | case MAINBOARD_POWER_OFF: | |
179 | reg16 |= 1; | |
180 | state = "off"; | |
181 | break; | |
182 | case MAINBOARD_POWER_ON: | |
183 | reg16 &= ~1; | |
184 | state = "on"; | |
185 | break; | |
186 | case MAINBOARD_POWER_KEEP: | |
187 | reg16 &= ~1; | |
188 | state = "state keep"; | |
189 | break; | |
190 | default: | |
191 | state = "undefined"; | |
192 | } | |
193 | dm_pci_write_config16(dev, GEN_PMCON_3, reg16); | |
194 | debug("Set power %s after power failure.\n", state); | |
195 | ||
196 | /* GPE setup based on device tree configuration */ | |
e160f7d4 | 197 | ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), |
1e6f4e58 SG |
198 | "intel,gpe0-en", enable, ARRAY_SIZE(enable)); |
199 | if (ret) | |
200 | return -EINVAL; | |
201 | enable_all_gpe(enable[0], enable[1], enable[2], enable[3]); | |
202 | ||
203 | /* SMI setup based on device tree configuration */ | |
e160f7d4 | 204 | enable_alt_smi(dev, fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), |
1e6f4e58 SG |
205 | "intel,alt-gp-smi-enable", 0)); |
206 | ||
207 | return 0; | |
208 | } | |
209 | ||
210 | /* Magic register settings for power management */ | |
211 | static void pch_pm_init_magic(struct udevice *dev) | |
212 | { | |
213 | dm_pci_write_config8(dev, 0xa9, 0x46); | |
214 | clrbits_le32(RCB_REG(0x232c), 1), | |
215 | setbits_le32(RCB_REG(0x1100), 0x0000c13f); | |
216 | clrsetbits_le32(RCB_REG(0x2320), 0x60, 0x10); | |
217 | writel(0x00012fff, RCB_REG(0x3314)); | |
218 | clrsetbits_le32(RCB_REG(0x3318), 0x000f0330, 0x0dcf0400); | |
219 | writel(0x04000000, RCB_REG(0x3324)); | |
220 | writel(0x00041400, RCB_REG(0x3368)); | |
221 | writel(0x3f8ddbff, RCB_REG(0x3388)); | |
222 | writel(0x00007001, RCB_REG(0x33ac)); | |
223 | writel(0x00181900, RCB_REG(0x33b0)); | |
224 | writel(0x00060A00, RCB_REG(0x33c0)); | |
225 | writel(0x06200840, RCB_REG(0x33d0)); | |
226 | writel(0x01010101, RCB_REG(0x3a28)); | |
227 | writel(0x040c0404, RCB_REG(0x3a2c)); | |
228 | writel(0x9000000a, RCB_REG(0x3a9c)); | |
229 | writel(0x03808033, RCB_REG(0x2b1c)); | |
230 | writel(0x80000009, RCB_REG(0x2b34)); | |
231 | writel(0x022ddfff, RCB_REG(0x3348)); | |
232 | writel(0x00000001, RCB_REG(0x334c)); | |
233 | writel(0x0001c000, RCB_REG(0x3358)); | |
234 | writel(0x3f8ddbff, RCB_REG(0x3380)); | |
235 | writel(0x0001c7e1, RCB_REG(0x3384)); | |
236 | writel(0x0001c7e1, RCB_REG(0x338c)); | |
237 | writel(0x0001c000, RCB_REG(0x3398)); | |
238 | writel(0x00181900, RCB_REG(0x33a8)); | |
239 | writel(0x00080000, RCB_REG(0x33dc)); | |
240 | writel(0x00000001, RCB_REG(0x33e0)); | |
241 | writel(0x0000040c, RCB_REG(0x3a20)); | |
242 | writel(0x01010101, RCB_REG(0x3a24)); | |
243 | writel(0x01010101, RCB_REG(0x3a30)); | |
244 | dm_pci_clrset_config32(dev, 0xac, 0x00200000, 0); | |
245 | setbits_le32(RCB_REG(0x0410), 0x00000003); | |
246 | setbits_le32(RCB_REG(0x2618), 0x08000000); | |
247 | setbits_le32(RCB_REG(0x2300), 0x00000002); | |
248 | setbits_le32(RCB_REG(0x2600), 0x00000008); | |
249 | writel(0x00007001, RCB_REG(0x33b4)); | |
250 | writel(0x022ddfff, RCB_REG(0x3350)); | |
251 | writel(0x00000001, RCB_REG(0x3354)); | |
252 | /* Power Optimizer */ | |
253 | setbits_le32(RCB_REG(0x33d4), 0x08000000); | |
254 | /* | |
255 | * This stops the LCD from turning on: | |
256 | * setbits_le32(RCB_REG(0x33c8), 0x08000080); | |
257 | */ | |
258 | writel(0x0000883c, RCB_REG(0x2b10)); | |
259 | writel(0x1e0a4616, RCB_REG(0x2b14)); | |
260 | writel(0x40000005, RCB_REG(0x2b24)); | |
261 | writel(0x0005db01, RCB_REG(0x2b20)); | |
262 | writel(0x05145005, RCB_REG(0x3a80)); | |
263 | writel(0x00001005, RCB_REG(0x3a84)); | |
264 | setbits_le32(RCB_REG(0x33d4), 0x2fff2fb1); | |
265 | setbits_le32(RCB_REG(0x33c8), 0x00008000); | |
266 | }; | |
267 | ||
268 | static int pch_type(struct udevice *dev) | |
269 | { | |
270 | u16 type; | |
271 | ||
272 | dm_pci_read_config16(dev, PCI_DEVICE_ID, &type); | |
273 | ||
274 | return type; | |
275 | } | |
276 | ||
277 | /* Return 1 if PCH type is WildcatPoint */ | |
278 | static int pch_is_wpt(struct udevice *dev) | |
279 | { | |
280 | return ((pch_type(dev) & 0xfff0) == 0x9cc0) ? 1 : 0; | |
281 | } | |
282 | ||
283 | /* Return 1 if PCH type is WildcatPoint ULX */ | |
284 | static int pch_is_wpt_ulx(struct udevice *dev) | |
285 | { | |
286 | u16 lpcid = pch_type(dev); | |
287 | ||
288 | switch (lpcid) { | |
289 | case PCH_WPT_BDW_Y_SAMPLE: | |
290 | case PCH_WPT_BDW_Y_PREMIUM: | |
291 | case PCH_WPT_BDW_Y_BASE: | |
292 | return 1; | |
293 | } | |
294 | ||
295 | return 0; | |
296 | } | |
297 | ||
298 | static u32 pch_read_soft_strap(int id) | |
299 | { | |
300 | clrbits_le32(SPI_REG(SPIBAR_FDOC), 0x00007ffc); | |
301 | setbits_le32(SPI_REG(SPIBAR_FDOC), 0x00004000 | id * 4); | |
302 | ||
303 | return readl(SPI_REG(SPIBAR_FDOD)); | |
304 | } | |
305 | ||
306 | static void pch_enable_mphy(struct udevice *dev) | |
307 | { | |
308 | u32 data_and = 0xffffffff; | |
309 | u32 data_or = (1 << 14) | (1 << 13) | (1 << 12); | |
310 | ||
311 | data_or |= (1 << 0); | |
312 | if (pch_is_wpt(dev)) { | |
313 | data_and &= ~((1 << 7) | (1 << 6) | (1 << 3)); | |
314 | data_or |= (1 << 5) | (1 << 4); | |
315 | ||
316 | if (pch_is_wpt_ulx(dev)) { | |
317 | /* Check if SATA and USB3 MPHY are enabled */ | |
318 | u32 strap19 = pch_read_soft_strap(19); | |
319 | strap19 &= ((1 << 31) | (1 << 30)); | |
320 | strap19 >>= 30; | |
321 | if (strap19 == 3) { | |
322 | data_or |= (1 << 3); | |
323 | debug("Enable ULX MPHY PG control in single domain\n"); | |
324 | } else if (strap19 == 0) { | |
325 | debug("Enable ULX MPHY PG control in split domains\n"); | |
326 | } else { | |
327 | debug("Invalid PCH Soft Strap 19 configuration\n"); | |
328 | } | |
329 | } else { | |
330 | data_or |= (1 << 3); | |
331 | } | |
332 | } | |
333 | ||
334 | pch_iobp_update(0xCF000000, data_and, data_or); | |
335 | } | |
336 | ||
337 | static void pch_init_deep_sx(bool deep_sx_enable_ac, bool deep_sx_enable_dc) | |
338 | { | |
339 | if (deep_sx_enable_ac) { | |
340 | setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_AC); | |
341 | setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_AC); | |
342 | } | |
343 | ||
344 | if (deep_sx_enable_dc) { | |
345 | setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_DC); | |
346 | setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_DC); | |
347 | } | |
348 | ||
349 | if (deep_sx_enable_ac || deep_sx_enable_dc) { | |
350 | setbits_le32(RCB_REG(DEEP_SX_CONFIG), | |
351 | DEEP_SX_WAKE_PIN_EN | DEEP_SX_GP27_PIN_EN); | |
352 | } | |
353 | } | |
354 | ||
355 | /* Power Management init */ | |
356 | static void pch_pm_init(struct udevice *dev) | |
357 | { | |
358 | debug("PCH PM init\n"); | |
359 | ||
360 | pch_init_deep_sx(false, false); | |
361 | pch_enable_mphy(dev); | |
362 | pch_pm_init_magic(dev); | |
363 | ||
364 | if (pch_is_wpt(dev)) { | |
365 | setbits_le32(RCB_REG(0x33e0), 1 << 4 | 1 << 1); | |
366 | setbits_le32(RCB_REG(0x2b1c), 1 << 22 | 1 << 14 | 1 << 13); | |
367 | writel(0x16bf0002, RCB_REG(0x33e4)); | |
368 | setbits_le32(RCB_REG(0x33e4), 0x1); | |
369 | } | |
370 | ||
371 | pch_iobp_update(0xCA000000, ~0UL, 0x00000009); | |
372 | ||
373 | /* Set RCBA 0x2b1c[29]=1 if DSP disabled */ | |
374 | if (readl(RCB_REG(FD)) & PCH_DISABLE_ADSPD) | |
375 | setbits_le32(RCB_REG(0x2b1c), 1 << 29); | |
376 | } | |
377 | ||
378 | static void pch_cg_init(struct udevice *dev) | |
379 | { | |
380 | struct udevice *bus = pci_get_controller(dev); | |
381 | u32 reg32; | |
382 | u16 reg16; | |
383 | ulong val; | |
384 | ||
385 | /* DMI */ | |
386 | setbits_le32(RCB_REG(0x2234), 0xf); | |
387 | ||
388 | dm_pci_read_config16(dev, GEN_PMCON_1, ®16); | |
389 | reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ | |
390 | if (pch_is_wpt(dev)) | |
391 | reg16 &= ~(1 << 11); | |
392 | else | |
393 | reg16 |= 1 << 11; | |
394 | reg16 |= 1 << 5 | 1 << 6 | 1 << 7 | 1 << 12; | |
395 | reg16 |= 1 << 2; /* PCI CLKRUN# Enable */ | |
396 | dm_pci_write_config16(dev, GEN_PMCON_1, reg16); | |
397 | ||
398 | /* | |
399 | * RCBA + 0x2614[27:25,14:13,10,8] = 101,11,1,1 | |
400 | * RCBA + 0x2614[23:16] = 0x20 | |
401 | * RCBA + 0x2614[30:28] = 0x0 | |
402 | * RCBA + 0x2614[26] = 1 (IF 0:2.0@0x08 >= 0x0b) | |
403 | */ | |
404 | clrsetbits_le32(RCB_REG(0x2614), 0x64ff0000, 0x0a206500); | |
405 | ||
406 | /* Check for 0:2.0@0x08 >= 0x0b */ | |
407 | pci_bus_read_config(bus, PCI_BDF(0, 0x2, 0), 0x8, &val, PCI_SIZE_8); | |
408 | if (pch_is_wpt(dev) || val >= 0x0b) | |
409 | setbits_le32(RCB_REG(0x2614), 1 << 26); | |
410 | ||
411 | setbits_le32(RCB_REG(0x900), 0x0000031f); | |
412 | ||
413 | reg32 = readl(RCB_REG(CG)); | |
414 | if (readl(RCB_REG(0x3454)) & (1 << 4)) | |
415 | reg32 &= ~(1 << 29); /* LPC Dynamic */ | |
416 | else | |
417 | reg32 |= (1 << 29); /* LPC Dynamic */ | |
418 | reg32 |= 1 << 31; /* LP LPC */ | |
419 | reg32 |= 1 << 30; /* LP BLA */ | |
420 | if (readl(RCB_REG(0x3454)) & (1 << 4)) | |
421 | reg32 &= ~(1 << 29); | |
422 | else | |
423 | reg32 |= 1 << 29; | |
424 | reg32 |= 1 << 28; /* GPIO Dynamic */ | |
425 | reg32 |= 1 << 27; /* HPET Dynamic */ | |
426 | reg32 |= 1 << 26; /* Generic Platform Event Clock */ | |
427 | if (readl(RCB_REG(BUC)) & PCH_DISABLE_GBE) | |
428 | reg32 |= 1 << 23; /* GbE Static */ | |
429 | if (readl(RCB_REG(FD)) & PCH_DISABLE_HD_AUDIO) | |
430 | reg32 |= 1 << 21; /* HDA Static */ | |
431 | reg32 |= 1 << 22; /* HDA Dynamic */ | |
432 | writel(reg32, RCB_REG(CG)); | |
433 | ||
434 | /* PCH-LP LPC */ | |
435 | if (pch_is_wpt(dev)) | |
436 | clrsetbits_le32(RCB_REG(0x3434), 0x1f, 0x17); | |
437 | else | |
438 | setbits_le32(RCB_REG(0x3434), 0x7); | |
439 | ||
440 | /* SPI */ | |
441 | setbits_le32(RCB_REG(0x38c0), 0x3c07); | |
442 | ||
443 | pch_iobp_update(0xCE00C000, ~1UL, 0x00000000); | |
444 | } | |
445 | ||
446 | static void systemagent_init(void) | |
447 | { | |
448 | /* Enable Power Aware Interrupt Routing */ | |
449 | clrsetbits_8(MCHBAR_REG(MCH_PAIR), 0x7, 0x4); /* Fixed Priority */ | |
450 | ||
451 | /* | |
452 | * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU | |
453 | * that BIOS has initialized memory and power management | |
454 | */ | |
455 | setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 3); | |
456 | debug("Set BIOS_RESET_CPL\n"); | |
457 | ||
458 | /* Configure turbo power limits 1ms after reset complete bit */ | |
459 | mdelay(1); | |
460 | ||
461 | cpu_set_power_limits(28); | |
462 | } | |
463 | ||
3f3411eb SG |
464 | /* Enable LTR Auto Mode for D21:F1-F6 */ |
465 | static void serialio_d21_ltr(u32 bar0) | |
466 | { | |
467 | /* 1. Program BAR0 + 808h[2] = 0b */ | |
468 | clrbits_le32(bar0 + SIO_REG_PPR_GEN, SIO_REG_PPR_GEN_LTR_MODE_MASK); | |
469 | ||
470 | /* 2. Program BAR0 + 804h[1:0] = 00b */ | |
471 | clrbits_le32(bar0 + SIO_REG_PPR_RST, SIO_REG_PPR_RST_ASSERT); | |
472 | ||
473 | /* 3. Program BAR0 + 804h[1:0] = 11b */ | |
474 | setbits_le32(bar0 + SIO_REG_PPR_RST, SIO_REG_PPR_RST_ASSERT); | |
475 | ||
476 | /* 4. Program BAR0 + 814h[31:0] = 00000000h */ | |
477 | writel(0, bar0 + SIO_REG_AUTO_LTR); | |
478 | } | |
479 | ||
480 | /* Select I2C voltage of 1.8V or 3.3V */ | |
481 | static void serialio_i2c_voltage_sel(u32 bar0, uint voltage) | |
482 | { | |
483 | clrsetbits_le32(bar0 + SIO_REG_PPR_GEN, SIO_REG_PPR_GEN_VOLTAGE_MASK, | |
484 | SIO_REG_PPR_GEN_VOLTAGE(voltage)); | |
485 | } | |
486 | ||
487 | /* Put Serial IO D21:F0-F6 device into desired mode */ | |
488 | static void serialio_d21_mode(int sio_index, int int_pin, bool acpi_mode) | |
489 | { | |
490 | u32 portctrl = SIO_IOBP_PORTCTRL_PM_CAP_PRSNT; | |
491 | ||
492 | /* Snoop select 1 */ | |
493 | portctrl |= SIO_IOBP_PORTCTRL_SNOOP_SELECT(1); | |
494 | ||
495 | /* Set interrupt pin */ | |
496 | portctrl |= SIO_IOBP_PORTCTRL_INT_PIN(int_pin); | |
497 | ||
498 | if (acpi_mode) { | |
499 | /* Enable ACPI interrupt mode */ | |
500 | portctrl |= SIO_IOBP_PORTCTRL_ACPI_IRQ_EN; | |
501 | } | |
502 | ||
503 | pch_iobp_update(SIO_IOBP_PORTCTRLX(sio_index), 0, portctrl); | |
504 | } | |
505 | ||
506 | /* Init sequence to be run once, done as part of D21:F0 (SDMA) init */ | |
507 | static void serialio_init_once(bool acpi_mode) | |
508 | { | |
509 | if (acpi_mode) { | |
510 | /* Enable ACPI IRQ for IRQ13, IRQ7, IRQ6, IRQ5 in RCBA */ | |
511 | setbits_le32(RCB_REG(ACPIIRQEN), | |
512 | 1 << 13 | 1 << 7 | 1 << 6 | 1 << 5); | |
513 | } | |
514 | ||
515 | /* Program IOBP CB000154h[12,9:8,4:0] = 1001100011111b */ | |
516 | pch_iobp_update(SIO_IOBP_GPIODF, ~0x0000131f, 0x0000131f); | |
517 | ||
518 | /* Program IOBP CB000180h[5:0] = 111111b (undefined register) */ | |
519 | pch_iobp_update(0xcb000180, ~0x0000003f, 0x0000003f); | |
520 | } | |
521 | ||
522 | /** | |
523 | * pch_serialio_init() - set up serial I/O devices | |
524 | * | |
525 | * @return 0 if OK, -ve on error | |
526 | */ | |
527 | static int pch_serialio_init(void) | |
528 | { | |
529 | struct udevice *dev, *hda; | |
530 | bool acpi_mode = true; | |
531 | u32 bar0, bar1; | |
532 | int ret; | |
533 | ||
534 | ret = uclass_find_first_device(UCLASS_I2C, &dev); | |
535 | if (ret) | |
536 | return ret; | |
537 | bar0 = dm_pci_read_bar32(dev, 0); | |
538 | if (!bar0) | |
539 | return -EINVAL; | |
540 | bar1 = dm_pci_read_bar32(dev, 1); | |
541 | if (!bar1) | |
542 | return -EINVAL; | |
543 | ||
544 | serialio_init_once(acpi_mode); | |
545 | serialio_d21_mode(SIO_ID_SDMA, SIO_PIN_INTB, acpi_mode); | |
546 | ||
547 | serialio_d21_ltr(bar0); | |
548 | serialio_i2c_voltage_sel(bar0, 1); /* Select 1.8V always */ | |
549 | serialio_d21_mode(SIO_ID_I2C0, SIO_PIN_INTC, acpi_mode); | |
550 | setbits_le32(bar1 + PCH_PCS, PCH_PCS_PS_D3HOT); | |
551 | ||
552 | clrbits_le32(bar1 + PCH_PCS, PCH_PCS_PS_D3HOT); | |
553 | ||
554 | setbits_le32(bar0 + SIO_REG_PPR_CLOCK, SIO_REG_PPR_CLOCK_EN); | |
555 | ||
556 | /* Manually find the High-definition audio, to turn it off */ | |
557 | ret = dm_pci_bus_find_bdf(PCI_BDF(0, 0x1b, 0), &hda); | |
558 | if (ret) | |
559 | return -ENOENT; | |
560 | dm_pci_clrset_config8(hda, 0x43, 0, 0x6f); | |
561 | ||
562 | /* Route I/O buffers to ADSP function */ | |
563 | dm_pci_clrset_config8(hda, 0x42, 0, 1 << 7 | 1 << 6); | |
564 | log_debug("HDA disabled, I/O buffers routed to ADSP\n"); | |
565 | ||
566 | return 0; | |
567 | } | |
568 | ||
1e6f4e58 SG |
569 | static int broadwell_pch_init(struct udevice *dev) |
570 | { | |
571 | int ret; | |
572 | ||
573 | /* Enable upper 128 bytes of CMOS */ | |
574 | setbits_le32(RCB_REG(RC), 1 << 2); | |
575 | ||
576 | /* | |
577 | * TODO: TCO timer halt - this hangs | |
578 | * setio_16(ACPI_BASE_ADDRESS + TCO1_CNT, TCO_TMR_HLT); | |
579 | */ | |
580 | ||
581 | /* Disable unused device (always) */ | |
582 | setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS); | |
583 | ||
584 | pch_misc_init(dev); | |
585 | ||
586 | /* Interrupt configuration */ | |
587 | pch_enable_ioapic(); | |
588 | ||
589 | /* Initialize power management */ | |
590 | ret = pch_power_options(dev); | |
591 | if (ret) | |
592 | return ret; | |
593 | pch_pm_init(dev); | |
594 | pch_cg_init(dev); | |
3f3411eb SG |
595 | ret = pch_serialio_init(); |
596 | if (ret) | |
597 | return ret; | |
1e6f4e58 SG |
598 | systemagent_init(); |
599 | ||
600 | return 0; | |
601 | } | |
602 | ||
603 | static int broadwell_pch_probe(struct udevice *dev) | |
604 | { | |
bfeeb8d8 SG |
605 | if (CONFIG_IS_ENABLED(X86_32BIT_INIT)) { |
606 | if (!(gd->flags & GD_FLG_RELOC)) | |
607 | return broadwell_pch_early_init(dev); | |
608 | else | |
609 | return broadwell_pch_init(dev); | |
610 | } else if (IS_ENABLED(CONFIG_SPL) && !IS_ENABLED(CONFIG_SPL_BUILD)) { | |
1e6f4e58 | 611 | return broadwell_pch_init(dev); |
bfeeb8d8 SG |
612 | } else { |
613 | return 0; | |
614 | } | |
1e6f4e58 SG |
615 | } |
616 | ||
617 | static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep) | |
618 | { | |
619 | u32 rcba; | |
620 | ||
621 | dm_pci_read_config32(dev, PCH_RCBA, &rcba); | |
622 | /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ | |
623 | rcba = rcba & 0xffffc000; | |
624 | *sbasep = rcba + 0x3800; | |
625 | ||
626 | return 0; | |
627 | } | |
628 | ||
629 | static int broadwell_set_spi_protect(struct udevice *dev, bool protect) | |
630 | { | |
631 | return lpc_set_spi_protect(dev, BIOS_CTRL, protect); | |
632 | } | |
633 | ||
634 | static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep) | |
635 | { | |
636 | dm_pci_read_config32(dev, GPIO_BASE, gbasep); | |
637 | *gbasep &= PCI_BASE_ADDRESS_IO_MASK; | |
638 | ||
639 | return 0; | |
640 | } | |
641 | ||
2b36eabd SG |
642 | static int broadwell_ioctl(struct udevice *dev, enum pch_req_t req, void *data, |
643 | int size) | |
644 | { | |
645 | switch (req) { | |
646 | case PCH_REQ_PMBASE_INFO: { | |
647 | struct pch_pmbase_info *pm = data; | |
648 | int ret; | |
649 | ||
650 | /* Find the base address of the powermanagement registers */ | |
651 | ret = dm_pci_read_config16(dev, 0x40, &pm->base); | |
652 | if (ret) | |
653 | return ret; | |
654 | pm->base &= 0xfffe; | |
655 | pm->gpio0_en_ofs = GPE0_EN(0); | |
656 | pm->pm1_sts_ofs = PM1_STS; | |
657 | pm->pm1_cnt_ofs = PM1_CNT; | |
658 | ||
659 | return 0; | |
660 | } | |
661 | default: | |
662 | return -ENOSYS; | |
663 | } | |
664 | } | |
665 | ||
1e6f4e58 SG |
666 | static const struct pch_ops broadwell_pch_ops = { |
667 | .get_spi_base = broadwell_pch_get_spi_base, | |
668 | .set_spi_protect = broadwell_set_spi_protect, | |
669 | .get_gpio_base = broadwell_get_gpio_base, | |
2b36eabd | 670 | .ioctl = broadwell_ioctl, |
1e6f4e58 SG |
671 | }; |
672 | ||
673 | static const struct udevice_id broadwell_pch_ids[] = { | |
674 | { .compatible = "intel,broadwell-pch" }, | |
675 | { } | |
676 | }; | |
677 | ||
678 | U_BOOT_DRIVER(broadwell_pch) = { | |
679 | .name = "broadwell_pch", | |
680 | .id = UCLASS_PCH, | |
681 | .of_match = broadwell_pch_ids, | |
682 | .probe = broadwell_pch_probe, | |
683 | .ops = &broadwell_pch_ops, | |
684 | }; |