xref: /aosp_15_r20/external/coreboot/src/device/software_i2c.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <timer.h>
5 #include <console/console.h>
6 #include <device/i2c_simple.h>
7 
8 /*
9  * The implementation is based on Wikipedia.
10  */
11 
12 #define DEBUG 0		/* Set to 1 for per-byte output */
13 #define SPEW 0		/* Set to 1 for verbose bitwise/line-state output */
14 #define DELAY_US 5	/* Default setup delay: 4us (+1 for timer inaccuracy) */
15 #define TIMEOUT_US 50000 /* Maximum clock stretching time we want to allow */
16 
17 #define spew(...) do { if (SPEW) printk(BIOS_SPEW, ##__VA_ARGS__); } while (0)
18 
19 #define ERR_NACK	-2
20 #define ERR_TIMEOUT	-3
21 #define ERR_ARB		-4
22 #define ERR_WEDGE	-5
23 
24 struct software_i2c_ops *software_i2c[SOFTWARE_I2C_MAX_BUS];
25 
26 /*
27  * Waits until either timeout_us have passed or (iff for_scl is set) until SCL
28  * goes high. Will report random line changes during the wait and return SCL.
29  */
__wait(unsigned int bus,int timeout_us,int for_scl)30 static int __wait(unsigned int bus, int timeout_us, int for_scl)
31 {
32 	int us;
33 	int sda = software_i2c[bus]->get_sda(bus);
34 	int scl = software_i2c[bus]->get_scl(bus);
35 	struct stopwatch sw;
36 
37 	stopwatch_init_usecs_expire(&sw, timeout_us);
38 
39 	do {
40 		int old_sda = sda;
41 		int old_scl = scl;
42 
43 		us = stopwatch_duration_usecs(&sw);
44 
45 		if (old_sda != (sda = software_i2c[bus]->get_sda(bus)))
46 			spew("[SDA transitioned to %d after %dus] ", sda, us);
47 		if (old_scl != (scl = software_i2c[bus]->get_scl(bus)))
48 			spew("[SCL transitioned to %d after %dus] ", scl, us);
49 	} while (!stopwatch_expired(&sw) && (!for_scl || !scl));
50 
51 	return scl;
52 }
53 
54 /* Waits the default DELAY_US to allow line state to stabilize. */
wait(unsigned int bus)55 static void wait(unsigned int bus)
56 {
57 	__wait(bus, DELAY_US, 0);
58 }
59 
60 /* Waits until SCL goes high. Prints a contextual error message on timeout. */
wait_for_scl(unsigned int bus,const char * error_context)61 static int wait_for_scl(unsigned int bus, const char *error_context)
62 {
63 	if (!__wait(bus, TIMEOUT_US, 1)) {
64 		printk(BIOS_ERR, "software_i2c(%d): ERROR: Clock stretching "
65 				 "timeout %s!\n", bus, error_context);
66 		return ERR_TIMEOUT;
67 	}
68 
69 	return 0;
70 }
71 
start_cond(unsigned int bus)72 static int start_cond(unsigned int bus)
73 {
74 	spew("software_i2c(%d): Sending start condition... ", bus);
75 
76 	/* SDA might not yet be high if repeated start. */
77 	software_i2c[bus]->set_sda(bus, 1);
78 	wait(bus);
79 
80 	/* Might need to wait for clock stretching if repeated start. */
81 	software_i2c[bus]->set_scl(bus, 1);
82 	if (wait_for_scl(bus, "before start condition"))
83 		return ERR_TIMEOUT;
84 	wait(bus);	/* Repeated start setup time, minimum 4.7us */
85 
86 	if (!software_i2c[bus]->get_sda(bus)) {
87 		printk(BIOS_ERR, "software_i2c(%d): Arbitration lost trying "
88 			"to send start condition!\n", bus);
89 		return ERR_ARB;
90 	}
91 
92 	/* SCL is high, transition SDA low as first part of start condition. */
93 	software_i2c[bus]->set_sda(bus, 0);
94 	wait(bus);
95 	assert(software_i2c[bus]->get_scl(bus));
96 
97 	/* Pull SCL low to finish start condition (next pulse will be data). */
98 	software_i2c[bus]->set_scl(bus, 0);
99 
100 	spew("Start condition transmitted!\n");
101 	return 0;
102 }
103 
stop_cond(unsigned int bus)104 static int stop_cond(unsigned int bus)
105 {
106 	spew("software_i2c(%d): Sending stop condition... ", bus);
107 
108 	/* SDA is unknown, set it to low. SCL must be low. */
109 	software_i2c[bus]->set_sda(bus, 0);
110 	wait(bus);
111 
112 	/* Clock stretching */
113 	assert(!software_i2c[bus]->get_scl(bus));
114 	software_i2c[bus]->set_scl(bus, 1);
115 	if (wait_for_scl(bus, "before stop condition"))
116 		return ERR_TIMEOUT;
117 	wait(bus);	/* Stop bit setup time, minimum 4us */
118 
119 	/* SCL is high, transition SDA high to signal stop condition. */
120 	software_i2c[bus]->set_sda(bus, 1);
121 	wait(bus);
122 	if (!software_i2c[bus]->get_sda(bus)) {
123 		printk(BIOS_WARNING, "software_i2c(%d): WARNING: SDA low after "
124 			"stop condition... access by another master or line "
125 			"stuck from faulty slave?\n", bus);
126 		/* Could theoretically happen with multi-master, so no -1. */
127 	}
128 
129 	spew("Stop condition transmitted\n");
130 	return 0;
131 }
132 
out_bit(unsigned int bus,int bit)133 static int out_bit(unsigned int bus, int bit)
134 {
135 	spew("software_i2c(%d): Sending a %d bit... ", bus, bit);
136 
137 	software_i2c[bus]->set_sda(bus, bit);
138 	wait(bus);
139 
140 	if (bit && !software_i2c[bus]->get_sda(bus)) {
141 		printk(BIOS_ERR, "software_i2c(%d): ERROR: SDA wedged low "
142 			"by slave before clock pulse on transmit!\n", bus);
143 		return ERR_WEDGE;
144 	}
145 
146 	/* Clock stretching */
147 	assert(!software_i2c[bus]->get_scl(bus));
148 	software_i2c[bus]->set_scl(bus, 1);
149 	if (wait_for_scl(bus, "on transmit"))
150 		return ERR_TIMEOUT;
151 	wait(bus);
152 
153 	if (bit && !software_i2c[bus]->get_sda(bus)) {
154 		printk(BIOS_ERR, "software_i2c(%d): ERROR: SDA wedged low "
155 			"by slave after clock pulse on transmit!\n", bus);
156 		return ERR_WEDGE;
157 	}
158 
159 	assert(software_i2c[bus]->get_scl(bus));
160 	software_i2c[bus]->set_scl(bus, 0);
161 
162 	spew("%d bit sent!\n", bit);
163 	return 0;
164 }
165 
in_bit(unsigned int bus)166 static int in_bit(unsigned int bus)
167 {
168 	int bit;
169 
170 	spew("software_i2c(%d): Receiving a bit... ", bus);
171 
172 	/* Let the slave drive data */
173 	software_i2c[bus]->set_sda(bus, 1);
174 	wait(bus);
175 
176 	/* Clock stretching */
177 	assert(!software_i2c[bus]->get_scl(bus));
178 	software_i2c[bus]->set_scl(bus, 1);
179 	if (wait_for_scl(bus, "on receive"))
180 		return ERR_TIMEOUT;
181 
182 	/* SCL is high, now data is valid */
183 	bit = software_i2c[bus]->get_sda(bus);
184 	wait(bus);
185 	assert(software_i2c[bus]->get_scl(bus));
186 	software_i2c[bus]->set_scl(bus, 0);
187 
188 	spew("Received a %d!\n", bit);
189 
190 	return bit;
191 }
192 
193 /* Write a byte to I2C bus. Return 0 if ack by the slave. */
out_byte(unsigned int bus,u8 byte)194 static int out_byte(unsigned int bus, u8 byte)
195 {
196 	unsigned int bit;
197 	int nack, ret;
198 
199 	for (bit = 0; bit < 8; bit++)
200 		if ((ret = out_bit(bus, (byte >> (7 - bit)) & 0x1)) < 0)
201 			return ret;
202 
203 	nack = in_bit(bus);
204 
205 	if (DEBUG && nack >= 0)
206 		printk(BIOS_DEBUG, "software_i2c(%d): wrote byte 0x%02x, "
207 			"received %s\n", bus, byte, nack ? "NAK" : "ACK");
208 
209 	return nack > 0 ? ERR_NACK : nack;
210 }
211 
in_byte(unsigned int bus,int ack)212 static int in_byte(unsigned int bus, int ack)
213 {
214 	u8 byte = 0;
215 	int i, ret;
216 	for (i = 0; i < 8; ++i) {
217 		int bit = in_bit(bus);
218 		if (bit < 0)
219 			return bit;
220 		byte = (byte << 1) | bit;
221 	}
222 
223 	if ((ret = out_bit(bus, !ack)) < 0)
224 		return ret;
225 
226 	if (DEBUG)
227 		printk(BIOS_DEBUG, "software_i2c(%d): read byte 0x%02x, "
228 			"sent %s\n", bus, byte, ack ? "ACK" : "NAK");
229 
230 	return byte;
231 }
232 
software_i2c_transfer(unsigned int bus,struct i2c_msg * segments,int count)233 int software_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count)
234 {
235 	int i, ret;
236 	struct i2c_msg *seg;
237 
238 	for (seg = segments; seg - segments < count; seg++) {
239 		if ((ret = start_cond(bus)) < 0)
240 			return ret;
241 		const u8 addr_dir = seg->slave << 1 | !!(seg->flags & I2C_M_RD);
242 		if ((ret = out_byte(bus, addr_dir)) < 0)
243 			return ret;
244 		for (i = 0; i < seg->len; i++) {
245 			if (seg->flags & I2C_M_RD) {
246 				ret = in_byte(bus, i < seg->len - 1);
247 				seg->buf[i] = (u8)ret;
248 			} else {
249 				ret = out_byte(bus, seg->buf[i]);
250 			}
251 			if (ret < 0)
252 				return ret;
253 		}
254 	}
255 	if ((ret = stop_cond(bus)) < 0)
256 		return ret;
257 
258 	return 0;
259 }
260 
software_i2c_wedge_ack(unsigned int bus,u8 chip)261 void software_i2c_wedge_ack(unsigned int bus, u8 chip)
262 {
263 	int i;
264 
265 	/* Start a command to 'chip'... */
266 	start_cond(bus);
267 
268 	/* Send the address bits but don't yet read the ACK. */
269 	chip <<= 1;
270 	for (i = 0; i < 8; ++i)
271 		out_bit(bus, (chip >> (7 - i)) & 0x1);
272 
273 	/* Let the slave drive it's ACK but keep the clock high forever. */
274 	software_i2c[bus]->set_sda(bus, 1);
275 	wait(bus);
276 	software_i2c[bus]->set_scl(bus, 1);
277 	wait_for_scl(bus, "on wedge_ack()");
278 
279 	printk(BIOS_INFO, "software_i2c(%d): wedged address write on slave "
280 		"ACK. SDA %d, SCL %d\n", bus, software_i2c[bus]->get_sda(bus),
281 		software_i2c[bus]->get_scl(bus));
282 }
283 
software_i2c_wedge_read(unsigned int bus,u8 chip,u8 reg,int bits)284 void software_i2c_wedge_read(unsigned int bus, u8 chip, u8 reg, int bits)
285 {
286 	int i;
287 
288 	/* Start a command to 'chip'... */
289 	start_cond(bus);
290 	out_byte(bus, chip << 1);
291 	/* ...for register 'reg'. */
292 	out_byte(bus, reg);
293 
294 	/* Start a read command... */
295 	start_cond(bus);
296 	out_byte(bus, chip << 1 | 1);
297 
298 	/* Read bit_count bits and stop */
299 	for (i = 0; i < bits; ++i)
300 		in_bit(bus);
301 
302 	/* Let the slave drive SDA but keep the clock high forever. */
303 	software_i2c[bus]->set_sda(bus, 1);
304 	wait(bus);
305 	software_i2c[bus]->set_scl(bus, 1);
306 	wait_for_scl(bus, "on wedge_read()");
307 
308 	printk(BIOS_INFO, "software_i2c(%d): wedged data read after %d bits. "
309 		"SDA %d, SCL %d\n", bus, bits, software_i2c[bus]->get_sda(bus),
310 		software_i2c[bus]->get_scl(bus));
311 }
312 
software_i2c_wedge_write(unsigned int bus,u8 chip,u8 reg,int bits)313 void software_i2c_wedge_write(unsigned int bus, u8 chip, u8 reg, int bits)
314 {
315 	int i;
316 
317 	/* Start a command to 'chip'... */
318 	start_cond(bus);
319 	out_byte(bus, chip << 1);
320 
321 	/* Write bit_count register bits and stop */
322 	for (i = 0; i < bits; ++i)
323 		out_bit(bus, (reg >> (7 - i)) & 0x1);
324 
325 	/* Pretend to write another 1 bit but keep the clock high forever. */
326 	software_i2c[bus]->set_sda(bus, 1);
327 	wait(bus);
328 	software_i2c[bus]->set_scl(bus, 1);
329 	wait_for_scl(bus, "on wedge_write()");
330 
331 	printk(BIOS_INFO, "software_i2c(%d): wedged data write after %d bits. "
332 		"SDA %d, SCL %d\n", bus, bits, software_i2c[bus]->get_sda(bus),
333 		software_i2c[bus]->get_scl(bus));
334 }
335