Shiyu Sun has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176. ......................................................................
lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 548 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/1
diff --git a/Makefile b/Makefile index aa77a64..298890e 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,11 @@ else override CONFIG_STLINKV3_SPI = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif # libjaylink is also not available for DOS ifeq ($(CONFIG_JLINK_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_JLINK_SPI=yes @@ -306,6 +311,11 @@ else override CONFIG_SATAMV = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif endif
ifneq ($(TARGET_OS), MinGW) @@ -381,6 +391,11 @@ else override CONFIG_STLINKV3_SPI = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif ifeq ($(CONFIG_CH341A_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_CH341A_SPI=yes else @@ -656,6 +671,9 @@ # Always enable STLink V3 CONFIG_STLINKV3_SPI ?= yes
+# Always enable I2C SPI +CONFIG_LSPCON_I2C_SPI ?= yes + # Always enable dummy tracing for now. CONFIG_DUMMY ?= yes
@@ -735,6 +753,7 @@ override CONFIG_DEVELOPERBOX_SPI = no override CONFIG_PICKIT2_SPI = no override CONFIG_STLINKV3_SPI = no +override CONFIG_LSPCON_I2C_SPI = no endif ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no) override CONFIG_INTERNAL = no @@ -913,6 +932,12 @@ NEED_LIBUSB1 += CONFIG_STLINKV3_SPI endif
+ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +FEATURE_CFLAGS += -D'CONFIG_LSPCON_I2C_SPI=1' +PROGRAMMER_OBJS += lspcon_i2c_spi.o +NEED_LIBUSB1 += CONFIG_LSPCON_I2C_SPI +endif + ifneq ($(NEED_LIBFTDI), ) FTDILIBS := $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)" ; $(PKG_CONFIG) --libs libftdi1 || $(PKG_CONFIG) --libs libftdi || printf "%s" "-lftdi -lusb") FEATURE_CFLAGS += $(call debug_shell,grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") diff --git a/flashrom.c b/flashrom.c index e541b68..3fc705a 100644 --- a/flashrom.c +++ b/flashrom.c @@ -389,6 +389,18 @@ }, #endif
+#if CONFIG_LSPCON_I2C_SPI == 1 + { + .name = "lspcon_i2c_spi", + .type = OTHER, + .devs.note = "Device files /dev/i2c-*.\n", + .init = lspcon_i2c_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + #if CONFIG_USBBLASTER_SPI == 1 { .name = "usbblaster_spi", diff --git a/lspcon_i2c_spi.c b/lspcon_i2c_spi.c new file mode 100644 index 0000000..d56da92 --- /dev/null +++ b/lspcon_i2c_spi.c @@ -0,0 +1,499 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2020 The Chromium OS Authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <errno.h> + +#include "programmer.h" +#include "spi.h" +#include "i2c_helper.h" + +#define REGISTER_ADDRESS (0x94 >> 1) +#define PAGE_ADDRESS (0x9e >> 1) +#define PAGE_SIZE 256 +#define READ_SIZE 32 +#define MAX_SPI_WAIT_RETRIES 1000 +#define FUNCTION_ERR -1 + +#define CLT2_SPI 0x82 +#define SPIEDID_BASE_ADDR2 0x8d +#define ROMADDR_BYTE1 0x8e +#define ROMADDR_BYTE2 0x8f +#define SWSPI_WDATA 0x90 + #define SWSPI_WDATA_CLEAR_STATUS 0x00 + #define SWSPI_WDATA_WRITE_REGISTER 0x01 + #define SWSPI_WDATA_READ_REGISTER 0x05 + #define SWSPI_WDATA_ENABLE_REGISTER 0x06 + #define SWSPI_WDATA_SECTOR_ERASE 0x20 + #define SWSPI_WDATA_PROTECT_BP 0x8c +#define SWSPI_RDATA 0x91 +#define SWSPI_LEN 0x92 +#define SWSPICTL 0x93 + #define SWSPICTL_ACCESS_TRIGGER 1 + #define SWSPICTL_CLEAR_PTR (1 << 1) + #define SWSPICTL_NO_READ (1 << 2) + #define SWSPICTL_ENABLE_READBACK (1 << 3) + #define SWSPICTL_MOT (1 << 4) +#define SPISTATUS 0x9e + #define SPISTATUS_BYTE_PROGRAM_FINISHED 0 + #define SPISTATUS_BYTE_PROGRAM_IN_IF 1 + #define SPISTATUS_BYTE_PROGRAM_SEND_DONE (1 << 1) + #define SPISTATUS_SECTOR_ERASE_FINISHED 0 + #define SPISTATUS_SECTOR_ERASE_IN_IF (1 << 2) + #define SPISTATUS_SECTOR_ERASE_SEND_DONE (1 << 3) + #define SPISTATUS_CHIP_ERASE_FINISHED 0 + #define SPISTATUS_CHIP_ERASE_IN_IF (1 << 4) + #define SPISTATUS_CHIP_ERASE_SEND_DONE (1 << 5) + #define SPISTATUS_FW_UPDATE_ENABLE (1 << 6) +#define WRITE_PROTECTION 0xb3 + #define WRITE_PROTECTION_ON 0 + #define WRITE_PROTECTION_OFF 0x10 +#define MPU 0xbc +#define PAGE_HW_WRITE 0xda + #define PAGE_HW_WRITE_DISABLE 0 + #define PAGE_HW_COFIG_REGISTER 0xaa + #define PAGE_HW_WRITE_ENABLE 0x55 + +struct lspcon_i2c_spi_data { + int fd; +}; + +typedef struct { + uint8_t command; + uint8_t data_size; + const uint8_t *data; + uint8_t control; +} packet_t; + +static int lspcon_i2c_spi_write_data(int fd, uint16_t addr, void *buf, uint16_t len) +{ + i2c_buffer_t data; + if (i2c_buffer_t_fill(&data, buf, len)) + return FUNCTION_ERR; + + return i2c_write(fd, addr, &data) == len ? 0 : FUNCTION_ERR; +} + +static int lspcon_i2c_spi_read_data(int fd, uint16_t addr, void *buf, uint16_t len) +{ + i2c_buffer_t data; + if (i2c_buffer_t_fill(&data, buf, len)) + return FUNCTION_ERR; + + return i2c_read(fd, addr, &data) == len ? 0 : FUNCTION_ERR; +} + +static int get_fd_from_context(struct flashctx *flash) +{ + if (!flash || !flash->mst || !flash->mst->spi.data) { + msg_perr("Unable to extract fd from flash context.\n"); + return FUNCTION_ERR; + } + + return ((const struct lspcon_i2c_spi_data *)flash->mst->spi.data)->fd; +} + +static int lspcon_i2c_spi_write_register(int fd, uint8_t i2c_register, uint8_t value) +{ + uint8_t command[] = { i2c_register, value }; + return lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 2); +} + +static int lspcon_i2c_spi_read_register(int fd, uint8_t i2c_register, uint8_t *value) +{ + uint8_t command[] = { i2c_register }; + int ret = lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 1); + ret |= lspcon_i2c_spi_read_data(fd, REGISTER_ADDRESS, value, 1); + + return ret ? FUNCTION_ERR : 0; +} + +static int lspcon_i2c_spi_register_control(int fd, packet_t *packet) +{ + int i; + int ret = lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->command); + if (ret) + return ret; + + /* Higher 4 bits are read size. */ + int write_size = packet->data_size & 0x0f; + for (i = 0; i < write_size; ++i) { + ret |= lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->data[i]); + } + + ret |= lspcon_i2c_spi_write_register(fd, SWSPI_LEN, packet->data_size); + ret |= lspcon_i2c_spi_write_register(fd, SWSPICTL, packet->control); + + return ret; +} + +static int lspcon_i2c_spi_wait_command_done(int fd, unsigned int offset, int mask) +{ + uint8_t val; + int tried = 0; + int ret = 0; + do { + ret |= lspcon_i2c_spi_read_register(fd, offset, &val); + } while(!ret && (val & mask) && ++tried < MAX_SPI_WAIT_RETRIES); + + if (tried == MAX_SPI_WAIT_RETRIES) { + msg_perr("Error: Time out on sending command.\n"); + return -MAX_SPI_WAIT_RETRIES; + } + + return (val & mask) ? FUNCTION_ERR : ret; +} + +static int lspcon_i2c_spi_wait_rom_free(int fd) +{ + uint8_t val; + int tried = 0; + int ret = 0; + ret |= lspcon_i2c_spi_wait_command_done(fd, SPISTATUS, + SPISTATUS_SECTOR_ERASE_IN_IF | SPISTATUS_SECTOR_ERASE_SEND_DONE); + if (ret) + return ret; + + do { + packet_t packet = { SWSPI_WDATA_READ_REGISTER, 0, NULL, SWSPICTL_ACCESS_TRIGGER }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER); + ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &val); + } while (!ret && (val & SWSPICTL_ACCESS_TRIGGER) && ++tried < MAX_SPI_WAIT_RETRIES); + + if (tried == MAX_SPI_WAIT_RETRIES) { + msg_perr("Error: Time out on waiting ROM free.\n"); + return -MAX_SPI_WAIT_RETRIES; + } + + return (val & SWSPICTL_ACCESS_TRIGGER) ? FUNCTION_ERR : ret; +} + +static int lspcon_i2c_spi_toggle_register_protection(int fd, int toggle) +{ + return lspcon_i2c_spi_write_register(fd, WRITE_PROTECTION, + toggle ? WRITE_PROTECTION_OFF : WRITE_PROTECTION_ON); +} + +static int lspcon_i2c_spi_enable_write_status_register(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + packet_t packet = { + SWSPI_WDATA_ENABLE_REGISTER, 0, NULL, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_enable_write_status_register_protection(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + uint8_t data[] = { SWSPI_WDATA_PROTECT_BP }; + packet_t packet = { + SWSPI_WDATA_WRITE_REGISTER, 1, data, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_disable_protection(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + uint8_t data[] = { SWSPI_WDATA_CLEAR_STATUS }; + packet_t packet = { + SWSPI_WDATA_WRITE_REGISTER, 1, &data[0], SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_disable_hw_write(int fd) +{ + return lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_DISABLE); +} + +static int lspcon_i2c_spi_enable_write_protection(int fd) +{ + int ret = lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_enable_write_status_register_protection(fd); + ret |= lspcon_i2c_spi_wait_rom_free(fd); + ret |= lspcon_i2c_spi_disable_hw_write(fd); + + return ret; +} + +static int lspcon_i2c_spi_disable_all_protection(int fd) +{ + int ret = lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_disable_protection(fd); + ret |= lspcon_i2c_spi_wait_rom_free(fd); + + return ret; +} + +static int lspcon_i2c_spi_send_command(struct flashctx *flash, + unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned int i; + if (writecnt > 16 || readcnt > 16 || writecnt == 0) { + msg_perr("Error: Invalid read/write count for send command.\n"); + return FUNCTION_ERR; + } + + int fd = get_fd_from_context(flash); + if (fd < 0) + return FUNCTION_ERR; + + int ret = lspcon_i2c_spi_disable_all_protection(fd); + ret |= lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 1); + + /* First bit of writearr shuld be the command value, followed by the value to write. + Read length occupies 4 bit and represents 16 level, thus if read 1 bit, + read length should be set 0. */ + packet_t packet = { + writearr[0], (writecnt - 1) | ((readcnt - 1) << 4), &writearr[1], + SWSPICTL_ACCESS_TRIGGER | (readcnt ? 0 : SWSPICTL_NO_READ), + }; + + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + if (ret) + return ret; + + for (i = 0; i < readcnt; ++i) { + ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &readarr[i]); + } + + ret |= lspcon_i2c_spi_wait_rom_free(fd); + + return ret; +} + +static int lspcon_i2c_spi_enable_hw_write(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_COFIG_REGISTER); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_ENABLE); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x50); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x41); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x52); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x44); + + return ret; +} + +static int lspcon_i2c_clt2_spi_reset(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x20); + struct timespec wait_100_ms = { 0, 100000000 }; + nanosleep(&wait_100_ms, NULL); + ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x00); + + return ret; +} + +static int lspcon_i2c_spi_reset_mpu_stop(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, MPU, 0xc0); // cmd mode + ret |= lspcon_i2c_spi_write_register(fd, MPU, 0x40); // stop mcu + + return ret; +} + +static int lspcon_i2c_spi_map_page(int fd, unsigned int offset) +{ + /* Page number byte, need to / PAGE_SIZE. */ + uint8_t command_byte1[] = { ROMADDR_BYTE1, (offset >> 8) & 0xff }; + uint8_t command_byte2[] = { ROMADDR_BYTE2, (offset >> 16) }; + int ret = 0; + ret |= lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command_byte1, 2); + ret |= lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command_byte2, 2); + + return ret ? FUNCTION_ERR : 0; +} + +static int lspcon_i2c_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) +{ + unsigned int i; + int ret = 0; + if (start & 0xff) + return default_spi_read(flash, buf, start, len); + + int fd = get_fd_from_context(flash); + if (fd < 0) + return FUNCTION_ERR; + + for (i = 0; i < len; i += PAGE_SIZE) { + ret |= lspcon_i2c_spi_map_page(fd, start + i); + ret |= lspcon_i2c_spi_read_data(fd, PAGE_ADDRESS, buf + i, min(len - i, PAGE_SIZE)); + } + + return ret; +} + +static int lspcon_i2c_spi_write_page(int fd, const uint8_t *buf, unsigned int len) +{ + uint8_t write_buffer[len + 1]; + write_buffer[0] = 0; + memcpy(write_buffer + 1, buf, len); + + return lspcon_i2c_spi_write_data(fd, PAGE_ADDRESS, write_buffer, len + 1); +} + +static int lspcon_i2c_spi_write_256(struct flashctx *flash, const uint8_t *buf, + unsigned int start, unsigned int len) +{ + int ret = 0; + if (start & 0xff) + return default_spi_write_256(flash, buf, start, len); + + int fd = get_fd_from_context(flash); + if (fd < 0) + return FUNCTION_ERR; + + ret |= lspcon_i2c_spi_disable_all_protection(fd); + /* Enable hardware write and reset clt2SPI interface. */ + ret |= lspcon_i2c_spi_enable_hw_write(fd); + ret |= lspcon_i2c_clt2_spi_reset(fd); + + for (unsigned int i = 0; i < len; i += PAGE_SIZE) { + ret |= lspcon_i2c_spi_map_page(fd, start + i); + ret |= lspcon_i2c_spi_write_page(fd, buf + i, min(len - i, PAGE_SIZE)); + } + + ret |= lspcon_i2c_spi_enable_write_protection(fd); + ret |= lspcon_i2c_spi_disable_hw_write(fd); + + return ret; +} + +static int lspcon_i2c_spi_write_aai(struct flashctx *flash, const uint8_t *buf, + unsigned int start, unsigned int len) +{ + msg_perr("Error: AAI write function is not supported.\n"); + return FUNCTION_ERR; +} + +static const struct spi_master spi_master_i2c_lspcon = { + .max_data_read = 256, + .max_data_write = 256, + .command = lspcon_i2c_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = lspcon_i2c_spi_read, + .write_256 = lspcon_i2c_spi_write_256, + .write_aai = lspcon_i2c_spi_write_aai, +}; + +/* TODO: MPU still stop at this point, probably need to reset it. */ +static int lspcon_i2c_spi_shutdown(void *data) +{ + int ret = 0; + int fd = ((struct lspcon_i2c_spi_data *)data)->fd; + ret |= lspcon_i2c_spi_enable_write_protection(fd); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + i2c_close(fd); + free(data); + + return ret; +} + +/* TODO: remove this out of the specific spi master implementation. */ +static int get_bus() +{ + char *bus_str = extract_programmer_param("bus"); + int ret = FUNCTION_ERR; + if (bus_str) { + char *bus_suffix; + errno = 0; + int bus = (int)strtol(bus_str, &bus_suffix, 10); + if (errno != 0 || bus_str == bus_suffix) { + msg_perr("Error: Could not convert 'bus'.\n"); + goto get_bus_done; + } + + if (bus < 0 || bus > 255) { + msg_perr("Error: Value for 'bus' is out of range(0-255).\n"); + goto get_bus_done; + } + + if (strlen(bus_suffix) > 0) { + msg_perr("Error: Garbage following 'bus' value.\n"); + goto get_bus_done; + } + + msg_pinfo("Using i2c bus %i.\n", bus); + ret = bus; + goto get_bus_done; + } else { + msg_perr("Error: Bus number not specified.\n"); + } +get_bus_done: + if (bus_str) + free(bus_str); + + return ret; +} + +static int register_lspcon_i2c_spi_master(void *ptr) +{ + struct spi_master mst = spi_master_i2c_lspcon; + mst.data = ptr; + + return register_spi_master(&mst); +} + +int lspcon_i2c_spi_init(void) +{ + int lspcon_i2c_spi_bus = get_bus(); + if (lspcon_i2c_spi_bus < 0) + return FUNCTION_ERR; + + int ret = 0; + int fd = i2c_open(lspcon_i2c_spi_bus, REGISTER_ADDRESS, 0); + if (fd < 0) + return fd; + + ret |= lspcon_i2c_spi_reset_mpu_stop(fd); + if (ret) + return ret; + + struct lspcon_i2c_spi_data data = { fd }; + void *data_ptr = calloc(1, sizeof(data)); + if (!data_ptr) { + msg_perr("Unable to allocate space for extra spi master data.\n"); + return FUNCTION_ERR; + } + + memcpy(data_ptr, &data, sizeof(data)); + ret |= register_shutdown(lspcon_i2c_spi_shutdown, data_ptr); + ret |= register_lspcon_i2c_spi_master(data_ptr); + + return ret; +} diff --git a/meson.build b/meson.build index b586d9a..7494c51 100644 --- a/meson.build +++ b/meson.build @@ -63,6 +63,7 @@ config_serprog = get_option('config_serprog') config_usbblaster_spi = get_option('config_usbblaster_spi') config_stlinkv3_spi = get_option('config_stlinkv3_spi') +config_lspcon_i2c_spi = get_option('config_lspcon_i2c_spi') config_linux_i2c_helper = get_option('config_linux_i2c_helper')
cargs = [] @@ -284,6 +285,10 @@ srcs += 'stlinkv3_spi.c' cargs += '-DCONFIG_STLINKV3_SPI=1' endif +if config_lspcon_i2c_spi + srcs += 'lspcon_i2c_spi.c' + cargs += '-DCONFIG_LSPCON_I2C_SPI=1' +endif
# bitbanging SPI infrastructure if config_bitbang_spi diff --git a/meson_options.txt b/meson_options.txt index ff4a786..e4b4fa9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -35,4 +35,5 @@ option('config_serprog', type : 'boolean', value : true, description : 'serprog') option('config_usbblaster_spi', type : 'boolean', value : true, description : 'Altera USB-Blaster dongles') option('config_stlinkv3_spi', type : 'boolean', value : true, description : 'STMicroelectronics STLINK-V3') +option('config_lspcon_i2c_spi', type : 'boolean', value : true, description : 'SPI control from I2C bus') option('config_linux_i2c_helper', type: 'boolean', value : true, description : 'Linux I2C control') diff --git a/programmer.h b/programmer.h index 08500c6..d47caf3 100644 --- a/programmer.h +++ b/programmer.h @@ -130,6 +130,9 @@ #if CONFIG_STLINKV3_SPI == 1 PROGRAMMER_STLINKV3_SPI, #endif +#if CONFIG_LSPCON_I2C_SPI == 1 + PROGRAMMER_LSPCON_I2C_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -810,4 +813,7 @@ struct libusb_device_handle *usb_dev_get_by_vid_pid_number( struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num);
+/* lspcon_i2c_spi.c */ +int lspcon_i2c_spi_init(void); + #endif /* !__PROGRAMMER_H__ */
Hello build bot (Jenkins), Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#3).
Change subject: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176. ......................................................................
lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 548 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/3
Paul Menzel has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176. ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG@7 PS3, Line 7: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176. Please remove the dot/period at the end of the commit message summary.
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176. ......................................................................
Patch Set 3:
(8 comments)
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG@7 PS3, Line 7: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176.
Please remove the dot/period at the end of the commit message summary.
You can move this down into the body and have a shorter summary line:
``` lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parades lspcon usb-c to dp protocol translator part that is i2c-controlled. The support allows the host to reach the SPI rom that hangs off the part where it stores its firmware. ```
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@33 PS3, Line 33: #define FUNCTION_ERR -1 use flashrom enum of native error codes.
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@80 PS3, Line 80: uint8_t data_size; : const uint8_t *data; swap these two for readability?
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@105 PS3, Line 105: if (!flash || !flash->mst || !flash->mst->spi.data) { under what conditions is this true in practice?
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@110 PS3, Line 110: (const struct lspcon_i2c_spi_data *)flash->mst->spi.data case to an intermediate and then extract.
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@418 PS3, Line 418: int fd = ((struct lspcon_i2c_spi_data *)data)->fd; cast it then extract the value.
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@487 PS3, Line 487: struct lspcon_i2c_spi_data data = { fd }; : void *data_ptr = calloc(1, sizeof(data)); just calloc the heap and set the member, avoid the memcpy().
``` struct lspcon_i2c_spi_data * data = calloc(1, sizeof(struct lspcon_i2c_spi_data)); data->fd = fd; ```
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@500 PS3, Line 500: trim \n
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#4).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 550 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/4
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 4:
(8 comments)
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/flashrom/+/39687/3//COMMIT_MSG@7 PS3, Line 7: lspcon_i2c_spi.c: Add support for the i2c-controlled SPI master in PS175/176.
You can move this down into the body and have a shorter summary line: […]
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@33 PS3, Line 33: #define FUNCTION_ERR -1
use flashrom enum of native error codes.
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@80 PS3, Line 80: uint8_t data_size; : const uint8_t *data;
swap these two for readability?
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@105 PS3, Line 105: if (!flash || !flash->mst || !flash->mst->spi.data) {
under what conditions is this true in practice?
Most likely this won't be true, but this prevent some cases that `register_lspcon_i2c_spi_master` might not register customized master with proper data.
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@110 PS3, Line 110: (const struct lspcon_i2c_spi_data *)flash->mst->spi.data
case to an intermediate and then extract.
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@418 PS3, Line 418: int fd = ((struct lspcon_i2c_spi_data *)data)->fd;
cast it then extract the value.
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@487 PS3, Line 487: struct lspcon_i2c_spi_data data = { fd }; : void *data_ptr = calloc(1, sizeof(data));
just calloc the heap and set the member, avoid the memcpy(). […]
Done
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@500 PS3, Line 500:
trim \n
I am pretty sure there is no new line at the end, is that just a display issue?
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 4: Code-Review+2
(5 comments)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@314 PS4, Line 314: 100000000 `(unsigned)1e8` is more readable.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@314 PS4, Line 314: wait_100_ms wait_100ms
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@364 PS4, Line 364: uint8_t write_buffer[len + 1]; I find these VLA usages and clever ptr arithmetic to idx after the few elem a little unsettling. I guess i'll let it fly here.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@415 PS4, Line 415: stop stopped
https://review.coreboot.org/c/flashrom/+/39687/4/meson_options.txt File meson_options.txt:
https://review.coreboot.org/c/flashrom/+/39687/4/meson_options.txt@38 PS4, Line 38: true Do we perhaps want to default to false as the i2c helper only currently supports Linux and thus would break builds on the BSD's with missing symbols at link-time.
Also the desc needs changing: 'Parade lspcon USB-C to HDMI protocol translator'
Sam McNally has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 4:
(5 comments)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@270 PS4, Line 270: int ret = lspcon_i2c_spi_disable_all_protection(fd); Are you sure all of this is necessary for every command and that none of this duplicates commands that the other parts of flashrom's SPI infrastructure will generate?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@275 PS4, Line 275: bit byte
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@333 PS4, Line 333: uint8_t command_byte1[] = { ROMADDR_BYTE1, (offset >> 8) & 0xff }; Given ROMADDR_BYTE1 and ROMADDR_BYTE2 are adjacent, can this not be done in a single write? Otherwise, this should use lspcon_i2c_spi_write_register.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@406 PS4, Line 406: 256 Are you sure about these?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@431 PS4, Line 431: () (void)
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 4:
(6 comments)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@39 PS4, Line 39: #define SWSPI_WDATA_CLEAR_STATUS How about adding an extra space between `#define` and the macro name? #define SWSPI_WDATA 0x90 #define SWSPI_WDATA_CLEAR_STATUS 0x00
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@314 PS4, Line 314: 100000000
`(unsigned)1e8` is more readable.
Or (100 * 1000 * 1000)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@364 PS4, Line 364: uint8_t write_buffer[len + 1];
I find these VLA usages and clever ptr arithmetic to idx after the few elem a little unsettling. […]
This is quite unsettling, indeed. Is there any reason to not use a fixed-size buffer?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@365 PS4, Line 365: write_buffer[0] = 0 Why the special treatment for position zero?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@492 PS4, Line 492: spi SPI
https://review.coreboot.org/c/flashrom/+/39687/4/programmer.h File programmer.h:
https://review.coreboot.org/c/flashrom/+/39687/4/programmer.h@818 PS4, Line 818: Shouldn't this be guarded like on line 579?
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#5).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 550 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/5
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 4:
(13 comments)
https://review.coreboot.org/c/flashrom/+/39687/5/Makefile File Makefile:
https://review.coreboot.org/c/flashrom/+/39687/5/Makefile@675 PS5, Line 675: CONFIG_LSPCON_I2C_SPI ?= yes Sorry forgot to make this as false. Will update on next iteration.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@39 PS4, Line 39: #define SWSPI_WDATA_CLEAR_STATUS
How about adding an extra space between `#define` and the macro name? […]
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@275 PS4, Line 275: bit
byte
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@314 PS4, Line 314: wait_100_ms
wait_100ms
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@314 PS4, Line 314: 100000000
`(unsigned)1e8` is more readable.
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@333 PS4, Line 333: uint8_t command_byte1[] = { ROMADDR_BYTE1, (offset >> 8) & 0xff };
Given ROMADDR_BYTE1 and ROMADDR_BYTE2 are adjacent, can this not be done in a single write? Otherwis […]
Yes this can be done in a single write, I just want to separate them to make this clear. I will update this to use write_register if that's fine.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@365 PS4, Line 365: write_buffer[0] = 0
Why the special treatment for position zero?
I think it is the requirement for i2c data transfer to write the start offset before the write data, this is useful if the write has to be done slowly like 32 byte a time. Also make two separate write that send 0 first and followed by write data does not work. I would assume we will need to keep this, does it make sense?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@406 PS4, Line 406: 256
Are you sure about these?
Actually no, I have go through the code and looks like that applied to the send_command method eventually and thus this max value should be 16. While for the max write, I notice the value get passed in eventually as out_len here: https://github.com/flashrom/flashrom/blob/ef78de4a21323b8c459337356289218211..., that means the limit should be 16 - 4 is that correct?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@415 PS4, Line 415: stop
stopped
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@431 PS4, Line 431: ()
(void)
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@492 PS4, Line 492: spi
SPI
Done
https://review.coreboot.org/c/flashrom/+/39687/4/meson_options.txt File meson_options.txt:
https://review.coreboot.org/c/flashrom/+/39687/4/meson_options.txt@38 PS4, Line 38: true
Do we perhaps want to default to false as the i2c helper only currently supports Linux and thus woul […]
Done
https://review.coreboot.org/c/flashrom/+/39687/4/programmer.h File programmer.h:
https://review.coreboot.org/c/flashrom/+/39687/4/programmer.h@818 PS4, Line 818:
Shouldn't this be guarded like on line 579?
Done
Sam McNally has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 5:
(3 comments)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@333 PS4, Line 333: uint8_t command_byte1[] = { ROMADDR_BYTE1, (offset >> 8) & 0xff };
Yes this can be done in a single write, I just want to separate them to make this clear. […]
Ack
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@406 PS4, Line 406: 256
Actually no, I have go through the code and looks like that applied to the send_command method event […]
Sounds reasonable.
https://review.coreboot.org/c/flashrom/+/39687/5/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/5/lspcon_i2c_spi.c@31 PS5, Line 31: #define READ_SIZE 32 Remove.
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#6).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 550 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/6
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/c/flashrom/+/39687/5/Makefile File Makefile:
https://review.coreboot.org/c/flashrom/+/39687/5/Makefile@675 PS5, Line 675: CONFIG_LSPCON_I2C_SPI ?= yes
Sorry forgot to make this as false. Will update on next iteration.
Done
https://review.coreboot.org/c/flashrom/+/39687/5/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/5/lspcon_i2c_spi.c@31 PS5, Line 31: #define READ_SIZE 32
Remove.
Done
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#7).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
Tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 549 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/7
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7: Code-Review+2
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7:
(5 comments)
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@105 PS3, Line 105: if (!flash || !flash->mst || !flash->mst->spi.data) {
Most likely this won't be true, but this prevent some cases that `register_lspcon_i2c_spi_master` mi […]
Does it make sense or we want to remove the check?
https://review.coreboot.org/c/flashrom/+/39687/3/lspcon_i2c_spi.c@500 PS3, Line 500:
I am pretty sure there is no new line at the end, is that just a display issue?
Done
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@270 PS4, Line 270: int ret = lspcon_i2c_spi_disable_all_protection(fd);
Are you sure all of this is necessary for every command and that none of this duplicates commands th […]
Sorry thought I have replied this but somehow it's missing. On the tracking bug I think the vendor do state that we probably need to disable protection before every write attempt, as well as the register protection. As far as I know I didn't see there is any protection disable operation happens with the process. The only thing I noticed was https://github.com/flashrom/flashrom/blob/cd8aeba7f1cee4c2bd1f8598009fc3e6e7... defines a disable block protect function, but that only invoked inside some local function but seems not get called on flash process(?). Not sure if that make sense and Angel can you help verify that? Thanks!
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@364 PS4, Line 364: uint8_t write_buffer[len + 1];
This is quite unsettling, indeed. […]
We can use a fixed size buffer with buf[256 + 1] since that'd be the max size. But does it really helps lot?
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@365 PS4, Line 365: write_buffer[0] = 0
I think it is the requirement for i2c data transfer to write the start offset before the write data, […]
Do you have any idea if we have to change this or resolve the comment?
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7:
(3 comments)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@364 PS4, Line 364: uint8_t write_buffer[len + 1];
We can use a fixed size buffer with buf[256 + 1] since that'd be the max size. […]
You could have a static buffer of len 257 /* extra byte needed for prefixing zero in idx 0 */ and a if check to validate len does not exceed the static buffer before the memcpy()
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@365 PS4, Line 365: write_buffer[0] = 0
Do you have any idea if we have to change this or resolve the comment?
by initialising the static buf to zero you can skip this.
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@366 PS4, Line 366: write_buffer + 1 just say &write_buf[1] here, kind of makes it more clear.
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@270 PS4, Line 270: int ret = lspcon_i2c_spi_disable_all_protection(fd);
Sorry thought I have replied this but somehow it's missing. […]
ACK, will follow up with improvement if there are more comments comes in
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/flashrom/+/39687/4//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/flashrom/+/39687/4//COMMIT_MSG@18 PS4, Line 18: Tested with following commands, read/write/erase works good. BUG=b:xxx BRANCH=none TEST=..^what you said here.
That will allow this to get auto picked up when we sync it back into the ChromeOS flashrom tree, long term we can kill the fork however we are not quite there yet unfortunately. This is the same process as coreboot.
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/4/lspcon_i2c_spi.c@270 PS4, Line 270: int ret = lspcon_i2c_spi_disable_all_protection(fd);
ACK, will follow up with improvement if there are more comments comes in
Ack
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#8).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
BUG=b:148746232 BRANCH=none TEST=tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 551 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/8
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 8: Code-Review+2
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/flashrom/+/39687/8/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/8/lspcon_i2c_spi.c@364 PS8, Line 364: uint8_t write_buffer[PAGE_SIZE + 1] = { 0 }; put this before the if and you may want to add the code comment I provided before about the prefix of idx 0 needing to be set to zero or at least make careful note of it perhaps a line before the memcpy().
Hello build bot (Jenkins), Stefan Reinauer, Edward O'Callaghan,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/39687
to look at the new patch set (#9).
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
BUG=b:148746232 BRANCH=none TEST=tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 556 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/87/39687/9
Shiyu Sun has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 9:
(2 comments)
https://review.coreboot.org/c/flashrom/+/39687/4//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/flashrom/+/39687/4//COMMIT_MSG@18 PS4, Line 18: Tested with following commands, read/write/erase works good.
BUG=b:xxx […]
Done
https://review.coreboot.org/c/flashrom/+/39687/8/lspcon_i2c_spi.c File lspcon_i2c_spi.c:
https://review.coreboot.org/c/flashrom/+/39687/8/lspcon_i2c_spi.c@364 PS8, Line 364: uint8_t write_buffer[PAGE_SIZE + 1] = { 0 };
put this before the if and you may want to add the code comment I provided before about the prefix o […]
Done
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
Patch Set 9: Code-Review+2
Edward O'Callaghan has submitted this change. ( https://review.coreboot.org/c/flashrom/+/39687 )
Change subject: lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6} ......................................................................
lspcon_i2c_spi.c: Add SPI-master support for PS17{5,6}
This adds support for the Parade lspcon usb-c to HDMI protocol translater part that is i2c-controlled. The support allows the host to reach the SPI ROM that hangs off the part where it stores its firmware.
Usage is as follows: flashrom -p lspcon_i2c_spi:bus=X where X is the bus number.
BUG=b:148746232 BRANCH=none TEST=tested with following commands, read/write/erase works good. flashrom -p lspcon_i2c_spi:bus=7 -r /tmp/foo; flashrom -p lspcon_i2c_spi:bus=7 -E; flashrom -p lspcon_i2c_spi:bus=7 -w /tmp/foo;
Change-Id: I039e683252cfaf1ffef8694a3e8081b1b6b944f7 Signed-off-by: Shiyu Sun sshiyu@chromium.org Reviewed-on: https://review.coreboot.org/c/flashrom/+/39687 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Edward O'Callaghan quasisec@chromium.org --- M Makefile M flashrom.c A lspcon_i2c_spi.c M meson.build M meson_options.txt M programmer.h 6 files changed, 556 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Edward O'Callaghan: Looks good to me, approved
diff --git a/Makefile b/Makefile index 433d8f7..a533acf 100644 --- a/Makefile +++ b/Makefile @@ -195,6 +195,11 @@ else override CONFIG_STLINKV3_SPI = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif # libjaylink is also not available for DOS ifeq ($(CONFIG_JLINK_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_JLINK_SPI=yes @@ -306,6 +311,11 @@ else override CONFIG_SATAMV = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif endif
ifneq ($(TARGET_OS), MinGW) @@ -381,6 +391,11 @@ else override CONFIG_STLINKV3_SPI = no endif +ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes +else +override CONFIG_LSPCON_I2C_SPI = no +endif ifeq ($(CONFIG_CH341A_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_CH341A_SPI=yes else @@ -656,6 +671,9 @@ # Always enable STLink V3 CONFIG_STLINKV3_SPI ?= yes
+# Disables LSPCON support until the i2c helper supports multiple systems. +CONFIG_LSPCON_I2C_SPI ?= no + # Always enable dummy tracing for now. CONFIG_DUMMY ?= yes
@@ -736,6 +754,7 @@ override CONFIG_PICKIT2_SPI = no override CONFIG_RAIDEN = no override CONFIG_STLINKV3_SPI = no +override CONFIG_LSPCON_I2C_SPI = no endif ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no) override CONFIG_INTERNAL = no @@ -914,6 +933,12 @@ NEED_LIBUSB1 += CONFIG_STLINKV3_SPI endif
+ifeq ($(CONFIG_LSPCON_I2C_SPI), yes) +FEATURE_CFLAGS += -D'CONFIG_LSPCON_I2C_SPI=1' +PROGRAMMER_OBJS += lspcon_i2c_spi.o +NEED_LIBUSB1 += CONFIG_LSPCON_I2C_SPI +endif + ifneq ($(NEED_LIBFTDI), ) FTDILIBS := $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)" ; $(PKG_CONFIG) --libs libftdi1 || $(PKG_CONFIG) --libs libftdi || printf "%s" "-lftdi -lusb") FEATURE_CFLAGS += $(call debug_shell,grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") diff --git a/flashrom.c b/flashrom.c index 081b705..07ce734 100644 --- a/flashrom.c +++ b/flashrom.c @@ -389,6 +389,18 @@ }, #endif
+#if CONFIG_LSPCON_I2C_SPI == 1 + { + .name = "lspcon_i2c_spi", + .type = OTHER, + .devs.note = "Device files /dev/i2c-*.\n", + .init = lspcon_i2c_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + #if CONFIG_USBBLASTER_SPI == 1 { .name = "usbblaster_spi", diff --git a/lspcon_i2c_spi.c b/lspcon_i2c_spi.c new file mode 100644 index 0000000..4c85426 --- /dev/null +++ b/lspcon_i2c_spi.c @@ -0,0 +1,505 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2020 The Chromium OS Authors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <errno.h> + +#include "programmer.h" +#include "spi.h" +#include "i2c_helper.h" + +#define REGISTER_ADDRESS (0x94 >> 1) +#define PAGE_ADDRESS (0x9e >> 1) +#define PAGE_SIZE 256 +#define MAX_SPI_WAIT_RETRIES 1000 + +#define CLT2_SPI 0x82 +#define SPIEDID_BASE_ADDR2 0x8d +#define ROMADDR_BYTE1 0x8e +#define ROMADDR_BYTE2 0x8f +#define SWSPI_WDATA 0x90 + #define SWSPI_WDATA_CLEAR_STATUS 0x00 + #define SWSPI_WDATA_WRITE_REGISTER 0x01 + #define SWSPI_WDATA_READ_REGISTER 0x05 + #define SWSPI_WDATA_ENABLE_REGISTER 0x06 + #define SWSPI_WDATA_SECTOR_ERASE 0x20 + #define SWSPI_WDATA_PROTECT_BP 0x8c +#define SWSPI_RDATA 0x91 +#define SWSPI_LEN 0x92 +#define SWSPICTL 0x93 + #define SWSPICTL_ACCESS_TRIGGER 1 + #define SWSPICTL_CLEAR_PTR (1 << 1) + #define SWSPICTL_NO_READ (1 << 2) + #define SWSPICTL_ENABLE_READBACK (1 << 3) + #define SWSPICTL_MOT (1 << 4) +#define SPISTATUS 0x9e + #define SPISTATUS_BYTE_PROGRAM_FINISHED 0 + #define SPISTATUS_BYTE_PROGRAM_IN_IF 1 + #define SPISTATUS_BYTE_PROGRAM_SEND_DONE (1 << 1) + #define SPISTATUS_SECTOR_ERASE_FINISHED 0 + #define SPISTATUS_SECTOR_ERASE_IN_IF (1 << 2) + #define SPISTATUS_SECTOR_ERASE_SEND_DONE (1 << 3) + #define SPISTATUS_CHIP_ERASE_FINISHED 0 + #define SPISTATUS_CHIP_ERASE_IN_IF (1 << 4) + #define SPISTATUS_CHIP_ERASE_SEND_DONE (1 << 5) + #define SPISTATUS_FW_UPDATE_ENABLE (1 << 6) +#define WRITE_PROTECTION 0xb3 + #define WRITE_PROTECTION_ON 0 + #define WRITE_PROTECTION_OFF 0x10 +#define MPU 0xbc +#define PAGE_HW_WRITE 0xda + #define PAGE_HW_WRITE_DISABLE 0 + #define PAGE_HW_COFIG_REGISTER 0xaa + #define PAGE_HW_WRITE_ENABLE 0x55 + +struct lspcon_i2c_spi_data { + int fd; +}; + +typedef struct { + uint8_t command; + const uint8_t *data; + uint8_t data_size; + uint8_t control; +} packet_t; + +static int lspcon_i2c_spi_write_data(int fd, uint16_t addr, void *buf, uint16_t len) +{ + i2c_buffer_t data; + if (i2c_buffer_t_fill(&data, buf, len)) + return SPI_GENERIC_ERROR; + + return i2c_write(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR; +} + +static int lspcon_i2c_spi_read_data(int fd, uint16_t addr, void *buf, uint16_t len) +{ + i2c_buffer_t data; + if (i2c_buffer_t_fill(&data, buf, len)) + return SPI_GENERIC_ERROR; + + return i2c_read(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR; +} + +static int get_fd_from_context(struct flashctx *flash) +{ + if (!flash || !flash->mst || !flash->mst->spi.data) { + msg_perr("Unable to extract fd from flash context.\n"); + return SPI_GENERIC_ERROR; + } + const struct lspcon_i2c_spi_data *data = + (const struct lspcon_i2c_spi_data *)flash->mst->spi.data; + + return data->fd; +} + +static int lspcon_i2c_spi_write_register(int fd, uint8_t i2c_register, uint8_t value) +{ + uint8_t command[] = { i2c_register, value }; + return lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 2); +} + +static int lspcon_i2c_spi_read_register(int fd, uint8_t i2c_register, uint8_t *value) +{ + uint8_t command[] = { i2c_register }; + int ret = lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 1); + ret |= lspcon_i2c_spi_read_data(fd, REGISTER_ADDRESS, value, 1); + + return ret ? SPI_GENERIC_ERROR : 0; +} + +static int lspcon_i2c_spi_register_control(int fd, packet_t *packet) +{ + int i; + int ret = lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->command); + if (ret) + return ret; + + /* Higher 4 bits are read size. */ + int write_size = packet->data_size & 0x0f; + for (i = 0; i < write_size; ++i) { + ret |= lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->data[i]); + } + + ret |= lspcon_i2c_spi_write_register(fd, SWSPI_LEN, packet->data_size); + ret |= lspcon_i2c_spi_write_register(fd, SWSPICTL, packet->control); + + return ret; +} + +static int lspcon_i2c_spi_wait_command_done(int fd, unsigned int offset, int mask) +{ + uint8_t val; + int tried = 0; + int ret = 0; + do { + ret |= lspcon_i2c_spi_read_register(fd, offset, &val); + } while(!ret && (val & mask) && ++tried < MAX_SPI_WAIT_RETRIES); + + if (tried == MAX_SPI_WAIT_RETRIES) { + msg_perr("Error: Time out on sending command.\n"); + return -MAX_SPI_WAIT_RETRIES; + } + + return (val & mask) ? SPI_GENERIC_ERROR : ret; +} + +static int lspcon_i2c_spi_wait_rom_free(int fd) +{ + uint8_t val; + int tried = 0; + int ret = 0; + ret |= lspcon_i2c_spi_wait_command_done(fd, SPISTATUS, + SPISTATUS_SECTOR_ERASE_IN_IF | SPISTATUS_SECTOR_ERASE_SEND_DONE); + if (ret) + return ret; + + do { + packet_t packet = { SWSPI_WDATA_READ_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER); + ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &val); + } while (!ret && (val & SWSPICTL_ACCESS_TRIGGER) && ++tried < MAX_SPI_WAIT_RETRIES); + + if (tried == MAX_SPI_WAIT_RETRIES) { + msg_perr("Error: Time out on waiting ROM free.\n"); + return -MAX_SPI_WAIT_RETRIES; + } + + return (val & SWSPICTL_ACCESS_TRIGGER) ? SPI_GENERIC_ERROR : ret; +} + +static int lspcon_i2c_spi_toggle_register_protection(int fd, int toggle) +{ + return lspcon_i2c_spi_write_register(fd, WRITE_PROTECTION, + toggle ? WRITE_PROTECTION_OFF : WRITE_PROTECTION_ON); +} + +static int lspcon_i2c_spi_enable_write_status_register(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + packet_t packet = { + SWSPI_WDATA_ENABLE_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_enable_write_status_register_protection(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + uint8_t data[] = { SWSPI_WDATA_PROTECT_BP }; + packet_t packet = { + SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_disable_protection(int fd) +{ + int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1); + uint8_t data[] = { SWSPI_WDATA_CLEAR_STATUS }; + packet_t packet = { + SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ }; + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + + return ret; +} + +static int lspcon_i2c_spi_disable_hw_write(int fd) +{ + return lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_DISABLE); +} + +static int lspcon_i2c_spi_enable_write_protection(int fd) +{ + int ret = lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_enable_write_status_register_protection(fd); + ret |= lspcon_i2c_spi_wait_rom_free(fd); + ret |= lspcon_i2c_spi_disable_hw_write(fd); + + return ret; +} + +static int lspcon_i2c_spi_disable_all_protection(int fd) +{ + int ret = lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_disable_protection(fd); + ret |= lspcon_i2c_spi_wait_rom_free(fd); + + return ret; +} + +static int lspcon_i2c_spi_send_command(struct flashctx *flash, + unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned int i; + if (writecnt > 16 || readcnt > 16 || writecnt == 0) { + msg_perr("Error: Invalid read/write count for send command.\n"); + return SPI_GENERIC_ERROR; + } + + int fd = get_fd_from_context(flash); + if (fd < 0) + return SPI_GENERIC_ERROR; + + int ret = lspcon_i2c_spi_disable_all_protection(fd); + ret |= lspcon_i2c_spi_enable_write_status_register(fd); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 1); + + /* First byte of writearr shuld be the command value, followed by the value to write. + Read length occupies 4 bit and represents 16 level, thus if read 1 byte, + read length should be set 0. */ + packet_t packet = { + writearr[0], &writearr[1], (writecnt - 1) | ((readcnt - 1) << 4), + SWSPICTL_ACCESS_TRIGGER | (readcnt ? 0 : SWSPICTL_NO_READ), + }; + + ret |= lspcon_i2c_spi_register_control(fd, &packet); + ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + if (ret) + return ret; + + for (i = 0; i < readcnt; ++i) { + ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &readarr[i]); + } + + ret |= lspcon_i2c_spi_wait_rom_free(fd); + + return ret; +} + +static int lspcon_i2c_spi_enable_hw_write(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_COFIG_REGISTER); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_ENABLE); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x50); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x41); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x52); + ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x44); + + return ret; +} + +static int lspcon_i2c_clt2_spi_reset(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x20); + struct timespec wait_100ms = { 0, (unsigned)1e8 }; + nanosleep(&wait_100ms, NULL); + ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x00); + + return ret; +} + +static int lspcon_i2c_spi_reset_mpu_stop(int fd) +{ + int ret = 0; + ret |= lspcon_i2c_spi_write_register(fd, MPU, 0xc0); // cmd mode + ret |= lspcon_i2c_spi_write_register(fd, MPU, 0x40); // stop mcu + + return ret; +} + +static int lspcon_i2c_spi_map_page(int fd, unsigned int offset) +{ + int ret = 0; + /* Page number byte, need to / PAGE_SIZE. */ + ret |= lspcon_i2c_spi_write_register(fd, ROMADDR_BYTE1, (offset >> 8) & 0xff); + ret |= lspcon_i2c_spi_write_register(fd, ROMADDR_BYTE2, (offset >> 16)); + + return ret ? SPI_GENERIC_ERROR : 0; +} + +static int lspcon_i2c_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) +{ + unsigned int i; + int ret = 0; + if (start & 0xff) + return default_spi_read(flash, buf, start, len); + + int fd = get_fd_from_context(flash); + if (fd < 0) + return SPI_GENERIC_ERROR; + + for (i = 0; i < len; i += PAGE_SIZE) { + ret |= lspcon_i2c_spi_map_page(fd, start + i); + ret |= lspcon_i2c_spi_read_data(fd, PAGE_ADDRESS, buf + i, min(len - i, PAGE_SIZE)); + } + + return ret; +} + +static int lspcon_i2c_spi_write_page(int fd, const uint8_t *buf, unsigned int len) +{ + /** + * Using static buffer with maximum possible size, + * extra byte is needed for prefixing zero at index 0. + */ + uint8_t write_buffer[PAGE_SIZE + 1] = { 0 }; + if (len > PAGE_SIZE) + return SPI_GENERIC_ERROR; + + /* First byte represents the writing offset and should always be zero. */ + memcpy(&write_buffer[1], buf, len); + + return lspcon_i2c_spi_write_data(fd, PAGE_ADDRESS, write_buffer, len + 1); +} + +static int lspcon_i2c_spi_write_256(struct flashctx *flash, const uint8_t *buf, + unsigned int start, unsigned int len) +{ + int ret = 0; + if (start & 0xff) + return default_spi_write_256(flash, buf, start, len); + + int fd = get_fd_from_context(flash); + if (fd < 0) + return SPI_GENERIC_ERROR; + + ret |= lspcon_i2c_spi_disable_all_protection(fd); + /* Enable hardware write and reset clt2SPI interface. */ + ret |= lspcon_i2c_spi_enable_hw_write(fd); + ret |= lspcon_i2c_clt2_spi_reset(fd); + + for (unsigned int i = 0; i < len; i += PAGE_SIZE) { + ret |= lspcon_i2c_spi_map_page(fd, start + i); + ret |= lspcon_i2c_spi_write_page(fd, buf + i, min(len - i, PAGE_SIZE)); + } + + ret |= lspcon_i2c_spi_enable_write_protection(fd); + ret |= lspcon_i2c_spi_disable_hw_write(fd); + + return ret; +} + +static int lspcon_i2c_spi_write_aai(struct flashctx *flash, const uint8_t *buf, + unsigned int start, unsigned int len) +{ + msg_perr("Error: AAI write function is not supported.\n"); + return SPI_GENERIC_ERROR; +} + +static const struct spi_master spi_master_i2c_lspcon = { + .max_data_read = 16, + .max_data_write = 12, + .command = lspcon_i2c_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = lspcon_i2c_spi_read, + .write_256 = lspcon_i2c_spi_write_256, + .write_aai = lspcon_i2c_spi_write_aai, +}; + +/* TODO: MPU still stopped at this point, probably need to reset it. */ +static int lspcon_i2c_spi_shutdown(void *data) +{ + int ret = 0; + struct lspcon_i2c_spi_data *lspcon_data = + (struct lspcon_i2c_spi_data *)data; + int fd = lspcon_data->fd; + ret |= lspcon_i2c_spi_enable_write_protection(fd); + ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0); + i2c_close(fd); + free(data); + + return ret; +} + +/* TODO: remove this out of the specific SPI master implementation. */ +static int get_bus(void) +{ + char *bus_str = extract_programmer_param("bus"); + int ret = SPI_GENERIC_ERROR; + if (bus_str) { + char *bus_suffix; + errno = 0; + int bus = (int)strtol(bus_str, &bus_suffix, 10); + if (errno != 0 || bus_str == bus_suffix) { + msg_perr("Error: Could not convert 'bus'.\n"); + goto get_bus_done; + } + + if (bus < 0 || bus > 255) { + msg_perr("Error: Value for 'bus' is out of range(0-255).\n"); + goto get_bus_done; + } + + if (strlen(bus_suffix) > 0) { + msg_perr("Error: Garbage following 'bus' value.\n"); + goto get_bus_done; + } + + msg_pinfo("Using i2c bus %i.\n", bus); + ret = bus; + goto get_bus_done; + } else { + msg_perr("Error: Bus number not specified.\n"); + } +get_bus_done: + if (bus_str) + free(bus_str); + + return ret; +} + +static int register_lspcon_i2c_spi_master(void *ptr) +{ + struct spi_master mst = spi_master_i2c_lspcon; + mst.data = ptr; + + return register_spi_master(&mst); +} + +int lspcon_i2c_spi_init(void) +{ + int lspcon_i2c_spi_bus = get_bus(); + if (lspcon_i2c_spi_bus < 0) + return SPI_GENERIC_ERROR; + + int ret = 0; + int fd = i2c_open(lspcon_i2c_spi_bus, REGISTER_ADDRESS, 0); + if (fd < 0) + return fd; + + ret |= lspcon_i2c_spi_reset_mpu_stop(fd); + if (ret) + return ret; + + struct lspcon_i2c_spi_data *data = calloc(1, sizeof(struct lspcon_i2c_spi_data)); + if (!data) { + msg_perr("Unable to allocate space for extra SPI master data.\n"); + return SPI_GENERIC_ERROR; + } + + data->fd = fd; + ret |= register_shutdown(lspcon_i2c_spi_shutdown, data); + ret |= register_lspcon_i2c_spi_master(data); + + return ret; +} diff --git a/meson.build b/meson.build index b847c63..699370a 100644 --- a/meson.build +++ b/meson.build @@ -63,6 +63,7 @@ config_serprog = get_option('config_serprog') config_usbblaster_spi = get_option('config_usbblaster_spi') config_stlinkv3_spi = get_option('config_stlinkv3_spi') +config_lspcon_i2c_spi = get_option('config_lspcon_i2c_spi')
cargs = [] deps = [] @@ -283,6 +284,10 @@ srcs += 'stlinkv3_spi.c' cargs += '-DCONFIG_STLINKV3_SPI=1' endif +if config_lspcon_i2c_spi + srcs += 'lspcon_i2c_spi.c' + cargs += '-DCONFIG_LSPCON_I2C_SPI=1' +endif
# bitbanging SPI infrastructure if config_bitbang_spi diff --git a/meson_options.txt b/meson_options.txt index 2831271..a103dc6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -35,3 +35,4 @@ option('config_serprog', type : 'boolean', value : true, description : 'serprog') option('config_usbblaster_spi', type : 'boolean', value : true, description : 'Altera USB-Blaster dongles') option('config_stlinkv3_spi', type : 'boolean', value : true, description : 'STMicroelectronics STLINK-V3') +option('config_lspcon_i2c_spi', type : 'boolean', value : false, description : 'Parade lspcon USB-C to HDMI protocol translator') diff --git a/programmer.h b/programmer.h index 9a41be1..f6c5399 100644 --- a/programmer.h +++ b/programmer.h @@ -130,6 +130,9 @@ #if CONFIG_STLINKV3_SPI == 1 PROGRAMMER_STLINKV3_SPI, #endif +#if CONFIG_LSPCON_I2C_SPI == 1 + PROGRAMMER_LSPCON_I2C_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -811,4 +814,9 @@ struct libusb_device_handle *usb_dev_get_by_vid_pid_number( struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num);
+/* lspcon_i2c_spi.c */ +#if CONFIG_LSPCON_I2C_SPI == 1 +int lspcon_i2c_spi_init(void); +#endif + #endif /* !__PROGRAMMER_H__ */