1*1e6f4e58SSimon Glass /*
2*1e6f4e58SSimon Glass * Copyright (c) 2016 Google, Inc
3*1e6f4e58SSimon Glass *
4*1e6f4e58SSimon Glass * Modified from coreboot
5*1e6f4e58SSimon Glass *
6*1e6f4e58SSimon Glass * SPDX-License-Identifier: GPL-2.0
7*1e6f4e58SSimon Glass */
8*1e6f4e58SSimon Glass
9*1e6f4e58SSimon Glass #include <common.h>
10*1e6f4e58SSimon Glass #include <errno.h>
11*1e6f4e58SSimon Glass #include <asm/intel_regs.h>
12*1e6f4e58SSimon Glass #include <asm/io.h>
13*1e6f4e58SSimon Glass #include <asm/arch/pch.h>
14*1e6f4e58SSimon Glass
15*1e6f4e58SSimon Glass #define IOBP_RETRY 1000
16*1e6f4e58SSimon Glass
17*1e6f4e58SSimon Glass /* IO Buffer Programming */
18*1e6f4e58SSimon Glass #define IOBPIRI 0x2330
19*1e6f4e58SSimon Glass #define IOBPD 0x2334
20*1e6f4e58SSimon Glass #define IOBPS 0x2338
21*1e6f4e58SSimon Glass #define IOBPS_READY 0x0001
22*1e6f4e58SSimon Glass #define IOBPS_TX_MASK 0x0006
23*1e6f4e58SSimon Glass #define IOBPS_MASK 0xff00
24*1e6f4e58SSimon Glass #define IOBPS_READ 0x0600
25*1e6f4e58SSimon Glass #define IOBPS_WRITE 0x0700
26*1e6f4e58SSimon Glass #define IOBPU 0x233a
27*1e6f4e58SSimon Glass #define IOBPU_MAGIC 0xf000
28*1e6f4e58SSimon Glass #define IOBP_PCICFG_READ 0x0400
29*1e6f4e58SSimon Glass #define IOBP_PCICFG_WRITE 0x0500
30*1e6f4e58SSimon Glass
iobp_poll(void)31*1e6f4e58SSimon Glass static inline int iobp_poll(void)
32*1e6f4e58SSimon Glass {
33*1e6f4e58SSimon Glass unsigned try;
34*1e6f4e58SSimon Glass
35*1e6f4e58SSimon Glass for (try = IOBP_RETRY; try > 0; try--) {
36*1e6f4e58SSimon Glass u16 status = readw(RCB_REG(IOBPS));
37*1e6f4e58SSimon Glass if ((status & IOBPS_READY) == 0)
38*1e6f4e58SSimon Glass return 1;
39*1e6f4e58SSimon Glass udelay(10);
40*1e6f4e58SSimon Glass }
41*1e6f4e58SSimon Glass
42*1e6f4e58SSimon Glass printf("IOBP: timeout waiting for transaction to complete\n");
43*1e6f4e58SSimon Glass return 0;
44*1e6f4e58SSimon Glass }
45*1e6f4e58SSimon Glass
pch_iobp_trans_start(u32 address,int op)46*1e6f4e58SSimon Glass int pch_iobp_trans_start(u32 address, int op)
47*1e6f4e58SSimon Glass {
48*1e6f4e58SSimon Glass if (!iobp_poll())
49*1e6f4e58SSimon Glass return 0;
50*1e6f4e58SSimon Glass
51*1e6f4e58SSimon Glass /* Set the address */
52*1e6f4e58SSimon Glass writel(address, RCB_REG(IOBPIRI));
53*1e6f4e58SSimon Glass
54*1e6f4e58SSimon Glass /* READ OPCODE */
55*1e6f4e58SSimon Glass clrsetbits_le16(RCB_REG(IOBPS), IOBPS_MASK, op);
56*1e6f4e58SSimon Glass
57*1e6f4e58SSimon Glass return 1;
58*1e6f4e58SSimon Glass }
59*1e6f4e58SSimon Glass
pch_iobp_trans_finish(void)60*1e6f4e58SSimon Glass int pch_iobp_trans_finish(void)
61*1e6f4e58SSimon Glass {
62*1e6f4e58SSimon Glass u16 status;
63*1e6f4e58SSimon Glass
64*1e6f4e58SSimon Glass /* Undocumented magic */
65*1e6f4e58SSimon Glass writew(IOBPU_MAGIC, RCB_REG(IOBPU));
66*1e6f4e58SSimon Glass
67*1e6f4e58SSimon Glass /* Set ready bit */
68*1e6f4e58SSimon Glass setbits_le16(RCB_REG(IOBPS), IOBPS_READY);
69*1e6f4e58SSimon Glass
70*1e6f4e58SSimon Glass if (!iobp_poll())
71*1e6f4e58SSimon Glass return 1;
72*1e6f4e58SSimon Glass
73*1e6f4e58SSimon Glass /* Check for successful transaction */
74*1e6f4e58SSimon Glass status = readw(RCB_REG(IOBPS));
75*1e6f4e58SSimon Glass if (status & IOBPS_TX_MASK)
76*1e6f4e58SSimon Glass return 1;
77*1e6f4e58SSimon Glass
78*1e6f4e58SSimon Glass return 0;
79*1e6f4e58SSimon Glass }
80*1e6f4e58SSimon Glass
pch_iobp_read(u32 address)81*1e6f4e58SSimon Glass u32 pch_iobp_read(u32 address)
82*1e6f4e58SSimon Glass {
83*1e6f4e58SSimon Glass if (!pch_iobp_trans_start(address, IOBPS_READ))
84*1e6f4e58SSimon Glass return 0;
85*1e6f4e58SSimon Glass if (pch_iobp_trans_finish()) {
86*1e6f4e58SSimon Glass printf("IOBP: read 0x%08x failed\n", address);
87*1e6f4e58SSimon Glass return 0;
88*1e6f4e58SSimon Glass }
89*1e6f4e58SSimon Glass
90*1e6f4e58SSimon Glass /* Read IOBP data */
91*1e6f4e58SSimon Glass return readl(RCB_REG(IOBPD));
92*1e6f4e58SSimon Glass }
93*1e6f4e58SSimon Glass
pch_iobp_write(u32 address,u32 data)94*1e6f4e58SSimon Glass int pch_iobp_write(u32 address, u32 data)
95*1e6f4e58SSimon Glass {
96*1e6f4e58SSimon Glass if (!pch_iobp_trans_start(address, IOBPS_WRITE))
97*1e6f4e58SSimon Glass return -EIO;
98*1e6f4e58SSimon Glass
99*1e6f4e58SSimon Glass writel(data, RCB_REG(IOBPD));
100*1e6f4e58SSimon Glass
101*1e6f4e58SSimon Glass if (pch_iobp_trans_finish()) {
102*1e6f4e58SSimon Glass printf("IOBP: write 0x%08x failed\n", address);
103*1e6f4e58SSimon Glass return -EIO;
104*1e6f4e58SSimon Glass }
105*1e6f4e58SSimon Glass
106*1e6f4e58SSimon Glass return 0;
107*1e6f4e58SSimon Glass }
108*1e6f4e58SSimon Glass
pch_iobp_update(u32 address,u32 andvalue,u32 orvalue)109*1e6f4e58SSimon Glass int pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
110*1e6f4e58SSimon Glass {
111*1e6f4e58SSimon Glass u32 data = pch_iobp_read(address);
112*1e6f4e58SSimon Glass
113*1e6f4e58SSimon Glass /* Update the data */
114*1e6f4e58SSimon Glass data &= andvalue;
115*1e6f4e58SSimon Glass data |= orvalue;
116*1e6f4e58SSimon Glass
117*1e6f4e58SSimon Glass return pch_iobp_write(address, data);
118*1e6f4e58SSimon Glass }
119*1e6f4e58SSimon Glass
pch_iobp_exec(u32 addr,u16 op_code,u8 route_id,u32 * data,u8 * resp)120*1e6f4e58SSimon Glass int pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp)
121*1e6f4e58SSimon Glass {
122*1e6f4e58SSimon Glass if (!data || !resp)
123*1e6f4e58SSimon Glass return 0;
124*1e6f4e58SSimon Glass
125*1e6f4e58SSimon Glass *resp = -1;
126*1e6f4e58SSimon Glass if (!iobp_poll())
127*1e6f4e58SSimon Glass return -EIO;
128*1e6f4e58SSimon Glass
129*1e6f4e58SSimon Glass writel(addr, RCB_REG(IOBPIRI));
130*1e6f4e58SSimon Glass clrsetbits_le16(RCB_REG(IOBPS), 0xff00, op_code);
131*1e6f4e58SSimon Glass writew(IOBPU_MAGIC | route_id, RCB_REG(IOBPU));
132*1e6f4e58SSimon Glass
133*1e6f4e58SSimon Glass writel(*data, RCB_REG(IOBPD));
134*1e6f4e58SSimon Glass /* Set IOBPS[0] to trigger IOBP transaction*/
135*1e6f4e58SSimon Glass setbits_le16(RCB_REG(IOBPS), 1);
136*1e6f4e58SSimon Glass
137*1e6f4e58SSimon Glass if (!iobp_poll())
138*1e6f4e58SSimon Glass return -EIO;
139*1e6f4e58SSimon Glass
140*1e6f4e58SSimon Glass *resp = (readw(RCB_REG(IOBPS)) & IOBPS_TX_MASK) >> 1;
141*1e6f4e58SSimon Glass *data = readl(RCB_REG(IOBPD));
142*1e6f4e58SSimon Glass
143*1e6f4e58SSimon Glass return 0;
144*1e6f4e58SSimon Glass }
145