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 22f2b85ab5SSimon Glass #define BIOS_CTRL 0xdc 23f2b85ab5SSimon Glass 24a5ea3a7dSSimon Glass static int pch_revision_id = -1; 25a5ea3a7dSSimon Glass static int pch_type = -1; 26a5ea3a7dSSimon Glass 27a5ea3a7dSSimon Glass /** 28a5ea3a7dSSimon Glass * pch_silicon_revision() - Read silicon revision ID from the PCH 29a5ea3a7dSSimon Glass * 30a5ea3a7dSSimon Glass * @dev: PCH device 31a5ea3a7dSSimon Glass * @return silicon revision ID 32a5ea3a7dSSimon Glass */ 33a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev) 34a5ea3a7dSSimon Glass { 35a5ea3a7dSSimon Glass u8 val; 36a5ea3a7dSSimon Glass 37a5ea3a7dSSimon Glass if (pch_revision_id < 0) { 38a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_REVISION_ID, &val); 39a5ea3a7dSSimon Glass pch_revision_id = val; 40a5ea3a7dSSimon Glass } 41a5ea3a7dSSimon Glass 42a5ea3a7dSSimon Glass return pch_revision_id; 43a5ea3a7dSSimon Glass } 44a5ea3a7dSSimon Glass 45a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev) 46a5ea3a7dSSimon Glass { 47a5ea3a7dSSimon Glass u8 val; 48a5ea3a7dSSimon Glass 49a5ea3a7dSSimon Glass if (pch_type < 0) { 50a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val); 51a5ea3a7dSSimon Glass pch_type = val; 52a5ea3a7dSSimon Glass } 53a5ea3a7dSSimon Glass 54a5ea3a7dSSimon Glass return pch_type; 55a5ea3a7dSSimon Glass } 56a5ea3a7dSSimon Glass 57a5ea3a7dSSimon Glass /** 58a5ea3a7dSSimon Glass * pch_silicon_supported() - Check if a certain revision is supported 59a5ea3a7dSSimon Glass * 60a5ea3a7dSSimon Glass * @dev: PCH device 61a5ea3a7dSSimon Glass * @type: PCH type 62a5ea3a7dSSimon Glass * @rev: Minimum required resion 63a5ea3a7dSSimon Glass * @return 0 if not supported, 1 if supported 64a5ea3a7dSSimon Glass */ 65a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev) 66a5ea3a7dSSimon Glass { 67a5ea3a7dSSimon Glass int cur_type = pch_silicon_type(dev); 68a5ea3a7dSSimon Glass int cur_rev = pch_silicon_revision(dev); 69a5ea3a7dSSimon Glass 70a5ea3a7dSSimon Glass switch (type) { 71a5ea3a7dSSimon Glass case PCH_TYPE_CPT: 72a5ea3a7dSSimon Glass /* CougarPoint minimum revision */ 73a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) 74a5ea3a7dSSimon Glass return 1; 75a5ea3a7dSSimon Glass /* PantherPoint any revision */ 76a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT) 77a5ea3a7dSSimon Glass return 1; 78a5ea3a7dSSimon Glass break; 79a5ea3a7dSSimon Glass 80a5ea3a7dSSimon Glass case PCH_TYPE_PPT: 81a5ea3a7dSSimon Glass /* PantherPoint minimum revision */ 82a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) 83a5ea3a7dSSimon Glass return 1; 84a5ea3a7dSSimon Glass break; 85a5ea3a7dSSimon Glass } 86a5ea3a7dSSimon Glass 87a5ea3a7dSSimon Glass return 0; 88a5ea3a7dSSimon Glass } 89a5ea3a7dSSimon Glass 90a5ea3a7dSSimon Glass #define IOBP_RETRY 1000 91a5ea3a7dSSimon Glass static inline int iobp_poll(void) 92a5ea3a7dSSimon Glass { 93a5ea3a7dSSimon Glass unsigned try = IOBP_RETRY; 94a5ea3a7dSSimon Glass u32 data; 95a5ea3a7dSSimon Glass 96a5ea3a7dSSimon Glass while (try--) { 97a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPS)); 98a5ea3a7dSSimon Glass if ((data & 1) == 0) 99a5ea3a7dSSimon Glass return 1; 100a5ea3a7dSSimon Glass udelay(10); 101a5ea3a7dSSimon Glass } 102a5ea3a7dSSimon Glass 103a5ea3a7dSSimon Glass printf("IOBP timeout\n"); 104a5ea3a7dSSimon Glass return 0; 105a5ea3a7dSSimon Glass } 106a5ea3a7dSSimon Glass 107a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue, 108a5ea3a7dSSimon Glass u32 orvalue) 109a5ea3a7dSSimon Glass { 110a5ea3a7dSSimon Glass u32 data; 111a5ea3a7dSSimon Glass 112a5ea3a7dSSimon Glass /* Set the address */ 113a5ea3a7dSSimon Glass writel(address, RCB_REG(IOBPIRI)); 114a5ea3a7dSSimon Glass 115a5ea3a7dSSimon Glass /* READ OPCODE */ 116a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 117a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 118a5ea3a7dSSimon Glass else 119a5ea3a7dSSimon Glass writel(IOBPS_READ_AX, RCB_REG(IOBPS)); 120a5ea3a7dSSimon Glass if (!iobp_poll()) 121a5ea3a7dSSimon Glass return; 122a5ea3a7dSSimon Glass 123a5ea3a7dSSimon Glass /* Read IOBP data */ 124a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPD)); 125a5ea3a7dSSimon Glass if (!iobp_poll()) 126a5ea3a7dSSimon Glass return; 127a5ea3a7dSSimon Glass 128a5ea3a7dSSimon Glass /* Check for successful transaction */ 129a5ea3a7dSSimon Glass if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { 130a5ea3a7dSSimon Glass printf("IOBP read 0x%08x failed\n", address); 131a5ea3a7dSSimon Glass return; 132a5ea3a7dSSimon Glass } 133a5ea3a7dSSimon Glass 134a5ea3a7dSSimon Glass /* Update the data */ 135a5ea3a7dSSimon Glass data &= andvalue; 136a5ea3a7dSSimon Glass data |= orvalue; 137a5ea3a7dSSimon Glass 138a5ea3a7dSSimon Glass /* WRITE OPCODE */ 139a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 140a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 141a5ea3a7dSSimon Glass else 142a5ea3a7dSSimon Glass writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); 143a5ea3a7dSSimon Glass if (!iobp_poll()) 144a5ea3a7dSSimon Glass return; 145a5ea3a7dSSimon Glass 146a5ea3a7dSSimon Glass /* Write IOBP data */ 147a5ea3a7dSSimon Glass writel(data, RCB_REG(IOBPD)); 148a5ea3a7dSSimon Glass if (!iobp_poll()) 149a5ea3a7dSSimon Glass return; 150a5ea3a7dSSimon Glass } 151a5ea3a7dSSimon Glass 152aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev) 1534e7a6acaSSimon Glass { 15425d5352cSSimon Glass struct udevice *gma_dev; 155effcf067SSimon Glass int ret; 15672cd085aSSimon Glass 1574acc83d4SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 1584acc83d4SSimon Glass return 0; 1594acc83d4SSimon Glass 16001a67908SSimon Glass /* Cause the SATA device to do its init */ 16101a67908SSimon Glass uclass_first_device(UCLASS_DISK, &dev); 16201a67908SSimon Glass 16325d5352cSSimon Glass ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev); 1649bf727fcSSimon Glass if (ret) 1659bf727fcSSimon Glass return ret; 16625d5352cSSimon Glass ret = gma_func0_init(gma_dev); 167effcf067SSimon Glass if (ret) 168effcf067SSimon Glass return ret; 169effcf067SSimon Glass 1704e7a6acaSSimon Glass return 0; 1714e7a6acaSSimon Glass } 1724e7a6acaSSimon Glass 173*3e389d8bSBin Meng static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep) 174f2b85ab5SSimon Glass { 175f2b85ab5SSimon Glass u32 rcba; 176f2b85ab5SSimon Glass 177f2b85ab5SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 178f2b85ab5SSimon Glass /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ 179f2b85ab5SSimon Glass rcba = rcba & 0xffffc000; 180f2b85ab5SSimon Glass *sbasep = rcba + 0x3800; 181f2b85ab5SSimon Glass 182f2b85ab5SSimon Glass return 0; 183f2b85ab5SSimon Glass } 184f2b85ab5SSimon Glass 185f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect) 186f2b85ab5SSimon Glass { 187f2b85ab5SSimon Glass uint8_t bios_cntl; 188f2b85ab5SSimon Glass 189f2b85ab5SSimon Glass /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */ 190f2b85ab5SSimon Glass dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl); 191f2b85ab5SSimon Glass if (protect) { 192f2b85ab5SSimon Glass bios_cntl &= ~BIOS_CTRL_BIOSWE; 193f2b85ab5SSimon Glass bios_cntl |= BIT(5); 194f2b85ab5SSimon Glass } else { 195f2b85ab5SSimon Glass bios_cntl |= BIOS_CTRL_BIOSWE; 196f2b85ab5SSimon Glass bios_cntl &= ~BIT(5); 197f2b85ab5SSimon Glass } 198f2b85ab5SSimon Glass dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl); 199f2b85ab5SSimon Glass 200f2b85ab5SSimon Glass return 0; 201f2b85ab5SSimon Glass } 202f2b85ab5SSimon Glass 203f2b85ab5SSimon Glass static const struct pch_ops bd82x6x_pch_ops = { 204*3e389d8bSBin Meng .get_spi_base = bd82x6x_pch_get_spi_base, 205f2b85ab5SSimon Glass .set_spi_protect = bd82x6x_set_spi_protect, 206f2b85ab5SSimon Glass }; 207f2b85ab5SSimon Glass 208aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = { 209aad78d27SSimon Glass { .compatible = "intel,bd82x6x" }, 210aad78d27SSimon Glass { } 211aad78d27SSimon Glass }; 212aad78d27SSimon Glass 213aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = { 214aad78d27SSimon Glass .name = "bd82x6x", 215aad78d27SSimon Glass .id = UCLASS_PCH, 216aad78d27SSimon Glass .of_match = bd82x6x_ids, 217aad78d27SSimon Glass .probe = bd82x6x_probe, 218f2b85ab5SSimon Glass .ops = &bd82x6x_pch_ops, 219aad78d27SSimon Glass }; 220