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