/* * Copyright (c) 2016 Google, Inc * * Modified from coreboot * * SPDX-License-Identifier: GPL-2.0 */ #include <common.h> #include <errno.h> #include <asm/intel_regs.h> #include <asm/io.h> #include <asm/arch/pch.h> #define IOBP_RETRY 1000 /* IO Buffer Programming */ #define IOBPIRI 0x2330 #define IOBPD 0x2334 #define IOBPS 0x2338 #define IOBPS_READY 0x0001 #define IOBPS_TX_MASK 0x0006 #define IOBPS_MASK 0xff00 #define IOBPS_READ 0x0600 #define IOBPS_WRITE 0x0700 #define IOBPU 0x233a #define IOBPU_MAGIC 0xf000 #define IOBP_PCICFG_READ 0x0400 #define IOBP_PCICFG_WRITE 0x0500 static inline int iobp_poll(void) { unsigned try; for (try = IOBP_RETRY; try > 0; try--) { u16 status = readw(RCB_REG(IOBPS)); if ((status & IOBPS_READY) == 0) return 1; udelay(10); } printf("IOBP: timeout waiting for transaction to complete\n"); return 0; } int pch_iobp_trans_start(u32 address, int op) { if (!iobp_poll()) return 0; /* Set the address */ writel(address, RCB_REG(IOBPIRI)); /* READ OPCODE */ clrsetbits_le16(RCB_REG(IOBPS), IOBPS_MASK, op); return 1; } int pch_iobp_trans_finish(void) { u16 status; /* Undocumented magic */ writew(IOBPU_MAGIC, RCB_REG(IOBPU)); /* Set ready bit */ setbits_le16(RCB_REG(IOBPS), IOBPS_READY); if (!iobp_poll()) return 1; /* Check for successful transaction */ status = readw(RCB_REG(IOBPS)); if (status & IOBPS_TX_MASK) return 1; return 0; } u32 pch_iobp_read(u32 address) { if (!pch_iobp_trans_start(address, IOBPS_READ)) return 0; if (pch_iobp_trans_finish()) { printf("IOBP: read 0x%08x failed\n", address); return 0; } /* Read IOBP data */ return readl(RCB_REG(IOBPD)); } int pch_iobp_write(u32 address, u32 data) { if (!pch_iobp_trans_start(address, IOBPS_WRITE)) return -EIO; writel(data, RCB_REG(IOBPD)); if (pch_iobp_trans_finish()) { printf("IOBP: write 0x%08x failed\n", address); return -EIO; } return 0; } int pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) { u32 data = pch_iobp_read(address); /* Update the data */ data &= andvalue; data |= orvalue; return pch_iobp_write(address, data); } int pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp) { if (!data || !resp) return 0; *resp = -1; if (!iobp_poll()) return -EIO; writel(addr, RCB_REG(IOBPIRI)); clrsetbits_le16(RCB_REG(IOBPS), 0xff00, op_code); writew(IOBPU_MAGIC | route_id, RCB_REG(IOBPU)); writel(*data, RCB_REG(IOBPD)); /* Set IOBPS[0] to trigger IOBP transaction*/ setbits_le16(RCB_REG(IOBPS), 1); if (!iobp_poll()) return -EIO; *resp = (readw(RCB_REG(IOBPS)) & IOBPS_TX_MASK) >> 1; *data = readl(RCB_REG(IOBPD)); return 0; }