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