2 * Copyright (c) 2016 Google, Inc
4 * Modified from coreboot
6 * SPDX-License-Identifier: GPL-2.0
11 #include <asm/intel_regs.h>
13 #include <asm/arch/pch.h>
15 #define IOBP_RETRY 1000
17 /* IO Buffer Programming */
18 #define IOBPIRI 0x2330
21 #define IOBPS_READY 0x0001
22 #define IOBPS_TX_MASK 0x0006
23 #define IOBPS_MASK 0xff00
24 #define IOBPS_READ 0x0600
25 #define IOBPS_WRITE 0x0700
27 #define IOBPU_MAGIC 0xf000
28 #define IOBP_PCICFG_READ 0x0400
29 #define IOBP_PCICFG_WRITE 0x0500
31 static inline int iobp_poll(void)
35 for (try = IOBP_RETRY; try > 0; try--) {
36 u16 status = readw(RCB_REG(IOBPS));
37 if ((status & IOBPS_READY) == 0)
42 printf("IOBP: timeout waiting for transaction to complete\n");
46 int pch_iobp_trans_start(u32 address, int op)
52 writel(address, RCB_REG(IOBPIRI));
55 clrsetbits_le16(RCB_REG(IOBPS), IOBPS_MASK, op);
60 int pch_iobp_trans_finish(void)
64 /* Undocumented magic */
65 writew(IOBPU_MAGIC, RCB_REG(IOBPU));
68 setbits_le16(RCB_REG(IOBPS), IOBPS_READY);
73 /* Check for successful transaction */
74 status = readw(RCB_REG(IOBPS));
75 if (status & IOBPS_TX_MASK)
81 u32 pch_iobp_read(u32 address)
83 if (!pch_iobp_trans_start(address, IOBPS_READ))
85 if (pch_iobp_trans_finish()) {
86 printf("IOBP: read 0x%08x failed\n", address);
91 return readl(RCB_REG(IOBPD));
94 int pch_iobp_write(u32 address, u32 data)
96 if (!pch_iobp_trans_start(address, IOBPS_WRITE))
99 writel(data, RCB_REG(IOBPD));
101 if (pch_iobp_trans_finish()) {
102 printf("IOBP: write 0x%08x failed\n", address);
109 int pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
111 u32 data = pch_iobp_read(address);
113 /* Update the data */
117 return pch_iobp_write(address, data);
120 int pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp)
129 writel(addr, RCB_REG(IOBPIRI));
130 clrsetbits_le16(RCB_REG(IOBPS), 0xff00, op_code);
131 writew(IOBPU_MAGIC | route_id, RCB_REG(IOBPU));
133 writel(*data, RCB_REG(IOBPD));
134 /* Set IOBPS[0] to trigger IOBP transaction*/
135 setbits_le16(RCB_REG(IOBPS), 1);
140 *resp = (readw(RCB_REG(IOBPS)) & IOBPS_TX_MASK) >> 1;
141 *data = readl(RCB_REG(IOBPD));