8a3ca6cde7e54d8fd22ecca1be0ab96dba965b5c
[oweals/u-boot.git] / arch / x86 / cpu / broadwell / iobp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2016 Google, Inc
4  *
5  * Modified from coreboot
6  */
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
30 static 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
45 int 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
59 int 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
80 u32 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
93 int 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
108 int 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
119 int 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 }