183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 24e7a6acaSSimon Glass /* 34e7a6acaSSimon Glass * Copyright (C) 2014 Google, Inc 44e7a6acaSSimon Glass */ 54e7a6acaSSimon Glass #include <common.h> 6aad78d27SSimon Glass #include <dm.h> 74e7a6acaSSimon Glass #include <errno.h> 84e7a6acaSSimon Glass #include <fdtdec.h> 94e7a6acaSSimon Glass #include <malloc.h> 10f2b85ab5SSimon Glass #include <pch.h> 1125d5352cSSimon Glass #include <asm/cpu.h> 12bb096b9fSSimon Glass #include <asm/intel_regs.h> 13a5ea3a7dSSimon Glass #include <asm/io.h> 144e7a6acaSSimon Glass #include <asm/lapic.h> 158c30b571SSimon Glass #include <asm/lpc_common.h> 164e7a6acaSSimon Glass #include <asm/pci.h> 174e7a6acaSSimon Glass #include <asm/arch/model_206ax.h> 184e7a6acaSSimon Glass #include <asm/arch/pch.h> 194e7a6acaSSimon Glass #include <asm/arch/sandybridge.h> 204e7a6acaSSimon Glass 2105af050eSSimon Glass DECLARE_GLOBAL_DATA_PTR; 2205af050eSSimon Glass 23ec2af6f8SBin Meng #define GPIO_BASE 0x48 24f2b85ab5SSimon Glass #define BIOS_CTRL 0xdc 25f2b85ab5SSimon Glass 26*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG 0x2030 27*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG_HDA BIT(31) 28*67b0cda7SSimon Glass #define RCBA_AUDIO_CONFIG_MASK 0xfe 29*67b0cda7SSimon Glass 3087077e97SBin Meng #ifndef CONFIG_HAVE_FSP 31a5ea3a7dSSimon Glass static int pch_revision_id = -1; 32a5ea3a7dSSimon Glass static int pch_type = -1; 33a5ea3a7dSSimon Glass 34a5ea3a7dSSimon Glass /** 35a5ea3a7dSSimon Glass * pch_silicon_revision() - Read silicon revision ID from the PCH 36a5ea3a7dSSimon Glass * 37a5ea3a7dSSimon Glass * @dev: PCH device 38a5ea3a7dSSimon Glass * @return silicon revision ID 39a5ea3a7dSSimon Glass */ 40a5ea3a7dSSimon Glass static int pch_silicon_revision(struct udevice *dev) 41a5ea3a7dSSimon Glass { 42a5ea3a7dSSimon Glass u8 val; 43a5ea3a7dSSimon Glass 44a5ea3a7dSSimon Glass if (pch_revision_id < 0) { 45a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_REVISION_ID, &val); 46a5ea3a7dSSimon Glass pch_revision_id = val; 47a5ea3a7dSSimon Glass } 48a5ea3a7dSSimon Glass 49a5ea3a7dSSimon Glass return pch_revision_id; 50a5ea3a7dSSimon Glass } 51a5ea3a7dSSimon Glass 52a5ea3a7dSSimon Glass int pch_silicon_type(struct udevice *dev) 53a5ea3a7dSSimon Glass { 54a5ea3a7dSSimon Glass u8 val; 55a5ea3a7dSSimon Glass 56a5ea3a7dSSimon Glass if (pch_type < 0) { 57a5ea3a7dSSimon Glass dm_pci_read_config8(dev, PCI_DEVICE_ID + 1, &val); 58a5ea3a7dSSimon Glass pch_type = val; 59a5ea3a7dSSimon Glass } 60a5ea3a7dSSimon Glass 61a5ea3a7dSSimon Glass return pch_type; 62a5ea3a7dSSimon Glass } 63a5ea3a7dSSimon Glass 64a5ea3a7dSSimon Glass /** 65a5ea3a7dSSimon Glass * pch_silicon_supported() - Check if a certain revision is supported 66a5ea3a7dSSimon Glass * 67a5ea3a7dSSimon Glass * @dev: PCH device 68a5ea3a7dSSimon Glass * @type: PCH type 69a5ea3a7dSSimon Glass * @rev: Minimum required resion 70a5ea3a7dSSimon Glass * @return 0 if not supported, 1 if supported 71a5ea3a7dSSimon Glass */ 72a5ea3a7dSSimon Glass static int pch_silicon_supported(struct udevice *dev, int type, int rev) 73a5ea3a7dSSimon Glass { 74a5ea3a7dSSimon Glass int cur_type = pch_silicon_type(dev); 75a5ea3a7dSSimon Glass int cur_rev = pch_silicon_revision(dev); 76a5ea3a7dSSimon Glass 77a5ea3a7dSSimon Glass switch (type) { 78a5ea3a7dSSimon Glass case PCH_TYPE_CPT: 79a5ea3a7dSSimon Glass /* CougarPoint minimum revision */ 80a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) 81a5ea3a7dSSimon Glass return 1; 82a5ea3a7dSSimon Glass /* PantherPoint any revision */ 83a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT) 84a5ea3a7dSSimon Glass return 1; 85a5ea3a7dSSimon Glass break; 86a5ea3a7dSSimon Glass 87a5ea3a7dSSimon Glass case PCH_TYPE_PPT: 88a5ea3a7dSSimon Glass /* PantherPoint minimum revision */ 89a5ea3a7dSSimon Glass if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) 90a5ea3a7dSSimon Glass return 1; 91a5ea3a7dSSimon Glass break; 92a5ea3a7dSSimon Glass } 93a5ea3a7dSSimon Glass 94a5ea3a7dSSimon Glass return 0; 95a5ea3a7dSSimon Glass } 96a5ea3a7dSSimon Glass 97a5ea3a7dSSimon Glass #define IOBP_RETRY 1000 98a5ea3a7dSSimon Glass static inline int iobp_poll(void) 99a5ea3a7dSSimon Glass { 100a5ea3a7dSSimon Glass unsigned try = IOBP_RETRY; 101a5ea3a7dSSimon Glass u32 data; 102a5ea3a7dSSimon Glass 103a5ea3a7dSSimon Glass while (try--) { 104a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPS)); 105a5ea3a7dSSimon Glass if ((data & 1) == 0) 106a5ea3a7dSSimon Glass return 1; 107a5ea3a7dSSimon Glass udelay(10); 108a5ea3a7dSSimon Glass } 109a5ea3a7dSSimon Glass 110a5ea3a7dSSimon Glass printf("IOBP timeout\n"); 111a5ea3a7dSSimon Glass return 0; 112a5ea3a7dSSimon Glass } 113a5ea3a7dSSimon Glass 114a5ea3a7dSSimon Glass void pch_iobp_update(struct udevice *dev, u32 address, u32 andvalue, 115a5ea3a7dSSimon Glass u32 orvalue) 116a5ea3a7dSSimon Glass { 117a5ea3a7dSSimon Glass u32 data; 118a5ea3a7dSSimon Glass 119a5ea3a7dSSimon Glass /* Set the address */ 120a5ea3a7dSSimon Glass writel(address, RCB_REG(IOBPIRI)); 121a5ea3a7dSSimon Glass 122a5ea3a7dSSimon Glass /* READ OPCODE */ 123a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 124a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 125a5ea3a7dSSimon Glass else 126a5ea3a7dSSimon Glass writel(IOBPS_READ_AX, RCB_REG(IOBPS)); 127a5ea3a7dSSimon Glass if (!iobp_poll()) 128a5ea3a7dSSimon Glass return; 129a5ea3a7dSSimon Glass 130a5ea3a7dSSimon Glass /* Read IOBP data */ 131a5ea3a7dSSimon Glass data = readl(RCB_REG(IOBPD)); 132a5ea3a7dSSimon Glass if (!iobp_poll()) 133a5ea3a7dSSimon Glass return; 134a5ea3a7dSSimon Glass 135a5ea3a7dSSimon Glass /* Check for successful transaction */ 136a5ea3a7dSSimon Glass if ((readl(RCB_REG(IOBPS)) & 0x6) != 0) { 137a5ea3a7dSSimon Glass printf("IOBP read 0x%08x failed\n", address); 138a5ea3a7dSSimon Glass return; 139a5ea3a7dSSimon Glass } 140a5ea3a7dSSimon Glass 141a5ea3a7dSSimon Glass /* Update the data */ 142a5ea3a7dSSimon Glass data &= andvalue; 143a5ea3a7dSSimon Glass data |= orvalue; 144a5ea3a7dSSimon Glass 145a5ea3a7dSSimon Glass /* WRITE OPCODE */ 146a5ea3a7dSSimon Glass if (pch_silicon_supported(dev, PCH_TYPE_CPT, PCH_STEP_B0)) 147a5ea3a7dSSimon Glass writel(IOBPS_RW_BX, RCB_REG(IOBPS)); 148a5ea3a7dSSimon Glass else 149a5ea3a7dSSimon Glass writel(IOBPS_WRITE_AX, RCB_REG(IOBPS)); 150a5ea3a7dSSimon Glass if (!iobp_poll()) 151a5ea3a7dSSimon Glass return; 152a5ea3a7dSSimon Glass 153a5ea3a7dSSimon Glass /* Write IOBP data */ 154a5ea3a7dSSimon Glass writel(data, RCB_REG(IOBPD)); 155a5ea3a7dSSimon Glass if (!iobp_poll()) 156a5ea3a7dSSimon Glass return; 157a5ea3a7dSSimon Glass } 158a5ea3a7dSSimon Glass 159aad78d27SSimon Glass static int bd82x6x_probe(struct udevice *dev) 1604e7a6acaSSimon 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 */ 165a219639dSSimon Glass uclass_first_device(UCLASS_AHCI, &dev); 16601a67908SSimon Glass 1674e7a6acaSSimon Glass return 0; 1684e7a6acaSSimon Glass } 16987077e97SBin Meng #endif /* CONFIG_HAVE_FSP */ 1704e7a6acaSSimon Glass 1713e389d8bSBin Meng static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep) 172f2b85ab5SSimon Glass { 173f2b85ab5SSimon Glass u32 rcba; 174f2b85ab5SSimon Glass 175f2b85ab5SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 176f2b85ab5SSimon Glass /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable */ 177f2b85ab5SSimon Glass rcba = rcba & 0xffffc000; 178f2b85ab5SSimon Glass *sbasep = rcba + 0x3800; 179f2b85ab5SSimon Glass 180f2b85ab5SSimon Glass return 0; 181f2b85ab5SSimon Glass } 182f2b85ab5SSimon Glass 183f2b85ab5SSimon Glass static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect) 184f2b85ab5SSimon Glass { 1858c30b571SSimon Glass return lpc_set_spi_protect(dev, BIOS_CTRL, protect); 186f2b85ab5SSimon Glass } 187f2b85ab5SSimon Glass 188ec2af6f8SBin Meng static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep) 189ec2af6f8SBin Meng { 190ec2af6f8SBin Meng u32 base; 191ec2af6f8SBin Meng 192ec2af6f8SBin Meng /* 193ec2af6f8SBin Meng * GPIO_BASE moved to its current offset with ICH6, but prior to 194ec2af6f8SBin Meng * that it was unused (or undocumented). Check that it looks 195ec2af6f8SBin Meng * okay: not all ones or zeros. 196ec2af6f8SBin Meng * 197ec2af6f8SBin Meng * Note we don't need check bit0 here, because the Tunnel Creek 198ec2af6f8SBin Meng * GPIO base address register bit0 is reserved (read returns 0), 199ec2af6f8SBin Meng * while on the Ivybridge the bit0 is used to indicate it is an 200ec2af6f8SBin Meng * I/O space. 201ec2af6f8SBin Meng */ 202ec2af6f8SBin Meng dm_pci_read_config32(dev, GPIO_BASE, &base); 203ec2af6f8SBin Meng if (base == 0x00000000 || base == 0xffffffff) { 204ec2af6f8SBin Meng debug("%s: unexpected BASE value\n", __func__); 205ec2af6f8SBin Meng return -ENODEV; 206ec2af6f8SBin Meng } 207ec2af6f8SBin Meng 208ec2af6f8SBin Meng /* 209ec2af6f8SBin Meng * Okay, I guess we're looking at the right device. The actual 210ec2af6f8SBin Meng * GPIO registers are in the PCI device's I/O space, starting 211ec2af6f8SBin Meng * at the offset that we just read. Bit 0 indicates that it's 212ec2af6f8SBin Meng * an I/O address, not a memory address, so mask that off. 213ec2af6f8SBin Meng */ 214ec2af6f8SBin Meng *gbasep = base & 1 ? base & ~3 : base & ~15; 215ec2af6f8SBin Meng 216ec2af6f8SBin Meng return 0; 217ec2af6f8SBin Meng } 218ec2af6f8SBin Meng 219*67b0cda7SSimon Glass static int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data, 220*67b0cda7SSimon Glass int size) 221*67b0cda7SSimon Glass { 222*67b0cda7SSimon Glass u32 rcba, val; 223*67b0cda7SSimon Glass 224*67b0cda7SSimon Glass switch (req) { 225*67b0cda7SSimon Glass case PCH_REQ_HDA_CONFIG: 226*67b0cda7SSimon Glass dm_pci_read_config32(dev, PCH_RCBA, &rcba); 227*67b0cda7SSimon Glass val = readl(rcba + RCBA_AUDIO_CONFIG); 228*67b0cda7SSimon Glass if (!(val & RCBA_AUDIO_CONFIG_HDA)) 229*67b0cda7SSimon Glass return -ENOENT; 230*67b0cda7SSimon Glass 231*67b0cda7SSimon Glass return val & RCBA_AUDIO_CONFIG_MASK; 232*67b0cda7SSimon Glass default: 233*67b0cda7SSimon Glass return -ENOSYS; 234*67b0cda7SSimon Glass } 235*67b0cda7SSimon Glass } 236*67b0cda7SSimon Glass 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, 241*67b0cda7SSimon Glass .ioctl = bd82x6x_ioctl, 242f2b85ab5SSimon Glass }; 243f2b85ab5SSimon Glass 244aad78d27SSimon Glass static const struct udevice_id bd82x6x_ids[] = { 245aad78d27SSimon Glass { .compatible = "intel,bd82x6x" }, 246aad78d27SSimon Glass { } 247aad78d27SSimon Glass }; 248aad78d27SSimon Glass 249aad78d27SSimon Glass U_BOOT_DRIVER(bd82x6x_drv) = { 250aad78d27SSimon Glass .name = "bd82x6x", 251aad78d27SSimon Glass .id = UCLASS_PCH, 252aad78d27SSimon Glass .of_match = bd82x6x_ids, 25387077e97SBin Meng #ifndef CONFIG_HAVE_FSP 254aad78d27SSimon Glass .probe = bd82x6x_probe, 25587077e97SBin Meng #endif 256f2b85ab5SSimon Glass .ops = &bd82x6x_pch_ops, 257aad78d27SSimon Glass }; 258