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