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