1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0 21e6f4e58SSimon Glass /* 31e6f4e58SSimon Glass * Copyright (c) 2016 Google, Inc 41e6f4e58SSimon Glass */ 51e6f4e58SSimon Glass 61e6f4e58SSimon Glass #include <common.h> 71e6f4e58SSimon Glass #include <dm.h> 81e6f4e58SSimon Glass #include <pch.h> 91e6f4e58SSimon Glass #include <asm/cpu.h> 101e6f4e58SSimon Glass #include <asm/gpio.h> 111e6f4e58SSimon Glass #include <asm/i8259.h> 121e6f4e58SSimon Glass #include <asm/intel_regs.h> 131e6f4e58SSimon Glass #include <asm/io.h> 141e6f4e58SSimon Glass #include <asm/ioapic.h> 151e6f4e58SSimon Glass #include <asm/lpc_common.h> 161e6f4e58SSimon Glass #include <asm/pch_common.h> 171e6f4e58SSimon Glass #include <asm/arch/cpu.h> 181e6f4e58SSimon Glass #include <asm/arch/gpio.h> 191e6f4e58SSimon Glass #include <asm/arch/iomap.h> 201e6f4e58SSimon Glass #include <asm/arch/pch.h> 211e6f4e58SSimon Glass #include <asm/arch/pm.h> 221e6f4e58SSimon Glass #include <asm/arch/rcb.h> 231e6f4e58SSimon Glass #include <asm/arch/spi.h> 241e6f4e58SSimon Glass 251e6f4e58SSimon Glass #define BIOS_CTRL 0xdc 261e6f4e58SSimon Glass 271e6f4e58SSimon Glass bool cpu_is_ult(void) 281e6f4e58SSimon Glass { 291e6f4e58SSimon Glass u32 fm = cpu_get_family_model(); 301e6f4e58SSimon Glass 311e6f4e58SSimon Glass return fm == BROADWELL_FAMILY_ULT || fm == HASWELL_FAMILY_ULT; 321e6f4e58SSimon Glass } 331e6f4e58SSimon Glass 341e6f4e58SSimon Glass static int broadwell_pch_early_init(struct udevice *dev) 351e6f4e58SSimon Glass { 361e6f4e58SSimon Glass struct gpio_desc desc; 371e6f4e58SSimon Glass struct udevice *bus; 381e6f4e58SSimon Glass pci_dev_t bdf; 391e6f4e58SSimon Glass int ret; 401e6f4e58SSimon Glass 411e6f4e58SSimon Glass dm_pci_write_config32(dev, PCH_RCBA, RCB_BASE_ADDRESS | 1); 421e6f4e58SSimon Glass 431e6f4e58SSimon Glass dm_pci_write_config32(dev, PMBASE, ACPI_BASE_ADDRESS | 1); 441e6f4e58SSimon Glass dm_pci_write_config8(dev, ACPI_CNTL, ACPI_EN); 451e6f4e58SSimon Glass dm_pci_write_config32(dev, GPIO_BASE, GPIO_BASE_ADDRESS | 1); 461e6f4e58SSimon Glass dm_pci_write_config8(dev, GPIO_CNTL, GPIO_EN); 471e6f4e58SSimon Glass 481e6f4e58SSimon Glass /* Enable IOAPIC */ 491e6f4e58SSimon Glass writew(0x1000, RCB_REG(OIC)); 501e6f4e58SSimon Glass /* Read back for posted write */ 511e6f4e58SSimon Glass readw(RCB_REG(OIC)); 521e6f4e58SSimon Glass 531e6f4e58SSimon Glass /* Set HPET address and enable it */ 541e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(HPTC), 3, 1 << 7); 551e6f4e58SSimon Glass /* Read back for posted write */ 561e6f4e58SSimon Glass readl(RCB_REG(HPTC)); 571e6f4e58SSimon Glass /* Enable HPET to start counter */ 581e6f4e58SSimon Glass setbits_le32(HPET_BASE_ADDRESS + 0x10, 1 << 0); 591e6f4e58SSimon Glass 601e6f4e58SSimon Glass setbits_le32(RCB_REG(GCS), 1 << 5); 611e6f4e58SSimon Glass 621e6f4e58SSimon Glass /* 631e6f4e58SSimon Glass * Enable PP3300_AUTOBAHN_EN after initial GPIO setup 641e6f4e58SSimon Glass * to prevent possible brownout. This will cause the GPIOs to be set 651e6f4e58SSimon Glass * up if it has not been done already. 661e6f4e58SSimon Glass */ 671e6f4e58SSimon Glass ret = gpio_request_by_name(dev, "power-enable-gpio", 0, &desc, 681e6f4e58SSimon Glass GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 691e6f4e58SSimon Glass if (ret) 701e6f4e58SSimon Glass return ret; 711e6f4e58SSimon Glass 721e6f4e58SSimon Glass /* 8.14 Additional PCI Express Programming Steps, step #1 */ 731e6f4e58SSimon Glass bdf = PCI_BDF(0, 0x1c, 0); 741e6f4e58SSimon Glass bus = pci_get_controller(dev); 751e6f4e58SSimon Glass pci_bus_clrset_config32(bus, bdf, 0xf4, 0x60, 0); 761e6f4e58SSimon Glass pci_bus_clrset_config32(bus, bdf, 0xf4, 0x80, 0x80); 771e6f4e58SSimon Glass pci_bus_clrset_config32(bus, bdf, 0xe2, 0x30, 0x30); 781e6f4e58SSimon Glass 791e6f4e58SSimon Glass return 0; 801e6f4e58SSimon Glass } 811e6f4e58SSimon Glass 821e6f4e58SSimon Glass static void pch_misc_init(struct udevice *dev) 831e6f4e58SSimon Glass { 841e6f4e58SSimon Glass /* Setup SLP signal assertion, SLP_S4=4s, SLP_S3=50ms */ 851e6f4e58SSimon Glass dm_pci_clrset_config8(dev, GEN_PMCON_3, 3 << 4 | 1 << 10, 861e6f4e58SSimon Glass 1 << 3 | 1 << 11 | 1 << 12); 871e6f4e58SSimon Glass /* Prepare sleep mode */ 881e6f4e58SSimon Glass clrsetio_32(ACPI_BASE_ADDRESS + PM1_CNT, SLP_TYP, SCI_EN); 891e6f4e58SSimon Glass 901e6f4e58SSimon Glass /* Setup NMI on errors, disable SERR */ 911e6f4e58SSimon Glass clrsetio_8(0x61, 0xf0, 1 << 2); 921e6f4e58SSimon Glass /* Disable NMI sources */ 931e6f4e58SSimon Glass setio_8(0x70, 1 << 7); 941e6f4e58SSimon Glass /* Indicate DRAM init done for MRC */ 951e6f4e58SSimon Glass dm_pci_clrset_config8(dev, GEN_PMCON_2, 0, 1 << 7); 961e6f4e58SSimon Glass 971e6f4e58SSimon Glass /* Clear status bits to prevent unexpected wake */ 981e6f4e58SSimon Glass setbits_le32(RCB_REG(0x3310), 0x0000002f); 991e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(0x3f02), 0x0000000f, 0); 1001e6f4e58SSimon Glass /* Enable PCIe Relaxed Order */ 1011e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2314), 1 << 31 | 1 << 7); 1021e6f4e58SSimon Glass setbits_le32(RCB_REG(0x1114), 1 << 15 | 1 << 14); 1031e6f4e58SSimon Glass /* Setup SERIRQ, enable continuous mode */ 1041e6f4e58SSimon Glass dm_pci_clrset_config8(dev, SERIRQ_CNTL, 0, 1 << 7 | 1 << 6); 1051e6f4e58SSimon Glass }; 1061e6f4e58SSimon Glass 1071e6f4e58SSimon Glass static void pch_enable_ioapic(void) 1081e6f4e58SSimon Glass { 1091e6f4e58SSimon Glass u32 reg32; 1101e6f4e58SSimon Glass 111b813ea9aSBin Meng /* Make sure this is a unique ID within system */ 112b813ea9aSBin Meng io_apic_set_id(0x04); 1131e6f4e58SSimon Glass 1141e6f4e58SSimon Glass /* affirm full set of redirection table entries ("write once") */ 1151e6f4e58SSimon Glass reg32 = io_apic_read(0x01); 1161e6f4e58SSimon Glass 1171e6f4e58SSimon Glass /* PCH-LP has 39 redirection entries */ 1181e6f4e58SSimon Glass reg32 &= ~0x00ff0000; 1191e6f4e58SSimon Glass reg32 |= 0x00270000; 1201e6f4e58SSimon Glass 1211e6f4e58SSimon Glass io_apic_write(0x01, reg32); 1221e6f4e58SSimon Glass 1231e6f4e58SSimon Glass /* 1241e6f4e58SSimon Glass * Select Boot Configuration register (0x03) and 1251e6f4e58SSimon Glass * use Processor System Bus (0x01) to deliver interrupts. 1261e6f4e58SSimon Glass */ 1271e6f4e58SSimon Glass io_apic_write(0x03, 0x01); 1281e6f4e58SSimon Glass } 1291e6f4e58SSimon Glass 1301e6f4e58SSimon Glass /* Enable all requested GPE */ 1311e6f4e58SSimon Glass void enable_all_gpe(u32 set1, u32 set2, u32 set3, u32 set4) 1321e6f4e58SSimon Glass { 1331e6f4e58SSimon Glass outl(set1, ACPI_BASE_ADDRESS + GPE0_EN(GPE_31_0)); 1341e6f4e58SSimon Glass outl(set2, ACPI_BASE_ADDRESS + GPE0_EN(GPE_63_32)); 1351e6f4e58SSimon Glass outl(set3, ACPI_BASE_ADDRESS + GPE0_EN(GPE_94_64)); 1361e6f4e58SSimon Glass outl(set4, ACPI_BASE_ADDRESS + GPE0_EN(GPE_STD)); 1371e6f4e58SSimon Glass } 1381e6f4e58SSimon Glass 1391e6f4e58SSimon Glass /* 1401e6f4e58SSimon Glass * Enable GPIO SMI events - it would be good to put this in the GPIO driver 1411e6f4e58SSimon Glass * but it would need a new driver operation. 1421e6f4e58SSimon Glass */ 1431e6f4e58SSimon Glass int enable_alt_smi(struct udevice *pch, u32 mask) 1441e6f4e58SSimon Glass { 1451e6f4e58SSimon Glass struct pch_lp_gpio_regs *regs; 1461e6f4e58SSimon Glass u32 gpiobase; 1471e6f4e58SSimon Glass int ret; 1481e6f4e58SSimon Glass 1491e6f4e58SSimon Glass ret = pch_get_gpio_base(pch, &gpiobase); 1501e6f4e58SSimon Glass if (ret) { 1511e6f4e58SSimon Glass debug("%s: invalid GPIOBASE address (%08x)\n", __func__, 1521e6f4e58SSimon Glass gpiobase); 1531e6f4e58SSimon Glass return -EINVAL; 1541e6f4e58SSimon Glass } 1551e6f4e58SSimon Glass 1561e6f4e58SSimon Glass regs = (struct pch_lp_gpio_regs *)gpiobase; 1571e6f4e58SSimon Glass setio_32(regs->alt_gpi_smi_en, mask); 1581e6f4e58SSimon Glass 1591e6f4e58SSimon Glass return 0; 1601e6f4e58SSimon Glass } 1611e6f4e58SSimon Glass 1621e6f4e58SSimon Glass static int pch_power_options(struct udevice *dev) 1631e6f4e58SSimon Glass { 1641e6f4e58SSimon Glass int pwr_on_after_power_fail = MAINBOARD_POWER_OFF; 1651e6f4e58SSimon Glass const char *state; 1661e6f4e58SSimon Glass u32 enable[4]; 1671e6f4e58SSimon Glass u16 reg16; 1681e6f4e58SSimon Glass int ret; 1691e6f4e58SSimon Glass 1701e6f4e58SSimon Glass dm_pci_read_config16(dev, GEN_PMCON_3, ®16); 1711e6f4e58SSimon Glass reg16 &= 0xfffe; 1721e6f4e58SSimon Glass switch (pwr_on_after_power_fail) { 1731e6f4e58SSimon Glass case MAINBOARD_POWER_OFF: 1741e6f4e58SSimon Glass reg16 |= 1; 1751e6f4e58SSimon Glass state = "off"; 1761e6f4e58SSimon Glass break; 1771e6f4e58SSimon Glass case MAINBOARD_POWER_ON: 1781e6f4e58SSimon Glass reg16 &= ~1; 1791e6f4e58SSimon Glass state = "on"; 1801e6f4e58SSimon Glass break; 1811e6f4e58SSimon Glass case MAINBOARD_POWER_KEEP: 1821e6f4e58SSimon Glass reg16 &= ~1; 1831e6f4e58SSimon Glass state = "state keep"; 1841e6f4e58SSimon Glass break; 1851e6f4e58SSimon Glass default: 1861e6f4e58SSimon Glass state = "undefined"; 1871e6f4e58SSimon Glass } 1881e6f4e58SSimon Glass dm_pci_write_config16(dev, GEN_PMCON_3, reg16); 1891e6f4e58SSimon Glass debug("Set power %s after power failure.\n", state); 1901e6f4e58SSimon Glass 1911e6f4e58SSimon Glass /* GPE setup based on device tree configuration */ 192e160f7d4SSimon Glass ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), 1931e6f4e58SSimon Glass "intel,gpe0-en", enable, ARRAY_SIZE(enable)); 1941e6f4e58SSimon Glass if (ret) 1951e6f4e58SSimon Glass return -EINVAL; 1961e6f4e58SSimon Glass enable_all_gpe(enable[0], enable[1], enable[2], enable[3]); 1971e6f4e58SSimon Glass 1981e6f4e58SSimon Glass /* SMI setup based on device tree configuration */ 199e160f7d4SSimon Glass enable_alt_smi(dev, fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 2001e6f4e58SSimon Glass "intel,alt-gp-smi-enable", 0)); 2011e6f4e58SSimon Glass 2021e6f4e58SSimon Glass return 0; 2031e6f4e58SSimon Glass } 2041e6f4e58SSimon Glass 2051e6f4e58SSimon Glass /* Magic register settings for power management */ 2061e6f4e58SSimon Glass static void pch_pm_init_magic(struct udevice *dev) 2071e6f4e58SSimon Glass { 2081e6f4e58SSimon Glass dm_pci_write_config8(dev, 0xa9, 0x46); 2091e6f4e58SSimon Glass clrbits_le32(RCB_REG(0x232c), 1), 2101e6f4e58SSimon Glass setbits_le32(RCB_REG(0x1100), 0x0000c13f); 2111e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(0x2320), 0x60, 0x10); 2121e6f4e58SSimon Glass writel(0x00012fff, RCB_REG(0x3314)); 2131e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(0x3318), 0x000f0330, 0x0dcf0400); 2141e6f4e58SSimon Glass writel(0x04000000, RCB_REG(0x3324)); 2151e6f4e58SSimon Glass writel(0x00041400, RCB_REG(0x3368)); 2161e6f4e58SSimon Glass writel(0x3f8ddbff, RCB_REG(0x3388)); 2171e6f4e58SSimon Glass writel(0x00007001, RCB_REG(0x33ac)); 2181e6f4e58SSimon Glass writel(0x00181900, RCB_REG(0x33b0)); 2191e6f4e58SSimon Glass writel(0x00060A00, RCB_REG(0x33c0)); 2201e6f4e58SSimon Glass writel(0x06200840, RCB_REG(0x33d0)); 2211e6f4e58SSimon Glass writel(0x01010101, RCB_REG(0x3a28)); 2221e6f4e58SSimon Glass writel(0x040c0404, RCB_REG(0x3a2c)); 2231e6f4e58SSimon Glass writel(0x9000000a, RCB_REG(0x3a9c)); 2241e6f4e58SSimon Glass writel(0x03808033, RCB_REG(0x2b1c)); 2251e6f4e58SSimon Glass writel(0x80000009, RCB_REG(0x2b34)); 2261e6f4e58SSimon Glass writel(0x022ddfff, RCB_REG(0x3348)); 2271e6f4e58SSimon Glass writel(0x00000001, RCB_REG(0x334c)); 2281e6f4e58SSimon Glass writel(0x0001c000, RCB_REG(0x3358)); 2291e6f4e58SSimon Glass writel(0x3f8ddbff, RCB_REG(0x3380)); 2301e6f4e58SSimon Glass writel(0x0001c7e1, RCB_REG(0x3384)); 2311e6f4e58SSimon Glass writel(0x0001c7e1, RCB_REG(0x338c)); 2321e6f4e58SSimon Glass writel(0x0001c000, RCB_REG(0x3398)); 2331e6f4e58SSimon Glass writel(0x00181900, RCB_REG(0x33a8)); 2341e6f4e58SSimon Glass writel(0x00080000, RCB_REG(0x33dc)); 2351e6f4e58SSimon Glass writel(0x00000001, RCB_REG(0x33e0)); 2361e6f4e58SSimon Glass writel(0x0000040c, RCB_REG(0x3a20)); 2371e6f4e58SSimon Glass writel(0x01010101, RCB_REG(0x3a24)); 2381e6f4e58SSimon Glass writel(0x01010101, RCB_REG(0x3a30)); 2391e6f4e58SSimon Glass dm_pci_clrset_config32(dev, 0xac, 0x00200000, 0); 2401e6f4e58SSimon Glass setbits_le32(RCB_REG(0x0410), 0x00000003); 2411e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2618), 0x08000000); 2421e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2300), 0x00000002); 2431e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2600), 0x00000008); 2441e6f4e58SSimon Glass writel(0x00007001, RCB_REG(0x33b4)); 2451e6f4e58SSimon Glass writel(0x022ddfff, RCB_REG(0x3350)); 2461e6f4e58SSimon Glass writel(0x00000001, RCB_REG(0x3354)); 2471e6f4e58SSimon Glass /* Power Optimizer */ 2481e6f4e58SSimon Glass setbits_le32(RCB_REG(0x33d4), 0x08000000); 2491e6f4e58SSimon Glass /* 2501e6f4e58SSimon Glass * This stops the LCD from turning on: 2511e6f4e58SSimon Glass * setbits_le32(RCB_REG(0x33c8), 0x08000080); 2521e6f4e58SSimon Glass */ 2531e6f4e58SSimon Glass writel(0x0000883c, RCB_REG(0x2b10)); 2541e6f4e58SSimon Glass writel(0x1e0a4616, RCB_REG(0x2b14)); 2551e6f4e58SSimon Glass writel(0x40000005, RCB_REG(0x2b24)); 2561e6f4e58SSimon Glass writel(0x0005db01, RCB_REG(0x2b20)); 2571e6f4e58SSimon Glass writel(0x05145005, RCB_REG(0x3a80)); 2581e6f4e58SSimon Glass writel(0x00001005, RCB_REG(0x3a84)); 2591e6f4e58SSimon Glass setbits_le32(RCB_REG(0x33d4), 0x2fff2fb1); 2601e6f4e58SSimon Glass setbits_le32(RCB_REG(0x33c8), 0x00008000); 2611e6f4e58SSimon Glass }; 2621e6f4e58SSimon Glass 2631e6f4e58SSimon Glass static int pch_type(struct udevice *dev) 2641e6f4e58SSimon Glass { 2651e6f4e58SSimon Glass u16 type; 2661e6f4e58SSimon Glass 2671e6f4e58SSimon Glass dm_pci_read_config16(dev, PCI_DEVICE_ID, &type); 2681e6f4e58SSimon Glass 2691e6f4e58SSimon Glass return type; 2701e6f4e58SSimon Glass } 2711e6f4e58SSimon Glass 2721e6f4e58SSimon Glass /* Return 1 if PCH type is WildcatPoint */ 2731e6f4e58SSimon Glass static int pch_is_wpt(struct udevice *dev) 2741e6f4e58SSimon Glass { 2751e6f4e58SSimon Glass return ((pch_type(dev) & 0xfff0) == 0x9cc0) ? 1 : 0; 2761e6f4e58SSimon Glass } 2771e6f4e58SSimon Glass 2781e6f4e58SSimon Glass /* Return 1 if PCH type is WildcatPoint ULX */ 2791e6f4e58SSimon Glass static int pch_is_wpt_ulx(struct udevice *dev) 2801e6f4e58SSimon Glass { 2811e6f4e58SSimon Glass u16 lpcid = pch_type(dev); 2821e6f4e58SSimon Glass 2831e6f4e58SSimon Glass switch (lpcid) { 2841e6f4e58SSimon Glass case PCH_WPT_BDW_Y_SAMPLE: 2851e6f4e58SSimon Glass case PCH_WPT_BDW_Y_PREMIUM: 2861e6f4e58SSimon Glass case PCH_WPT_BDW_Y_BASE: 2871e6f4e58SSimon Glass return 1; 2881e6f4e58SSimon Glass } 2891e6f4e58SSimon Glass 2901e6f4e58SSimon Glass return 0; 2911e6f4e58SSimon Glass } 2921e6f4e58SSimon Glass 2931e6f4e58SSimon Glass static u32 pch_read_soft_strap(int id) 2941e6f4e58SSimon Glass { 2951e6f4e58SSimon Glass clrbits_le32(SPI_REG(SPIBAR_FDOC), 0x00007ffc); 2961e6f4e58SSimon Glass setbits_le32(SPI_REG(SPIBAR_FDOC), 0x00004000 | id * 4); 2971e6f4e58SSimon Glass 2981e6f4e58SSimon Glass return readl(SPI_REG(SPIBAR_FDOD)); 2991e6f4e58SSimon Glass } 3001e6f4e58SSimon Glass 3011e6f4e58SSimon Glass static void pch_enable_mphy(struct udevice *dev) 3021e6f4e58SSimon Glass { 3031e6f4e58SSimon Glass u32 data_and = 0xffffffff; 3041e6f4e58SSimon Glass u32 data_or = (1 << 14) | (1 << 13) | (1 << 12); 3051e6f4e58SSimon Glass 3061e6f4e58SSimon Glass data_or |= (1 << 0); 3071e6f4e58SSimon Glass if (pch_is_wpt(dev)) { 3081e6f4e58SSimon Glass data_and &= ~((1 << 7) | (1 << 6) | (1 << 3)); 3091e6f4e58SSimon Glass data_or |= (1 << 5) | (1 << 4); 3101e6f4e58SSimon Glass 3111e6f4e58SSimon Glass if (pch_is_wpt_ulx(dev)) { 3121e6f4e58SSimon Glass /* Check if SATA and USB3 MPHY are enabled */ 3131e6f4e58SSimon Glass u32 strap19 = pch_read_soft_strap(19); 3141e6f4e58SSimon Glass strap19 &= ((1 << 31) | (1 << 30)); 3151e6f4e58SSimon Glass strap19 >>= 30; 3161e6f4e58SSimon Glass if (strap19 == 3) { 3171e6f4e58SSimon Glass data_or |= (1 << 3); 3181e6f4e58SSimon Glass debug("Enable ULX MPHY PG control in single domain\n"); 3191e6f4e58SSimon Glass } else if (strap19 == 0) { 3201e6f4e58SSimon Glass debug("Enable ULX MPHY PG control in split domains\n"); 3211e6f4e58SSimon Glass } else { 3221e6f4e58SSimon Glass debug("Invalid PCH Soft Strap 19 configuration\n"); 3231e6f4e58SSimon Glass } 3241e6f4e58SSimon Glass } else { 3251e6f4e58SSimon Glass data_or |= (1 << 3); 3261e6f4e58SSimon Glass } 3271e6f4e58SSimon Glass } 3281e6f4e58SSimon Glass 3291e6f4e58SSimon Glass pch_iobp_update(0xCF000000, data_and, data_or); 3301e6f4e58SSimon Glass } 3311e6f4e58SSimon Glass 3321e6f4e58SSimon Glass static void pch_init_deep_sx(bool deep_sx_enable_ac, bool deep_sx_enable_dc) 3331e6f4e58SSimon Glass { 3341e6f4e58SSimon Glass if (deep_sx_enable_ac) { 3351e6f4e58SSimon Glass setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_AC); 3361e6f4e58SSimon Glass setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_AC); 3371e6f4e58SSimon Glass } 3381e6f4e58SSimon Glass 3391e6f4e58SSimon Glass if (deep_sx_enable_dc) { 3401e6f4e58SSimon Glass setbits_le32(RCB_REG(DEEP_S3_POL), DEEP_S3_EN_DC); 3411e6f4e58SSimon Glass setbits_le32(RCB_REG(DEEP_S5_POL), DEEP_S5_EN_DC); 3421e6f4e58SSimon Glass } 3431e6f4e58SSimon Glass 3441e6f4e58SSimon Glass if (deep_sx_enable_ac || deep_sx_enable_dc) { 3451e6f4e58SSimon Glass setbits_le32(RCB_REG(DEEP_SX_CONFIG), 3461e6f4e58SSimon Glass DEEP_SX_WAKE_PIN_EN | DEEP_SX_GP27_PIN_EN); 3471e6f4e58SSimon Glass } 3481e6f4e58SSimon Glass } 3491e6f4e58SSimon Glass 3501e6f4e58SSimon Glass /* Power Management init */ 3511e6f4e58SSimon Glass static void pch_pm_init(struct udevice *dev) 3521e6f4e58SSimon Glass { 3531e6f4e58SSimon Glass debug("PCH PM init\n"); 3541e6f4e58SSimon Glass 3551e6f4e58SSimon Glass pch_init_deep_sx(false, false); 3561e6f4e58SSimon Glass pch_enable_mphy(dev); 3571e6f4e58SSimon Glass pch_pm_init_magic(dev); 3581e6f4e58SSimon Glass 3591e6f4e58SSimon Glass if (pch_is_wpt(dev)) { 3601e6f4e58SSimon Glass setbits_le32(RCB_REG(0x33e0), 1 << 4 | 1 << 1); 3611e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2b1c), 1 << 22 | 1 << 14 | 1 << 13); 3621e6f4e58SSimon Glass writel(0x16bf0002, RCB_REG(0x33e4)); 3631e6f4e58SSimon Glass setbits_le32(RCB_REG(0x33e4), 0x1); 3641e6f4e58SSimon Glass } 3651e6f4e58SSimon Glass 3661e6f4e58SSimon Glass pch_iobp_update(0xCA000000, ~0UL, 0x00000009); 3671e6f4e58SSimon Glass 3681e6f4e58SSimon Glass /* Set RCBA 0x2b1c[29]=1 if DSP disabled */ 3691e6f4e58SSimon Glass if (readl(RCB_REG(FD)) & PCH_DISABLE_ADSPD) 3701e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2b1c), 1 << 29); 3711e6f4e58SSimon Glass } 3721e6f4e58SSimon Glass 3731e6f4e58SSimon Glass static void pch_cg_init(struct udevice *dev) 3741e6f4e58SSimon Glass { 3751e6f4e58SSimon Glass struct udevice *bus = pci_get_controller(dev); 3761e6f4e58SSimon Glass u32 reg32; 3771e6f4e58SSimon Glass u16 reg16; 3781e6f4e58SSimon Glass ulong val; 3791e6f4e58SSimon Glass 3801e6f4e58SSimon Glass /* DMI */ 3811e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2234), 0xf); 3821e6f4e58SSimon Glass 3831e6f4e58SSimon Glass dm_pci_read_config16(dev, GEN_PMCON_1, ®16); 3841e6f4e58SSimon Glass reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ 3851e6f4e58SSimon Glass if (pch_is_wpt(dev)) 3861e6f4e58SSimon Glass reg16 &= ~(1 << 11); 3871e6f4e58SSimon Glass else 3881e6f4e58SSimon Glass reg16 |= 1 << 11; 3891e6f4e58SSimon Glass reg16 |= 1 << 5 | 1 << 6 | 1 << 7 | 1 << 12; 3901e6f4e58SSimon Glass reg16 |= 1 << 2; /* PCI CLKRUN# Enable */ 3911e6f4e58SSimon Glass dm_pci_write_config16(dev, GEN_PMCON_1, reg16); 3921e6f4e58SSimon Glass 3931e6f4e58SSimon Glass /* 3941e6f4e58SSimon Glass * RCBA + 0x2614[27:25,14:13,10,8] = 101,11,1,1 3951e6f4e58SSimon Glass * RCBA + 0x2614[23:16] = 0x20 3961e6f4e58SSimon Glass * RCBA + 0x2614[30:28] = 0x0 3971e6f4e58SSimon Glass * RCBA + 0x2614[26] = 1 (IF 0:2.0@0x08 >= 0x0b) 3981e6f4e58SSimon Glass */ 3991e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(0x2614), 0x64ff0000, 0x0a206500); 4001e6f4e58SSimon Glass 4011e6f4e58SSimon Glass /* Check for 0:2.0@0x08 >= 0x0b */ 4021e6f4e58SSimon Glass pci_bus_read_config(bus, PCI_BDF(0, 0x2, 0), 0x8, &val, PCI_SIZE_8); 4031e6f4e58SSimon Glass if (pch_is_wpt(dev) || val >= 0x0b) 4041e6f4e58SSimon Glass setbits_le32(RCB_REG(0x2614), 1 << 26); 4051e6f4e58SSimon Glass 4061e6f4e58SSimon Glass setbits_le32(RCB_REG(0x900), 0x0000031f); 4071e6f4e58SSimon Glass 4081e6f4e58SSimon Glass reg32 = readl(RCB_REG(CG)); 4091e6f4e58SSimon Glass if (readl(RCB_REG(0x3454)) & (1 << 4)) 4101e6f4e58SSimon Glass reg32 &= ~(1 << 29); /* LPC Dynamic */ 4111e6f4e58SSimon Glass else 4121e6f4e58SSimon Glass reg32 |= (1 << 29); /* LPC Dynamic */ 4131e6f4e58SSimon Glass reg32 |= 1 << 31; /* LP LPC */ 4141e6f4e58SSimon Glass reg32 |= 1 << 30; /* LP BLA */ 4151e6f4e58SSimon Glass if (readl(RCB_REG(0x3454)) & (1 << 4)) 4161e6f4e58SSimon Glass reg32 &= ~(1 << 29); 4171e6f4e58SSimon Glass else 4181e6f4e58SSimon Glass reg32 |= 1 << 29; 4191e6f4e58SSimon Glass reg32 |= 1 << 28; /* GPIO Dynamic */ 4201e6f4e58SSimon Glass reg32 |= 1 << 27; /* HPET Dynamic */ 4211e6f4e58SSimon Glass reg32 |= 1 << 26; /* Generic Platform Event Clock */ 4221e6f4e58SSimon Glass if (readl(RCB_REG(BUC)) & PCH_DISABLE_GBE) 4231e6f4e58SSimon Glass reg32 |= 1 << 23; /* GbE Static */ 4241e6f4e58SSimon Glass if (readl(RCB_REG(FD)) & PCH_DISABLE_HD_AUDIO) 4251e6f4e58SSimon Glass reg32 |= 1 << 21; /* HDA Static */ 4261e6f4e58SSimon Glass reg32 |= 1 << 22; /* HDA Dynamic */ 4271e6f4e58SSimon Glass writel(reg32, RCB_REG(CG)); 4281e6f4e58SSimon Glass 4291e6f4e58SSimon Glass /* PCH-LP LPC */ 4301e6f4e58SSimon Glass if (pch_is_wpt(dev)) 4311e6f4e58SSimon Glass clrsetbits_le32(RCB_REG(0x3434), 0x1f, 0x17); 4321e6f4e58SSimon Glass else 4331e6f4e58SSimon Glass setbits_le32(RCB_REG(0x3434), 0x7); 4341e6f4e58SSimon Glass 4351e6f4e58SSimon Glass /* SPI */ 4361e6f4e58SSimon Glass setbits_le32(RCB_REG(0x38c0), 0x3c07); 4371e6f4e58SSimon Glass 4381e6f4e58SSimon Glass pch_iobp_update(0xCE00C000, ~1UL, 0x00000000); 4391e6f4e58SSimon Glass } 4401e6f4e58SSimon Glass 4411e6f4e58SSimon Glass static void systemagent_init(void) 4421e6f4e58SSimon Glass { 4431e6f4e58SSimon Glass /* Enable Power Aware Interrupt Routing */ 4441e6f4e58SSimon Glass clrsetbits_8(MCHBAR_REG(MCH_PAIR), 0x7, 0x4); /* Fixed Priority */ 4451e6f4e58SSimon Glass 4461e6f4e58SSimon Glass /* 4471e6f4e58SSimon Glass * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU 4481e6f4e58SSimon Glass * that BIOS has initialized memory and power management 4491e6f4e58SSimon Glass */ 4501e6f4e58SSimon Glass setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 3); 4511e6f4e58SSimon Glass debug("Set BIOS_RESET_CPL\n"); 4521e6f4e58SSimon Glass 4531e6f4e58SSimon Glass /* Configure turbo power limits 1ms after reset complete bit */ 4541e6f4e58SSimon Glass mdelay(1); 4551e6f4e58SSimon Glass 4561e6f4e58SSimon Glass cpu_set_power_limits(28); 4571e6f4e58SSimon Glass } 4581e6f4e58SSimon Glass 4591e6f4e58SSimon Glass static int broadwell_pch_init(struct udevice *dev) 4601e6f4e58SSimon Glass { 4611e6f4e58SSimon Glass int ret; 4621e6f4e58SSimon Glass 4631e6f4e58SSimon Glass /* Enable upper 128 bytes of CMOS */ 4641e6f4e58SSimon Glass setbits_le32(RCB_REG(RC), 1 << 2); 4651e6f4e58SSimon Glass 4661e6f4e58SSimon Glass /* 4671e6f4e58SSimon Glass * TODO: TCO timer halt - this hangs 4681e6f4e58SSimon Glass * setio_16(ACPI_BASE_ADDRESS + TCO1_CNT, TCO_TMR_HLT); 4691e6f4e58SSimon Glass */ 4701e6f4e58SSimon Glass 4711e6f4e58SSimon Glass /* Disable unused device (always) */ 4721e6f4e58SSimon Glass setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS); 4731e6f4e58SSimon Glass 4741e6f4e58SSimon Glass pch_misc_init(dev); 4751e6f4e58SSimon Glass 4761e6f4e58SSimon Glass /* Interrupt configuration */ 4771e6f4e58SSimon Glass pch_enable_ioapic(); 4781e6f4e58SSimon Glass 4791e6f4e58SSimon Glass /* Initialize power management */ 4801e6f4e58SSimon Glass ret = pch_power_options(dev); 4811e6f4e58SSimon Glass if (ret) 4821e6f4e58SSimon Glass return ret; 4831e6f4e58SSimon Glass pch_pm_init(dev); 4841e6f4e58SSimon Glass pch_cg_init(dev); 4851e6f4e58SSimon Glass systemagent_init(); 4861e6f4e58SSimon Glass 4871e6f4e58SSimon Glass return 0; 4881e6f4e58SSimon Glass } 4891e6f4e58SSimon Glass 4901e6f4e58SSimon Glass static int broadwell_pch_probe(struct udevice *dev) 4911e6f4e58SSimon Glass { 4921e6f4e58SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 4931e6f4e58SSimon Glass return broadwell_pch_early_init(dev); 4941e6f4e58SSimon Glass else 4951e6f4e58SSimon Glass return broadwell_pch_init(dev); 4961e6f4e58SSimon Glass } 4971e6f4e58SSimon Glass 4981e6f4e58SSimon Glass static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep) 4991e6f4e58SSimon Glass { 5001e6f4e58SSimon Glass u32 rcba; 5011e6f4e58SSimon Glass 5021e6f4e58SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 5031e6f4e58SSimon Glass /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ 5041e6f4e58SSimon Glass rcba = rcba & 0xffffc000; 5051e6f4e58SSimon Glass *sbasep = rcba + 0x3800; 5061e6f4e58SSimon Glass 5071e6f4e58SSimon Glass return 0; 5081e6f4e58SSimon Glass } 5091e6f4e58SSimon Glass 5101e6f4e58SSimon Glass static int broadwell_set_spi_protect(struct udevice *dev, bool protect) 5111e6f4e58SSimon Glass { 5121e6f4e58SSimon Glass return lpc_set_spi_protect(dev, BIOS_CTRL, protect); 5131e6f4e58SSimon Glass } 5141e6f4e58SSimon Glass 5151e6f4e58SSimon Glass static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep) 5161e6f4e58SSimon Glass { 5171e6f4e58SSimon Glass dm_pci_read_config32(dev, GPIO_BASE, gbasep); 5181e6f4e58SSimon Glass *gbasep &= PCI_BASE_ADDRESS_IO_MASK; 5191e6f4e58SSimon Glass 5201e6f4e58SSimon Glass return 0; 5211e6f4e58SSimon Glass } 5221e6f4e58SSimon Glass 5231e6f4e58SSimon Glass static const struct pch_ops broadwell_pch_ops = { 5241e6f4e58SSimon Glass .get_spi_base = broadwell_pch_get_spi_base, 5251e6f4e58SSimon Glass .set_spi_protect = broadwell_set_spi_protect, 5261e6f4e58SSimon Glass .get_gpio_base = broadwell_get_gpio_base, 5271e6f4e58SSimon Glass }; 5281e6f4e58SSimon Glass 5291e6f4e58SSimon Glass static const struct udevice_id broadwell_pch_ids[] = { 5301e6f4e58SSimon Glass { .compatible = "intel,broadwell-pch" }, 5311e6f4e58SSimon Glass { } 5321e6f4e58SSimon Glass }; 5331e6f4e58SSimon Glass 5341e6f4e58SSimon Glass U_BOOT_DRIVER(broadwell_pch) = { 5351e6f4e58SSimon Glass .name = "broadwell_pch", 5361e6f4e58SSimon Glass .id = UCLASS_PCH, 5371e6f4e58SSimon Glass .of_match = broadwell_pch_ids, 5381e6f4e58SSimon Glass .probe = broadwell_pch_probe, 5391e6f4e58SSimon Glass .ops = &broadwell_pch_ops, 5401e6f4e58SSimon Glass }; 541