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> 1225d5352cSSimon Glass #include <syscon.h> 1325d5352cSSimon Glass #include <asm/cpu.h> 14a5ea3a7dSSimon Glass #include <asm/io.h> 154e7a6acaSSimon Glass #include <asm/lapic.h> 164e7a6acaSSimon Glass #include <asm/pci.h> 174e7a6acaSSimon Glass #include <asm/arch/bd82x6x.h> 184e7a6acaSSimon Glass #include <asm/arch/model_206ax.h> 194e7a6acaSSimon Glass #include <asm/arch/pch.h> 204e7a6acaSSimon Glass #include <asm/arch/sandybridge.h> 214e7a6acaSSimon Glass 22*ec2af6f8SBin Meng #define GPIO_BASE 0x48 23f2b85ab5SSimon Glass #define BIOS_CTRL 0xdc 24f2b85ab5SSimon Glass 25a5ea3a7dSSimon Glass static int pch_revision_id = -1; 26a5ea3a7dSSimon Glass static int pch_type = -1; 27a5ea3a7dSSimon Glass 28a5ea3a7dSSimon Glass /** 29a5ea3a7dSSimon Glass * pch_silicon_revision() - Read silicon revision ID from the PCH 30a5ea3a7dSSimon Glass * 31a5ea3a7dSSimon Glass * @dev: PCH device 32a5ea3a7dSSimon Glass * @return silicon revision ID 33a5ea3a7dSSimon Glass */ 34a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev) 35a5ea3a7dSSimon Glass { 36a5ea3a7dSSimon Glass u8 val; 37a5ea3a7dSSimon Glass 38a5ea3a7dSSimon Glass if (pch_revision_id < 0) { 39a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_REVISION_ID, &val); 40a5ea3a7dSSimon Glass pch_revision_id = val; 41a5ea3a7dSSimon Glass } 42a5ea3a7dSSimon Glass 43a5ea3a7dSSimon Glass return pch_revision_id; 44a5ea3a7dSSimon Glass } 45a5ea3a7dSSimon Glass 46a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev) 47a5ea3a7dSSimon Glass { 48a5ea3a7dSSimon Glass u8 val; 49a5ea3a7dSSimon Glass 50a5ea3a7dSSimon Glass if (pch_type < 0) { 51a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val); 52a5ea3a7dSSimon Glass pch_type = val; 53a5ea3a7dSSimon Glass } 54a5ea3a7dSSimon Glass 55a5ea3a7dSSimon Glass return pch_type; 56a5ea3a7dSSimon Glass } 57a5ea3a7dSSimon Glass 58a5ea3a7dSSimon Glass /** 59a5ea3a7dSSimon Glass * pch_silicon_supported() - Check if a certain revision is supported 60a5ea3a7dSSimon Glass * 61a5ea3a7dSSimon Glass * @dev: PCH device 62a5ea3a7dSSimon Glass * @type: PCH type 63a5ea3a7dSSimon Glass * @rev: Minimum required resion 64a5ea3a7dSSimon Glass * @return 0 if not supported, 1 if supported 65a5ea3a7dSSimon Glass */ 66a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev) 67a5ea3a7dSSimon Glass { 68a5ea3a7dSSimon Glass int cur_type = pch_silicon_type(dev); 69a5ea3a7dSSimon Glass int cur_rev = pch_silicon_revision(dev); 70a5ea3a7dSSimon Glass 71a5ea3a7dSSimon Glass switch (type) { 72a5ea3a7dSSimon Glass case PCH_TYPE_CPT: 73a5ea3a7dSSimon Glass /* CougarPoint minimum revision */ 74a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) 75a5ea3a7dSSimon Glass return 1; 76a5ea3a7dSSimon Glass /* PantherPoint any revision */ 77a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT) 78a5ea3a7dSSimon Glass return 1; 79a5ea3a7dSSimon Glass break; 80a5ea3a7dSSimon Glass 81a5ea3a7dSSimon Glass case PCH_TYPE_PPT: 82a5ea3a7dSSimon Glass /* PantherPoint minimum revision */ 83a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) 84a5ea3a7dSSimon Glass return 1; 85a5ea3a7dSSimon Glass break; 86a5ea3a7dSSimon Glass } 87a5ea3a7dSSimon Glass 88a5ea3a7dSSimon Glass return 0; 89a5ea3a7dSSimon Glass } 90a5ea3a7dSSimon Glass 91a5ea3a7dSSimon Glass #define IOBP_RETRY 1000 92a5ea3a7dSSimon Glass static inline int iobp_poll(void) 93a5ea3a7dSSimon Glass { 94a5ea3a7dSSimon Glass unsigned try = IOBP_RETRY; 95a5ea3a7dSSimon Glass u32 data; 96a5ea3a7dSSimon Glass 97a5ea3a7dSSimon Glass while (try--) { 98a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPS)); 99a5ea3a7dSSimon Glass if ((data & 1) == 0) 100a5ea3a7dSSimon Glass return 1; 101a5ea3a7dSSimon Glass udelay(10); 102a5ea3a7dSSimon Glass } 103a5ea3a7dSSimon Glass 104a5ea3a7dSSimon Glass printf("IOBP timeout\n"); 105a5ea3a7dSSimon Glass return 0; 106a5ea3a7dSSimon Glass } 107a5ea3a7dSSimon Glass 108a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue, 109a5ea3a7dSSimon Glass u32 orvalue) 110a5ea3a7dSSimon Glass { 111a5ea3a7dSSimon Glass u32 data; 112a5ea3a7dSSimon Glass 113a5ea3a7dSSimon Glass /* Set the address */ 114a5ea3a7dSSimon Glass writel(address, RCB_REG(IOBPIRI)); 115a5ea3a7dSSimon Glass 116a5ea3a7dSSimon Glass /* READ OPCODE */ 117a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 118a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 119a5ea3a7dSSimon Glass else 120a5ea3a7dSSimon Glass writel(IOBPS_READ_AX, RCB_REG(IOBPS)); 121a5ea3a7dSSimon Glass if (!iobp_poll()) 122a5ea3a7dSSimon Glass return; 123a5ea3a7dSSimon Glass 124a5ea3a7dSSimon Glass /* Read IOBP data */ 125a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPD)); 126a5ea3a7dSSimon Glass if (!iobp_poll()) 127a5ea3a7dSSimon Glass return; 128a5ea3a7dSSimon Glass 129a5ea3a7dSSimon Glass /* Check for successful transaction */ 130a5ea3a7dSSimon Glass if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { 131a5ea3a7dSSimon Glass printf("IOBP read 0x%08x failed\n", address); 132a5ea3a7dSSimon Glass return; 133a5ea3a7dSSimon Glass } 134a5ea3a7dSSimon Glass 135a5ea3a7dSSimon Glass /* Update the data */ 136a5ea3a7dSSimon Glass data &= andvalue; 137a5ea3a7dSSimon Glass data |= orvalue; 138a5ea3a7dSSimon Glass 139a5ea3a7dSSimon Glass /* WRITE OPCODE */ 140a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 141a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 142a5ea3a7dSSimon Glass else 143a5ea3a7dSSimon Glass writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); 144a5ea3a7dSSimon Glass if (!iobp_poll()) 145a5ea3a7dSSimon Glass return; 146a5ea3a7dSSimon Glass 147a5ea3a7dSSimon Glass /* Write IOBP data */ 148a5ea3a7dSSimon Glass writel(data, RCB_REG(IOBPD)); 149a5ea3a7dSSimon Glass if (!iobp_poll()) 150a5ea3a7dSSimon Glass return; 151a5ea3a7dSSimon Glass } 152a5ea3a7dSSimon Glass 153aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev) 1544e7a6acaSSimon Glass { 15525d5352cSSimon Glass struct udevice *gma_dev; 156effcf067SSimon Glass int ret; 15772cd085aSSimon Glass 1584acc83d4SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 1594acc83d4SSimon Glass return 0; 1604acc83d4SSimon Glass 16101a67908SSimon Glass /* Cause the SATA device to do its init */ 16201a67908SSimon Glass uclass_first_device(UCLASS_DISK, &dev); 16301a67908SSimon Glass 16425d5352cSSimon Glass ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev); 1659bf727fcSSimon Glass if (ret) 1669bf727fcSSimon Glass return ret; 16725d5352cSSimon Glass ret = gma_func0_init(gma_dev); 168effcf067SSimon Glass if (ret) 169effcf067SSimon Glass return ret; 170effcf067SSimon Glass 1714e7a6acaSSimon Glass return 0; 1724e7a6acaSSimon Glass } 1734e7a6acaSSimon Glass 1743e389d8bSBin Meng static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep) 175f2b85ab5SSimon Glass { 176f2b85ab5SSimon Glass u32 rcba; 177f2b85ab5SSimon Glass 178f2b85ab5SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 179f2b85ab5SSimon Glass /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ 180f2b85ab5SSimon Glass rcba = rcba & 0xffffc000; 181f2b85ab5SSimon Glass *sbasep = rcba + 0x3800; 182f2b85ab5SSimon Glass 183f2b85ab5SSimon Glass return 0; 184f2b85ab5SSimon Glass } 185f2b85ab5SSimon Glass 186f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect) 187f2b85ab5SSimon Glass { 188f2b85ab5SSimon Glass uint8_t bios_cntl; 189f2b85ab5SSimon Glass 190f2b85ab5SSimon Glass /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */ 191f2b85ab5SSimon Glass dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl); 192f2b85ab5SSimon Glass if (protect) { 193f2b85ab5SSimon Glass bios_cntl &= ~BIOS_CTRL_BIOSWE; 194f2b85ab5SSimon Glass bios_cntl |= BIT(5); 195f2b85ab5SSimon Glass } else { 196f2b85ab5SSimon Glass bios_cntl |= BIOS_CTRL_BIOSWE; 197f2b85ab5SSimon Glass bios_cntl &= ~BIT(5); 198f2b85ab5SSimon Glass } 199f2b85ab5SSimon Glass dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl); 200f2b85ab5SSimon Glass 201f2b85ab5SSimon Glass return 0; 202f2b85ab5SSimon Glass } 203f2b85ab5SSimon Glass 204*ec2af6f8SBin Meng static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep) 205*ec2af6f8SBin Meng { 206*ec2af6f8SBin Meng u32 base; 207*ec2af6f8SBin Meng 208*ec2af6f8SBin Meng /* 209*ec2af6f8SBin Meng * GPIO_BASE moved to its current offset with ICH6, but prior to 210*ec2af6f8SBin Meng * that it was unused (or undocumented). Check that it looks 211*ec2af6f8SBin Meng * okay: not all ones or zeros. 212*ec2af6f8SBin Meng * 213*ec2af6f8SBin Meng * Note we don't need check bit0 here, because the Tunnel Creek 214*ec2af6f8SBin Meng * GPIO base address register bit0 is reserved (read returns 0), 215*ec2af6f8SBin Meng * while on the Ivybridge the bit0 is used to indicate it is an 216*ec2af6f8SBin Meng * I/O space. 217*ec2af6f8SBin Meng */ 218*ec2af6f8SBin Meng dm_pci_read_config32(dev, GPIO_BASE, &base); 219*ec2af6f8SBin Meng if (base == 0x00000000 || base == 0xffffffff) { 220*ec2af6f8SBin Meng debug("%s: unexpected BASE value\n", __func__); 221*ec2af6f8SBin Meng return -ENODEV; 222*ec2af6f8SBin Meng } 223*ec2af6f8SBin Meng 224*ec2af6f8SBin Meng /* 225*ec2af6f8SBin Meng * Okay, I guess we're looking at the right device. The actual 226*ec2af6f8SBin Meng * GPIO registers are in the PCI device's I/O space, starting 227*ec2af6f8SBin Meng * at the offset that we just read. Bit 0 indicates that it's 228*ec2af6f8SBin Meng * an I/O address, not a memory address, so mask that off. 229*ec2af6f8SBin Meng */ 230*ec2af6f8SBin Meng *gbasep = base & 1 ? base & ~3 : base & ~15; 231*ec2af6f8SBin Meng 232*ec2af6f8SBin Meng return 0; 233*ec2af6f8SBin Meng } 234*ec2af6f8SBin Meng 235f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = { 2363e389d8bSBin Meng .get_spi_base = bd82x6x_pch_get_spi_base, 237f2b85ab5SSimon Glass .set_spi_protect = bd82x6x_set_spi_protect, 238*ec2af6f8SBin Meng .get_gpio_base = bd82x6x_get_gpio_base, 239f2b85ab5SSimon Glass }; 240f2b85ab5SSimon Glass 241aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = { 242aad78d27SSimon Glass { .compatible = "intel,bd82x6x" }, 243aad78d27SSimon Glass { } 244aad78d27SSimon Glass }; 245aad78d27SSimon Glass 246aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = { 247aad78d27SSimon Glass .name = "bd82x6x", 248aad78d27SSimon Glass .id = UCLASS_PCH, 249aad78d27SSimon Glass .of_match = bd82x6x_ids, 250aad78d27SSimon Glass .probe = bd82x6x_probe, 251f2b85ab5SSimon Glass .ops = &bd82x6x_pch_ops, 252aad78d27SSimon Glass }; 253