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