14e7a6acaSSimon Glass /* 24e7a6acaSSimon Glass * Copyright (C) 2014 Google, Inc 34e7a6acaSSimon Glass * 44e7a6acaSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 54e7a6acaSSimon Glass */ 64e7a6acaSSimon Glass #include <common.h> 7aad78d27SSimon Glass #include <dm.h> 84e7a6acaSSimon Glass #include <errno.h> 94e7a6acaSSimon Glass #include <fdtdec.h> 104e7a6acaSSimon Glass #include <malloc.h> 11f2b85ab5SSimon Glass #include <pch.h> 12*a5ea3a7dSSimon Glass #include <asm/io.h> 134e7a6acaSSimon Glass #include <asm/lapic.h> 144e7a6acaSSimon Glass #include <asm/pci.h> 154e7a6acaSSimon Glass #include <asm/arch/bd82x6x.h> 164e7a6acaSSimon Glass #include <asm/arch/model_206ax.h> 174e7a6acaSSimon Glass #include <asm/arch/pch.h> 184e7a6acaSSimon Glass #include <asm/arch/sandybridge.h> 194e7a6acaSSimon Glass 20f2b85ab5SSimon Glass #define BIOS_CTRL 0xdc 21f2b85ab5SSimon Glass 22*a5ea3a7dSSimon Glass static int pch_revision_id = -1; 23*a5ea3a7dSSimon Glass static int pch_type = -1; 24*a5ea3a7dSSimon Glass 25*a5ea3a7dSSimon Glass /** 26*a5ea3a7dSSimon Glass * pch_silicon_revision() - Read silicon revision ID from the PCH 27*a5ea3a7dSSimon Glass * 28*a5ea3a7dSSimon Glass * @dev: PCH device 29*a5ea3a7dSSimon Glass * @return silicon revision ID 30*a5ea3a7dSSimon Glass */ 31*a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev) 32*a5ea3a7dSSimon Glass { 33*a5ea3a7dSSimon Glass u8 val; 34*a5ea3a7dSSimon Glass 35*a5ea3a7dSSimon Glass if (pch_revision_id < 0) { 36*a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_REVISION_ID, &val); 37*a5ea3a7dSSimon Glass pch_revision_id = val; 38*a5ea3a7dSSimon Glass } 39*a5ea3a7dSSimon Glass 40*a5ea3a7dSSimon Glass return pch_revision_id; 41*a5ea3a7dSSimon Glass } 42*a5ea3a7dSSimon Glass 43*a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev) 44*a5ea3a7dSSimon Glass { 45*a5ea3a7dSSimon Glass u8 val; 46*a5ea3a7dSSimon Glass 47*a5ea3a7dSSimon Glass if (pch_type < 0) { 48*a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val); 49*a5ea3a7dSSimon Glass pch_type = val; 50*a5ea3a7dSSimon Glass } 51*a5ea3a7dSSimon Glass 52*a5ea3a7dSSimon Glass return pch_type; 53*a5ea3a7dSSimon Glass } 54*a5ea3a7dSSimon Glass 55*a5ea3a7dSSimon Glass /** 56*a5ea3a7dSSimon Glass * pch_silicon_supported() - Check if a certain revision is supported 57*a5ea3a7dSSimon Glass * 58*a5ea3a7dSSimon Glass * @dev: PCH device 59*a5ea3a7dSSimon Glass * @type: PCH type 60*a5ea3a7dSSimon Glass * @rev: Minimum required resion 61*a5ea3a7dSSimon Glass * @return 0 if not supported, 1 if supported 62*a5ea3a7dSSimon Glass */ 63*a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev) 64*a5ea3a7dSSimon Glass { 65*a5ea3a7dSSimon Glass int cur_type = pch_silicon_type(dev); 66*a5ea3a7dSSimon Glass int cur_rev = pch_silicon_revision(dev); 67*a5ea3a7dSSimon Glass 68*a5ea3a7dSSimon Glass switch (type) { 69*a5ea3a7dSSimon Glass case PCH_TYPE_CPT: 70*a5ea3a7dSSimon Glass /* CougarPoint minimum revision */ 71*a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) 72*a5ea3a7dSSimon Glass return 1; 73*a5ea3a7dSSimon Glass /* PantherPoint any revision */ 74*a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT) 75*a5ea3a7dSSimon Glass return 1; 76*a5ea3a7dSSimon Glass break; 77*a5ea3a7dSSimon Glass 78*a5ea3a7dSSimon Glass case PCH_TYPE_PPT: 79*a5ea3a7dSSimon Glass /* PantherPoint minimum revision */ 80*a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) 81*a5ea3a7dSSimon Glass return 1; 82*a5ea3a7dSSimon Glass break; 83*a5ea3a7dSSimon Glass } 84*a5ea3a7dSSimon Glass 85*a5ea3a7dSSimon Glass return 0; 86*a5ea3a7dSSimon Glass } 87*a5ea3a7dSSimon Glass 88*a5ea3a7dSSimon Glass #define IOBP_RETRY 1000 89*a5ea3a7dSSimon Glass static inline int iobp_poll(void) 90*a5ea3a7dSSimon Glass { 91*a5ea3a7dSSimon Glass unsigned try = IOBP_RETRY; 92*a5ea3a7dSSimon Glass u32 data; 93*a5ea3a7dSSimon Glass 94*a5ea3a7dSSimon Glass while (try--) { 95*a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPS)); 96*a5ea3a7dSSimon Glass if ((data & 1) == 0) 97*a5ea3a7dSSimon Glass return 1; 98*a5ea3a7dSSimon Glass udelay(10); 99*a5ea3a7dSSimon Glass } 100*a5ea3a7dSSimon Glass 101*a5ea3a7dSSimon Glass printf("IOBP timeout\n"); 102*a5ea3a7dSSimon Glass return 0; 103*a5ea3a7dSSimon Glass } 104*a5ea3a7dSSimon Glass 105*a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue, 106*a5ea3a7dSSimon Glass u32 orvalue) 107*a5ea3a7dSSimon Glass { 108*a5ea3a7dSSimon Glass u32 data; 109*a5ea3a7dSSimon Glass 110*a5ea3a7dSSimon Glass /* Set the address */ 111*a5ea3a7dSSimon Glass writel(address, RCB_REG(IOBPIRI)); 112*a5ea3a7dSSimon Glass 113*a5ea3a7dSSimon Glass /* READ OPCODE */ 114*a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 115*a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 116*a5ea3a7dSSimon Glass else 117*a5ea3a7dSSimon Glass writel(IOBPS_READ_AX, RCB_REG(IOBPS)); 118*a5ea3a7dSSimon Glass if (!iobp_poll()) 119*a5ea3a7dSSimon Glass return; 120*a5ea3a7dSSimon Glass 121*a5ea3a7dSSimon Glass /* Read IOBP data */ 122*a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPD)); 123*a5ea3a7dSSimon Glass if (!iobp_poll()) 124*a5ea3a7dSSimon Glass return; 125*a5ea3a7dSSimon Glass 126*a5ea3a7dSSimon Glass /* Check for successful transaction */ 127*a5ea3a7dSSimon Glass if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { 128*a5ea3a7dSSimon Glass printf("IOBP read 0x%08x failed\n", address); 129*a5ea3a7dSSimon Glass return; 130*a5ea3a7dSSimon Glass } 131*a5ea3a7dSSimon Glass 132*a5ea3a7dSSimon Glass /* Update the data */ 133*a5ea3a7dSSimon Glass data &= andvalue; 134*a5ea3a7dSSimon Glass data |= orvalue; 135*a5ea3a7dSSimon Glass 136*a5ea3a7dSSimon Glass /* WRITE OPCODE */ 137*a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 138*a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 139*a5ea3a7dSSimon Glass else 140*a5ea3a7dSSimon Glass writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); 141*a5ea3a7dSSimon Glass if (!iobp_poll()) 142*a5ea3a7dSSimon Glass return; 143*a5ea3a7dSSimon Glass 144*a5ea3a7dSSimon Glass /* Write IOBP data */ 145*a5ea3a7dSSimon Glass writel(data, RCB_REG(IOBPD)); 146*a5ea3a7dSSimon Glass if (!iobp_poll()) 147*a5ea3a7dSSimon Glass return; 148*a5ea3a7dSSimon Glass } 149*a5ea3a7dSSimon Glass 150aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev) 1514e7a6acaSSimon Glass { 1523ac83935SSimon Glass const void *blob = gd->fdt_blob; 15301a67908SSimon Glass int gma_node; 154effcf067SSimon Glass int ret; 15572cd085aSSimon Glass 1564acc83d4SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 1574acc83d4SSimon Glass return 0; 1584acc83d4SSimon Glass 15901a67908SSimon Glass /* Cause the SATA device to do its init */ 16001a67908SSimon Glass uclass_first_device(UCLASS_DISK, &dev); 16101a67908SSimon Glass 1629baeca4bSSimon Glass bd82x6x_usb_ehci_init(PCH_EHCI1_DEV); 1639baeca4bSSimon Glass bd82x6x_usb_ehci_init(PCH_EHCI2_DEV); 16472cd085aSSimon Glass 165effcf067SSimon Glass gma_node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_GMA); 166effcf067SSimon Glass if (gma_node < 0) { 167effcf067SSimon Glass debug("%s: Cannot find GMA node\n", __func__); 168effcf067SSimon Glass return -EINVAL; 169effcf067SSimon Glass } 1709bf727fcSSimon Glass ret = dm_pci_bus_find_bdf(PCH_VIDEO_DEV, &dev); 1719bf727fcSSimon Glass if (ret) 1729bf727fcSSimon Glass return ret; 1739bf727fcSSimon Glass ret = gma_func0_init(dev, blob, gma_node); 174effcf067SSimon Glass if (ret) 175effcf067SSimon Glass return ret; 176effcf067SSimon Glass 1774e7a6acaSSimon Glass return 0; 1784e7a6acaSSimon Glass } 1794e7a6acaSSimon Glass 180f2b85ab5SSimon Glass static int bd82x6x_pch_get_sbase(struct udevice *dev, ulong *sbasep) 181f2b85ab5SSimon Glass { 182f2b85ab5SSimon Glass u32 rcba; 183f2b85ab5SSimon Glass 184f2b85ab5SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 185f2b85ab5SSimon Glass /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ 186f2b85ab5SSimon Glass rcba = rcba & 0xffffc000; 187f2b85ab5SSimon Glass *sbasep = rcba + 0x3800; 188f2b85ab5SSimon Glass 189f2b85ab5SSimon Glass return 0; 190f2b85ab5SSimon Glass } 191f2b85ab5SSimon Glass 192f2b85ab5SSimon Glass static enum pch_version bd82x6x_pch_get_version(struct udevice *dev) 193f2b85ab5SSimon Glass { 194f2b85ab5SSimon Glass return PCHV_9; 195f2b85ab5SSimon Glass } 196f2b85ab5SSimon Glass 197f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect) 198f2b85ab5SSimon Glass { 199f2b85ab5SSimon Glass uint8_t bios_cntl; 200f2b85ab5SSimon Glass 201f2b85ab5SSimon Glass /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */ 202f2b85ab5SSimon Glass dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl); 203f2b85ab5SSimon Glass if (protect) { 204f2b85ab5SSimon Glass bios_cntl &= ~BIOS_CTRL_BIOSWE; 205f2b85ab5SSimon Glass bios_cntl |= BIT(5); 206f2b85ab5SSimon Glass } else { 207f2b85ab5SSimon Glass bios_cntl |= BIOS_CTRL_BIOSWE; 208f2b85ab5SSimon Glass bios_cntl &= ~BIT(5); 209f2b85ab5SSimon Glass } 210f2b85ab5SSimon Glass dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl); 211f2b85ab5SSimon Glass 212f2b85ab5SSimon Glass return 0; 213f2b85ab5SSimon Glass } 214f2b85ab5SSimon Glass 215f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = { 216f2b85ab5SSimon Glass .get_sbase = bd82x6x_pch_get_sbase, 217f2b85ab5SSimon Glass .get_version = bd82x6x_pch_get_version, 218f2b85ab5SSimon Glass .set_spi_protect = bd82x6x_set_spi_protect, 219f2b85ab5SSimon Glass }; 220f2b85ab5SSimon Glass 221aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = { 222aad78d27SSimon Glass { .compatible = "intel,bd82x6x" }, 223aad78d27SSimon Glass { } 224aad78d27SSimon Glass }; 225aad78d27SSimon Glass 226aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = { 227aad78d27SSimon Glass .name = "bd82x6x", 228aad78d27SSimon Glass .id = UCLASS_PCH, 229aad78d27SSimon Glass .of_match = bd82x6x_ids, 230aad78d27SSimon Glass .probe = bd82x6x_probe, 231f2b85ab5SSimon Glass .ops = &bd82x6x_pch_ops, 232aad78d27SSimon Glass }; 233