xref: /openbmc/u-boot/arch/x86/cpu/broadwell/iobp.c (revision 00caae6d)
1 /*
2  * Copyright (c) 2016 Google, Inc
3  *
4  * Modified from coreboot
5  *
6  * SPDX-License-Identifier:	GPL-2.0
7  */
8 
9 #include <common.h>
10 #include <errno.h>
11 #include <asm/intel_regs.h>
12 #include <asm/io.h>
13 #include <asm/arch/pch.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 }
145