Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[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 #include <linux/delay.h>
14
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
31 static 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
46 int 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
60 int 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
81 u32 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
94 int 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
109 int 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
120 int 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 }