xref: /aosp_15_r20/external/flashrom/mediatek_i2c_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2021 The Chromium OS Authors
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include <linux/i2c-dev.h>
18 #include <linux/i2c.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #include <unistd.h>
23 
24 #include "flash.h"
25 #include "i2c_helper.h"
26 #include "programmer.h"
27 #include "spi.h"
28 
29 #define ISP_PORT   (0x92 >> 1)
30 #define DEBUG_PORT (0xb2 >> 1)
31 
32 #define MTK_CMD_WRITE 0x10
33 #define MTK_CMD_READ 0x11
34 #define MTK_CMD_END 0x12
35 
36 struct mediatek_data {
37 	int fd;
38 	unsigned long funcs;
39 };
40 
41 // Returns null pointer on error.
get_data_from_context(const struct flashctx * flash)42 static const struct mediatek_data *get_data_from_context(
43 	const struct flashctx *flash)
44 {
45 	if (!flash || !flash->mst || !flash->mst->spi.data) {
46 		msg_pdbg("Unable to extract data from flash context\n");
47 		return NULL;
48 	}
49 	return (const struct mediatek_data *)flash->mst->spi.data;
50 }
51 
52 // Returns bytes read, negative value on error.
read_raw(const struct mediatek_data * port,uint16_t addr,uint8_t * buf,size_t len)53 static int read_raw(const struct mediatek_data *port, uint16_t addr,
54 	uint8_t *buf, size_t len)
55 {
56 	int ret;
57 
58 	if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
59 		msg_pdbg("Invalid length for read command: %zu\n", len);
60 		return SPI_INVALID_LENGTH;
61 	}
62 
63 	ret = ioctl(port->fd, I2C_SLAVE, addr);
64 	if (ret) {
65 		msg_pdbg("Failed to set slave address 0x%02x (%d)\n", addr, ret);
66 		return ret;
67 	}
68 
69 	if (port->funcs & I2C_FUNC_I2C) {
70 		// Use raw I2C read.
71 		uint8_t command = MTK_CMD_READ;
72 		if (write(port->fd, &command, 1) != 1) {
73 			return SPI_GENERIC_ERROR;
74 		}
75 		if (read(port->fd, buf, len) != (int)len) {
76 			return SPI_GENERIC_ERROR;
77 		}
78 		return len;
79 	}
80 
81 	union i2c_smbus_data data = {
82 		.block[0] = len,
83 	};
84 	struct i2c_smbus_ioctl_data args = {
85 		.read_write = I2C_SMBUS_READ,
86 		.command = MTK_CMD_READ,
87 		.size = I2C_SMBUS_I2C_BLOCK_DATA,
88 		.data = &data,
89 	};
90 	ret = ioctl(port->fd, I2C_SMBUS, &args);
91 	if (ret) {
92 		msg_pdbg("Failed to read SMBus I2C block data\n");
93 		return ret;
94 	}
95 	memcpy(buf, args.data->block + 1, len);
96 	return args.data->block[0];
97 }
98 
99 // Returns non-zero value on error.
write_command(const struct mediatek_data * port,uint16_t addr,uint8_t command,const uint8_t * buf,size_t len)100 static int write_command(const struct mediatek_data *port, uint16_t addr,
101 	uint8_t command, const uint8_t *buf, size_t len)
102 {
103 	int ret;
104 
105 	if (len > I2C_SMBUS_BLOCK_MAX) {
106 		msg_pdbg("Invalid length for write command: %zu\n", len);
107 		return SPI_INVALID_LENGTH;
108 	}
109 
110 	ret = ioctl(port->fd, I2C_SLAVE, addr);
111 	if (ret) {
112 		msg_pdbg("Failed to set slave address: 0x%02x\n", addr);
113 		return ret;
114 	}
115 
116 	if (port->funcs & I2C_FUNC_I2C) {
117 		// Use raw I2C write.
118 		uint8_t raw_buffer[I2C_SMBUS_BLOCK_MAX + 1];
119 		raw_buffer[0] = command;
120 		if (len > 0) {
121 			memcpy(raw_buffer + 1, buf, len);
122 		}
123 		if (write(port->fd, raw_buffer, len + 1) != (int)(len + 1)) {
124 			return SPI_GENERIC_ERROR;
125 		}
126 		return 0;
127 	}
128 
129 	union i2c_smbus_data data = {0};
130 	struct i2c_smbus_ioctl_data args = {
131 		.read_write = I2C_SMBUS_WRITE,
132 		.command = command,
133 		.data = &data,
134 	};
135 
136 	// Special case single byte commands, as empty I2C block data commands
137 	// failed on this component in practice.
138 	if (len == 0) {
139 		args.size = I2C_SMBUS_BYTE;
140 		ret = ioctl(port->fd, I2C_SMBUS, &args);
141 		if (ret) {
142 			msg_pdbg("Failed to write SMBus byte: 0x%02x\n", command);
143 		}
144 		return ret;
145 	}
146 
147 	args.size = I2C_SMBUS_I2C_BLOCK_DATA;
148 	data.block[0] = len;
149 	if (buf && len) {
150 		memcpy(data.block + 1, buf, len);
151 	}
152 	ret = ioctl(port->fd, I2C_SMBUS, &args);
153 	if (ret) {
154 		msg_pdbg("Failed to write SMBus I2C block data: 0x%02x\n", command);
155 	}
156 	return ret;
157 }
158 
159 // Returns non-zero value on error.
write_raw(const struct mediatek_data * port,uint16_t addr,const uint8_t * buf,size_t len)160 static int write_raw(const struct mediatek_data *port, uint16_t addr,
161 	const uint8_t *buf, size_t len)
162 {
163 	if (len < 1) {
164 		msg_pdbg("Invalid write length: %zu\n", len);
165 		return SPI_INVALID_LENGTH;
166 	}
167 	return write_command(port, addr, buf[0], buf + 1, len - 1);
168 }
169 
170 // Read from a GPIO register via debug port. Returns non-zero value on error.
mediatek_read_gpio(const struct mediatek_data * port,uint16_t gpio_addr,uint8_t * value)171 static int mediatek_read_gpio(const struct mediatek_data *port,
172 	uint16_t gpio_addr, uint8_t *value)
173 {
174 	int ret;
175 
176 	uint8_t data[2];
177 	data[0] = gpio_addr >> 8;
178 	data[1] = gpio_addr & 0xff;
179 
180 	ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, data, ARRAY_SIZE(data));
181 	if (ret) {
182 		msg_pdbg("Failed to issue read GPIO command at address 0x%04x\n", gpio_addr);
183 		return ret;
184 	}
185 
186 	size_t len = 1;
187 	ret = read_raw(port, DEBUG_PORT, value, len);
188 	if (ret < 0) {
189 		msg_pdbg("Failed to read GPIO register at address 0x%04x\n", gpio_addr);
190 		return ret;
191 	}
192 
193 	if (ret != 1) {
194 		msg_pdbg("GPIO read returned improper length: %d\n", ret);
195 		return SPI_INVALID_LENGTH;
196 	}
197 
198 	return 0;
199 }
200 
201 // Write to a GPIO register via the debug port. Returns non-zero value on error.
mediatek_write_gpio(const struct mediatek_data * port,uint16_t gpio_addr,uint8_t value)202 static int mediatek_write_gpio(const struct mediatek_data *port,
203 	uint16_t gpio_addr, uint8_t value)
204 {
205 	uint8_t data[3];
206 	data[0] = gpio_addr >> 8;
207 	data[1] = gpio_addr & 0xff;
208 	data[2] = value;
209 
210 	return write_command(port, DEBUG_PORT, MTK_CMD_WRITE, data, ARRAY_SIZE(data));
211 }
212 
213 // Write a single bit value to a GPIO register via the debug port. Returns
214 // non-zero value on error.
mediatek_set_gpio_bit(const struct mediatek_data * port,uint16_t gpio_addr,int bit,int value)215 static int mediatek_set_gpio_bit(const struct mediatek_data *port,
216 	uint16_t gpio_addr, int bit, int value)
217 {
218 	int ret;
219 	uint8_t data;
220 
221 	ret = mediatek_read_gpio(port, gpio_addr, &data);
222 	if (ret) {
223 		msg_pdbg("Failed to read GPIO 0x%04x\n", gpio_addr);
224 		return ret;
225 	}
226 
227 	if (value) {
228 		data |= (1 << bit);
229 	} else {
230 		data &= ~(1 << bit);
231 	}
232 
233 	ret = mediatek_write_gpio(port, gpio_addr, data);
234 	if (ret) {
235 		msg_pdbg("Failed to set GPIO 0x%04x to 0x%02x\n", gpio_addr, data);
236 		return ret;
237 	}
238 	return ret;
239 }
240 
241 // Poke the GPIO line that goes to SPI WP# using the MST9U GPIO register
242 // addresses. Returns non-zero value on error.
mediatek_set_write_protect(const struct mediatek_data * port,int protected)243 static int mediatek_set_write_protect(const struct mediatek_data *port,
244 	int protected)
245 {
246 	int ret;
247 
248 	ret = mediatek_set_gpio_bit(port, 0x426, 7, (protected == 0));
249 	if (ret) {
250 		msg_perr("Failed to set GPIO out value: %d\n", protected == 0);
251 		return ret;
252 	}
253 
254 	ret = mediatek_set_gpio_bit(port, 0x428, 7, (protected != 0));
255 	if (ret) {
256 		msg_perr("Failed to set GPIO enable value: %d\n", protected != 0);
257 		return ret;
258 	}
259 
260 	return 0;
261 }
262 
263 // Enter serial debug mode using "Option 1" for MST9U and select I2C channel 0
264 // to configure write protect GPIOs. Returns non-zero value on error.
mediatek_enter_serial_debug_mode(const struct mediatek_data * port)265 static int mediatek_enter_serial_debug_mode(const struct mediatek_data *port)
266 {
267 	int ret;
268 
269 	uint8_t enter_serial_debug[] = { 'S', 'E', 'R', 'D', 'B' };
270 	ret = write_raw(port, DEBUG_PORT, enter_serial_debug,
271 		ARRAY_SIZE(enter_serial_debug));
272 	if (ret) {
273 		msg_perr("Failed to send enter serial debug mode command\n");
274 		return ret;
275 	}
276 
277 	uint8_t enter_single_step_1[] = { 0xc0, 0xc1, 0x53 };
278 	ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE,
279 		enter_single_step_1, ARRAY_SIZE(enter_single_step_1));
280 	if (ret) {
281 		msg_perr("Failed to enter serial single step mode (part 1)\n");
282 		return ret;
283 	}
284 
285 	uint8_t enter_single_step_2[] = { 0x1f, 0xc1, 0x53 };
286 	ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, enter_single_step_2,
287 		ARRAY_SIZE(enter_single_step_2));
288 	if (ret) {
289 		msg_perr("Failed to enter serial single step mode (part 2)\n");
290 		return ret;
291 	}
292 
293 	// Send each I2C channel 0 configuration byte individually.
294 	uint8_t i2c_channel_0_config[] =
295 		{ 0x80, 0x82, 0x84, 0x51, 0x7f, 0x37, 0x61 };
296 	for (size_t i = 0; i < ARRAY_SIZE(i2c_channel_0_config); ++i) {
297 		ret = write_command(
298 			port, DEBUG_PORT, i2c_channel_0_config[i], NULL, 0);
299 		if (ret) {
300 			msg_perr("Failed to configure i2c channel 0: 0x%02x\n",
301 				i2c_channel_0_config[i]);
302 			return ret;
303 		}
304 	}
305 
306 	uint8_t enter_single_step_3[] = { 0x00, 0x00, 0x00 };
307 	ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, enter_single_step_3,
308 		ARRAY_SIZE(enter_single_step_3));
309 	if (ret) {
310 		msg_perr("Failed to enter serial single step mode (part 3)\n");
311 		return ret;
312 	}
313 
314 	ret = write_command(port, DEBUG_PORT, 0x35, NULL, 0);
315 	if (ret) {
316 		msg_perr("Failed to send serial debug command (part 1)\n");
317 		return ret;
318 	}
319 
320 	ret = write_command(port, DEBUG_PORT, 0x71, NULL, 0);
321 	if (ret) {
322 		msg_perr("Failed to send serial debug command (part 2)\n");
323 		return ret;
324 	}
325 
326 	return 0;
327 }
328 
329 // Returns non-zero value on error.
mediatek_enter_isp(const struct mediatek_data * port)330 static int mediatek_enter_isp(const struct mediatek_data *port)
331 {
332 	int ret;
333 
334 	ret = mediatek_enter_serial_debug_mode(port);
335 	if (ret) {
336 		msg_perr("Failed to enter serial debug mode\n");
337 		return ret;
338 	}
339 
340 	// MediaTek documentation says to do this twice just in case.
341 	uint8_t enter_isp[] = { 'M', 'S', 'T', 'A', 'R' };
342 	ret = write_raw(port, ISP_PORT, enter_isp, ARRAY_SIZE(enter_isp));
343 	if (ret) {
344 		msg_gwarn("Failed to enter ISP mode, trying again\n");
345 	}
346 	ret = write_raw(port, ISP_PORT, enter_isp, ARRAY_SIZE(enter_isp));
347 	if (ret) {
348 		msg_gwarn("Might already be in ISP mode, ignoring\n");
349 	}
350 
351 	ret = mediatek_set_write_protect(port, 0);
352 	if (ret) {
353 		msg_perr("Failed to disable write protection\n");
354 		return ret;
355 	}
356 
357 	return 0;
358 }
359 
360 // Returns non-zero value on error.
mediatek_exit_isp(const struct mediatek_data * port)361 static int mediatek_exit_isp(const struct mediatek_data *port)
362 {
363 	int ret;
364 
365 	ret = mediatek_set_write_protect(port, 1);
366 	if (ret) {
367 		msg_perr("Failed to re-enable write protect\n");
368 		return ret;
369 	}
370 
371 	uint8_t exit_single_step[] = { 0xc0, 0xc1, 0xff };
372 	ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, exit_single_step,
373 		ARRAY_SIZE(exit_single_step));
374 	if (ret) {
375 		msg_perr("Failed to exit single step mode\n");
376 		return ret;
377 	}
378 
379 	ret = write_command(port, DEBUG_PORT, 0x34, NULL, 0);
380 	if (ret) {
381 		msg_perr("Failed to exit serial debug mode (1), ignoring\n");
382 	}
383 
384 	ret = write_command(port, DEBUG_PORT, 0x45, NULL, 0);
385 	if (ret) {
386 		msg_perr("Failed to exit serial debug mode (2), ignoring\n");
387 	}
388 
389 	ret = write_command(port, ISP_PORT, 0x24, NULL, 0);
390 	if (ret) {
391 		msg_perr("Failed to exit ISP mode command, ignoring\n");
392 	}
393 
394 	return 0;
395 }
396 
mediatek_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const uint8_t * writearr,uint8_t * readarr)397 static int mediatek_send_command(const struct flashctx *flash,
398 	unsigned int writecnt, unsigned int readcnt,
399 	const uint8_t *writearr, uint8_t *readarr)
400 {
401 	const struct mediatek_data *port = get_data_from_context(flash);
402 	if (!port) {
403 		msg_perr("Failed to extract chip data for ISP command\n");
404 		return SPI_GENERIC_ERROR;
405 	}
406 
407 	int ret;
408 
409 	if (writecnt) {
410 		ret = write_command(port, ISP_PORT, MTK_CMD_WRITE,
411 			writearr, writecnt);
412 		if (ret) {
413 			msg_perr("Failed to issue ISP write command\n");
414 			return ret;
415 		}
416 	}
417 
418 	if (readcnt) {
419 		size_t len = readcnt;
420 		ret = read_raw(port, ISP_PORT, readarr, len);
421 		if (ret < 0) {
422 			msg_perr("Failed to read ISP command result\n");
423 			return ret;
424 		}
425 
426 		if (ret != (int)readcnt) {
427 			msg_perr("Read length mismatched: expected %u got %d\n", readcnt, ret);
428 			return SPI_INVALID_LENGTH;
429 		}
430 	}
431 
432 	// End the current command.
433 	ret = write_command(port, ISP_PORT, MTK_CMD_END, NULL, 0);
434 	if (ret) {
435 		msg_perr("Failed to end ISP command\n");
436 		return ret;
437 	}
438 
439 	return 0;
440 }
441 
mediatek_shutdown(void * data)442 static int mediatek_shutdown(void *data)
443 {
444 	int ret = 0;
445 	struct mediatek_data *port = (struct mediatek_data *)data;
446 
447 	ret |= mediatek_exit_isp(port);
448 	i2c_close(port->fd);
449 	free(data);
450 
451 	return ret;
452 }
453 
454 static const struct spi_master spi_master_i2c_mediatek = {
455 	.max_data_read	= I2C_SMBUS_BLOCK_MAX,
456 	// Leave room for 1-byte command and up to a 4-byte address.
457 	.max_data_write	= I2C_SMBUS_BLOCK_MAX - 5,
458 	.command	= mediatek_send_command,
459 	.read		= default_spi_read,
460 	.write_256	= default_spi_write_256,
461 	.shutdown	= mediatek_shutdown,
462 };
463 
get_params(const struct programmer_cfg * cfg,bool * allow_brick)464 static int get_params(const struct programmer_cfg *cfg, bool *allow_brick)
465 {
466 	char *brick_str = NULL;
467 	int ret = 0;
468 
469 	*allow_brick = false; /* Default behaviour is to bail. */
470 	brick_str = extract_programmer_param_str(cfg, "allow_brick");
471 	if (brick_str) {
472 		if (!strcmp(brick_str, "yes")) {
473 			*allow_brick = true;
474 		} else {
475 			msg_perr("%s: Incorrect param format, allow_brick=yes.\n", __func__);
476 			ret = SPI_GENERIC_ERROR;
477 		}
478 	}
479 	free(brick_str);
480 
481 	return ret;
482 }
483 
mediatek_init(const struct programmer_cfg * cfg)484 static int mediatek_init(const struct programmer_cfg *cfg)
485 {
486 	int ret;
487 	bool allow_brick;
488 
489 	if (get_params(cfg, &allow_brick))
490 		return SPI_GENERIC_ERROR;
491 
492 	/*
493 	 * TODO: Once board_enable can facilitate safe i2c allow listing
494 	 * 	 then this can be removed.
495 	 */
496 	if (!allow_brick) {
497 		msg_perr("%s: For i2c drivers you must explicitly 'allow_brick=yes'. ", __func__);
498 		msg_perr("There is currently no way to determine if the programmer works on a board "
499 			 "as i2c device address space can be overloaded. Set 'allow_brick=yes' if "
500 			 "you are sure you know what you are doing.\n");
501 		return SPI_GENERIC_ERROR;
502 	}
503 
504 	int fd = i2c_open_from_programmer_params(cfg, ISP_PORT, 0);
505 	if (fd < 0) {
506 		msg_perr("Failed to open i2c\n");
507 		return fd;
508 	}
509 
510 	struct mediatek_data *port = calloc(1, sizeof(*port));
511 	if (!port) {
512 		msg_perr("Unable to allocate space for SPI master data\n");
513 		i2c_close(fd);
514 		return SPI_GENERIC_ERROR;
515 	}
516 	port->fd = fd;
517 
518 	ret = ioctl(fd, I2C_FUNCS, &(port->funcs));
519 	if (ret) {
520 		msg_perr("Failed to fetch I2C bus functionality\n");
521 		free(port);
522 		i2c_close(fd);
523 		return ret;
524 	}
525 
526 	ret = mediatek_enter_isp(port);
527 	if (ret) {
528 		msg_perr("Failed to enter ISP mode\n");
529 		free(port);
530 		i2c_close(fd);
531 		return ret;
532 	}
533 
534 	return register_spi_master(&spi_master_i2c_mediatek, port);
535 }
536 
537 const struct programmer_entry programmer_mediatek_i2c_spi = {
538 	.name			= "mediatek_i2c_spi",
539 	.type			= OTHER,
540 	.devs.note		= "Device files /dev/i2c-*\n",
541 	.init			= mediatek_init,
542 };
543