123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- /*
- * 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;
- }
|