xref: /aosp_15_r20/external/coreboot/src/southbridge/intel/lynxpoint/iobp.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <delay.h>
5 #include "pch.h"
6 #include "iobp.h"
7 
8 #define IOBP_RETRY 1000
9 
iobp_poll(void)10 static inline int iobp_poll(void)
11 {
12 	unsigned int try;
13 
14 	for (try = IOBP_RETRY; try > 0; try--) {
15 		u16 status = RCBA16(IOBPS);
16 		if ((status & IOBPS_READY) == 0)
17 			return 1;
18 		udelay(10);
19 	}
20 
21 	printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
22 	return 0;
23 }
24 
pch_iobp_read(u32 address)25 u32 pch_iobp_read(u32 address)
26 {
27 	u16 status;
28 
29 	if (!iobp_poll())
30 		return 0;
31 
32 	/* Set the address */
33 	RCBA32(IOBPIRI) = address;
34 
35 	/* READ OPCODE */
36 	status = RCBA16(IOBPS);
37 	status &= ~IOBPS_MASK;
38 	status |= IOBPS_READ;
39 	RCBA16(IOBPS) = status;
40 
41 	/* Undocumented magic */
42 	RCBA16(IOBPU) = IOBPU_MAGIC;
43 
44 	/* Set ready bit */
45 	status = RCBA16(IOBPS);
46 	status |= IOBPS_READY;
47 	RCBA16(IOBPS) = status;
48 
49 	if (!iobp_poll())
50 		return 0;
51 
52 	/* Check for successful transaction */
53 	status = RCBA16(IOBPS);
54 	if (status & IOBPS_TX_MASK) {
55 		printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
56 		return 0;
57 	}
58 
59 	/* Read IOBP data */
60 	return RCBA32(IOBPD);
61 }
62 
pch_iobp_write(u32 address,u32 data)63 void pch_iobp_write(u32 address, u32 data)
64 {
65 	u16 status;
66 
67 	if (!iobp_poll())
68 		return;
69 
70 	/* Set the address */
71 	RCBA32(IOBPIRI) = address;
72 
73 	/* WRITE OPCODE */
74 	status = RCBA16(IOBPS);
75 	status &= ~IOBPS_MASK;
76 	status |= IOBPS_WRITE;
77 	RCBA16(IOBPS) = status;
78 
79 	RCBA32(IOBPD) = data;
80 
81 	/* Undocumented magic */
82 	RCBA16(IOBPU) = IOBPU_MAGIC;
83 
84 	/* Set ready bit */
85 	status = RCBA16(IOBPS);
86 	status |= IOBPS_READY;
87 	RCBA16(IOBPS) = status;
88 
89 	if (!iobp_poll())
90 		return;
91 
92 	/* Check for successful transaction */
93 	status = RCBA16(IOBPS);
94 	if (status & IOBPS_TX_MASK) {
95 		printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
96 		return;
97 	}
98 
99 	printk(BIOS_SPEW, "IOBP: set 0x%08x to 0x%08x\n", address, data);
100 }
101 
pch_iobp_update(u32 address,u32 andvalue,u32 orvalue)102 void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
103 {
104 	u32 data = pch_iobp_read(address);
105 
106 	/* Update the data */
107 	data &= andvalue;
108 	data |= orvalue;
109 
110 	pch_iobp_write(address, data);
111 }
112 
pch_iobp_exec(u32 addr,u16 op_code,u8 route_id,u32 * data,u8 * resp)113 void pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp)
114 {
115 	if (!data || !resp)
116 		return;
117 
118 	*resp = -1;
119 	if (!iobp_poll())
120 		return;
121 
122 	/* RCBA2330[31:0] = Address */
123 	RCBA32(IOBPIRI) = addr;
124 	/* RCBA2338[15:8] = opcode */
125 	RCBA16(IOBPS) = (RCBA16(IOBPS) & 0x00ff) | op_code;
126 	/* RCBA233A[15:8] = 0xf0 RCBA233A[7:0] = Route ID */
127 	RCBA16(IOBPU) = IOBPU_MAGIC | route_id;
128 
129 	if (op_code == IOBP_PCICFG_WRITE)
130 		RCBA32(IOBPD) = *data;
131 	/* Set RCBA2338[0] to trigger IOBP transaction*/
132 	RCBA16(IOBPS) = RCBA16(IOBPS) | 0x1;
133 
134 	if (!iobp_poll())
135 		return;
136 
137 	*resp = (RCBA16(IOBPS) & IOBPS_TX_MASK) >> 1;
138 	*data = RCBA32(IOBPD);
139 }
140