xref: /openbmc/u-boot/arch/x86/cpu/broadwell/iobp.c (revision b9553986)
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 }
144