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