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