Message ID | 20190202010510.25016-5-ajayg@nvidia.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add support for firmware update on Cypres CCGx | expand |
On Fri, Feb 01, 2019 at 05:05:08PM -0800, Ajay Gupta wrote: > From: Ajay Gupta <ajayg@nvidia.com> > > Adding support for below commands which will be used > during firmware flashing. > - ENTER_FLASHING > - RESET > - PDPORT_ENABLE > - JUMP_TO_BOOT > - FLASH_ROW_RW > - VALIDATE_FW > I command specific mutex lock is also added to sync > between driver and user threads. > > Signed-off-by: Ajay Gupta <ajayg@nvidia.com> > --- > Changes from v2 to v3 > - None > > drivers/usb/typec/ucsi/ucsi_ccg.c | 216 ++++++++++++++++++++++++++++++ > 1 file changed, 216 insertions(+) > > diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c > index 63b07b7d17f2..b9bbe90bdf57 100644 > --- a/drivers/usb/typec/ucsi/ucsi_ccg.c > +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c > @@ -30,13 +30,34 @@ enum enum_fw_mode { > #define PORT0_INT BIT(1) > #define PORT1_INT BIT(2) > #define UCSI_READ_INT BIT(7) > +#define CCGX_RAB_JUMP_TO_BOOT 0x0007 > +#define TO_BOOT 'J' > +#define TO_ALT_FW 'A' > +#define CCGX_RAB_RESET_REQ 0x0008 > +#define RESET_SIG 'R' > +#define CMD_RESET_I2C 0x0 > +#define CMD_RESET_DEV 0x1 > +#define CCGX_RAB_ENTER_FLASHING 0x000A > +#define FLASH_ENTER_SIG 'P' > +#define CCGX_RAB_VALIDATE_FW 0x000B > +#define CCGX_RAB_FLASH_ROW_RW 0x000C > +#define FLASH_SIG 'F' > +#define FLASH_RD_CMD 0x0 > +#define FLASH_WR_CMD 0x1 > +#define FLASH_FWCT1_WR_CMD 0x2 > +#define FLASH_FWCT2_WR_CMD 0x3 > +#define FLASH_FWCT_SIG_WR_CMD 0x4 > #define CCGX_RAB_READ_ALL_VER 0x0010 > #define CCGX_RAB_READ_FW2_VER 0x0020 > #define CCGX_RAB_UCSI_CONTROL 0x0039 > #define CCGX_RAB_UCSI_CONTROL_START BIT(0) > #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) > #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) > +#define REG_FLASH_RW_MEM 0x0200 > #define DEV_REG_IDX CCGX_RAB_DEVICE_MODE > +#define CCGX_RAB_PDPORT_ENABLE 0x002C > +#define PDPORT_1 BIT(0) > +#define PDPORT_2 BIT(1) > #define CCGX_RAB_RESPONSE 0x007E > #define ASYNC_EVENT BIT(7) > > @@ -47,6 +68,13 @@ enum enum_fw_mode { > #define PORT_DISCONNECT_DET 0x85 > #define ROLE_SWAP_COMPELETE 0x87 > > +/* ccg firmware */ > +#define CYACD_LINE_SIZE 527 > +#define CCG4_ROW_SIZE 256 > +#define FW1_METADATA_ROW 0x1FF > +#define FW2_METADATA_ROW 0x1FE > +#define FW_CFG_TABLE_SIG_SIZE 256 > + > struct ccg_dev_info { > #define CCG_DEVINFO_FWMODE_SHIFT (0) > #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) > @@ -118,6 +146,7 @@ struct ucsi_ccg { > struct ccg_resp dev_resp; > u8 cmd_resp; > int port_num; > + struct mutex lock; /* to sync between user and driver thread */ > }; > > static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) > @@ -431,6 +460,193 @@ static int ccg_send_command(struct ucsi_ccg *uc, struct ccg_cmd *cmd) > return uc->cmd_resp; > } > > +static int ccg_cmd_enter_flashing(struct ucsi_ccg *uc) > +{ > + struct ccg_cmd cmd; > + int ret; > + > + cmd.reg = CCGX_RAB_ENTER_FLASHING; > + cmd.data = FLASH_ENTER_SIG; > + cmd.len = 1; > + cmd.delay = 50; > + > + mutex_lock(&uc->lock); > + > + ret = ccg_send_command(uc, &cmd); > + > + mutex_unlock(&uc->lock); > + > + if (ret != CMD_SUCCESS) { > + dev_err(uc->dev, "enter flashing failed ret=%d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int ccg_cmd_reset(struct ucsi_ccg *uc, bool extra_delay) > +{ > + struct ccg_cmd cmd; > + u8 *p; > + int ret; > + > + p = (u8 *)&cmd.data; > + cmd.reg = CCGX_RAB_RESET_REQ; > + p[0] = RESET_SIG; > + p[1] = CMD_RESET_DEV; > + cmd.len = 2; > + cmd.delay = 2000 + (extra_delay ? 3000 : 0); > + > + mutex_lock(&uc->lock); > + > + set_bit(RESET_PENDING, &uc->flags); > + > + ret = ccg_send_command(uc, &cmd); > + if (ret != RESET_COMPLETE) > + goto err_clear_flag; > + > + ret = 0; > + > +err_clear_flag: > + clear_bit(RESET_PENDING, &uc->flags); > + > + mutex_unlock(&uc->lock); > + > + return ret; > +} > + > +static int ccg_cmd_port_control(struct ucsi_ccg *uc, bool enable) > +{ > + struct ccg_cmd cmd; > + int ret; > + > + cmd.reg = CCGX_RAB_PDPORT_ENABLE; > + if (enable) > + cmd.data = (uc->port_num == 1) ? > + PDPORT_1 : (PDPORT_1 | PDPORT_2); > + else > + cmd.data = 0x0; > + cmd.len = 1; > + cmd.delay = 10; > + > + mutex_lock(&uc->lock); > + > + ret = ccg_send_command(uc, &cmd); > + > + mutex_unlock(&uc->lock); > + > + if (ret != CMD_SUCCESS) { > + dev_err(uc->dev, "port control failed ret=%d\n", ret); > + return ret; > + } > + return 0; > +} > + > +static int ccg_cmd_jump_boot_mode(struct ucsi_ccg *uc, int bl_mode) > +{ > + struct ccg_cmd cmd; > + int ret; > + > + cmd.reg = CCGX_RAB_JUMP_TO_BOOT; > + > + if (bl_mode) > + cmd.data = TO_BOOT; > + else > + cmd.data = TO_ALT_FW; > + > + cmd.len = 1; > + cmd.delay = 100; > + > + mutex_lock(&uc->lock); > + > + set_bit(RESET_PENDING, &uc->flags); > + > + ret = ccg_send_command(uc, &cmd); > + if (ret != RESET_COMPLETE) > + goto err_clear_flag; > + > + ret = 0; > + > +err_clear_flag: > + clear_bit(RESET_PENDING, &uc->flags); > + > + mutex_unlock(&uc->lock); > + > + return ret; > +} > + > +static int > +ccg_cmd_write_flash_row(struct ucsi_ccg *uc, u16 row, > + const void *data, u8 fcmd) > +{ > + struct i2c_client *client = uc->client; > + struct ccg_cmd cmd; > + u8 buf[CCG4_ROW_SIZE + 2]; > + u8 *p; > + int ret; > + > + /* Copy the data into the flash read/write memory. */ > + buf[0] = REG_FLASH_RW_MEM & 0xFF; > + buf[1] = REG_FLASH_RW_MEM >> 8; > + > + memcpy(buf + 2, data, CCG4_ROW_SIZE); > + > + mutex_lock(&uc->lock); > + > + ret = i2c_master_send(client, buf, CCG4_ROW_SIZE + 2); > + if (ret != CCG4_ROW_SIZE + 2) { > + dev_err(uc->dev, "REG_FLASH_RW_MEM write fail %d\n", ret); > + return ret < 0 ? ret : -EIO; > + } > + > + /* Use the FLASH_ROW_READ_WRITE register to trigger */ > + /* writing of data to the desired flash row */ > + p = (u8 *)&cmd.data; > + cmd.reg = CCGX_RAB_FLASH_ROW_RW; > + p[0] = FLASH_SIG; > + p[1] = fcmd; > + p[2] = row & 0xFF; > + p[3] = row >> 8; > + cmd.len = 4; > + cmd.delay = 50; > + if (fcmd == FLASH_FWCT_SIG_WR_CMD) > + cmd.delay += 400; > + if (row == 510) > + cmd.delay += 220; > + ret = ccg_send_command(uc, &cmd); > + > + mutex_unlock(&uc->lock); > + > + if (ret != CMD_SUCCESS) { > + dev_err(uc->dev, "write flash row failed ret=%d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) > +{ > + struct ccg_cmd cmd; > + int ret; > + > + cmd.reg = CCGX_RAB_VALIDATE_FW; > + cmd.data = fwid; > + cmd.len = 1; > + cmd.delay = 500; > + > + mutex_lock(&uc->lock); > + > + ret = ccg_send_command(uc, &cmd); > + > + mutex_unlock(&uc->lock); > + > + if (ret != CMD_SUCCESS) > + return ret; > + > + return 0; > +} Here you finally call ccg_send_command(), but now you introduce new functions that are not yet used, causing compiler warnings. I think these patches need to be reorganized. thanks,
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 63b07b7d17f2..b9bbe90bdf57 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -30,13 +30,34 @@ enum enum_fw_mode { #define PORT0_INT BIT(1) #define PORT1_INT BIT(2) #define UCSI_READ_INT BIT(7) +#define CCGX_RAB_JUMP_TO_BOOT 0x0007 +#define TO_BOOT 'J' +#define TO_ALT_FW 'A' +#define CCGX_RAB_RESET_REQ 0x0008 +#define RESET_SIG 'R' +#define CMD_RESET_I2C 0x0 +#define CMD_RESET_DEV 0x1 +#define CCGX_RAB_ENTER_FLASHING 0x000A +#define FLASH_ENTER_SIG 'P' +#define CCGX_RAB_VALIDATE_FW 0x000B +#define CCGX_RAB_FLASH_ROW_RW 0x000C +#define FLASH_SIG 'F' +#define FLASH_RD_CMD 0x0 +#define FLASH_WR_CMD 0x1 +#define FLASH_FWCT1_WR_CMD 0x2 +#define FLASH_FWCT2_WR_CMD 0x3 +#define FLASH_FWCT_SIG_WR_CMD 0x4 #define CCGX_RAB_READ_ALL_VER 0x0010 #define CCGX_RAB_READ_FW2_VER 0x0020 #define CCGX_RAB_UCSI_CONTROL 0x0039 #define CCGX_RAB_UCSI_CONTROL_START BIT(0) #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) +#define REG_FLASH_RW_MEM 0x0200 #define DEV_REG_IDX CCGX_RAB_DEVICE_MODE +#define CCGX_RAB_PDPORT_ENABLE 0x002C +#define PDPORT_1 BIT(0) +#define PDPORT_2 BIT(1) #define CCGX_RAB_RESPONSE 0x007E #define ASYNC_EVENT BIT(7) @@ -47,6 +68,13 @@ enum enum_fw_mode { #define PORT_DISCONNECT_DET 0x85 #define ROLE_SWAP_COMPELETE 0x87 +/* ccg firmware */ +#define CYACD_LINE_SIZE 527 +#define CCG4_ROW_SIZE 256 +#define FW1_METADATA_ROW 0x1FF +#define FW2_METADATA_ROW 0x1FE +#define FW_CFG_TABLE_SIG_SIZE 256 + struct ccg_dev_info { #define CCG_DEVINFO_FWMODE_SHIFT (0) #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) @@ -118,6 +146,7 @@ struct ucsi_ccg { struct ccg_resp dev_resp; u8 cmd_resp; int port_num; + struct mutex lock; /* to sync between user and driver thread */ }; static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -431,6 +460,193 @@ static int ccg_send_command(struct ucsi_ccg *uc, struct ccg_cmd *cmd) return uc->cmd_resp; } +static int ccg_cmd_enter_flashing(struct ucsi_ccg *uc) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_ENTER_FLASHING; + cmd.data = FLASH_ENTER_SIG; + cmd.len = 1; + cmd.delay = 50; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "enter flashing failed ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ccg_cmd_reset(struct ucsi_ccg *uc, bool extra_delay) +{ + struct ccg_cmd cmd; + u8 *p; + int ret; + + p = (u8 *)&cmd.data; + cmd.reg = CCGX_RAB_RESET_REQ; + p[0] = RESET_SIG; + p[1] = CMD_RESET_DEV; + cmd.len = 2; + cmd.delay = 2000 + (extra_delay ? 3000 : 0); + + mutex_lock(&uc->lock); + + set_bit(RESET_PENDING, &uc->flags); + + ret = ccg_send_command(uc, &cmd); + if (ret != RESET_COMPLETE) + goto err_clear_flag; + + ret = 0; + +err_clear_flag: + clear_bit(RESET_PENDING, &uc->flags); + + mutex_unlock(&uc->lock); + + return ret; +} + +static int ccg_cmd_port_control(struct ucsi_ccg *uc, bool enable) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_PDPORT_ENABLE; + if (enable) + cmd.data = (uc->port_num == 1) ? + PDPORT_1 : (PDPORT_1 | PDPORT_2); + else + cmd.data = 0x0; + cmd.len = 1; + cmd.delay = 10; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "port control failed ret=%d\n", ret); + return ret; + } + return 0; +} + +static int ccg_cmd_jump_boot_mode(struct ucsi_ccg *uc, int bl_mode) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_JUMP_TO_BOOT; + + if (bl_mode) + cmd.data = TO_BOOT; + else + cmd.data = TO_ALT_FW; + + cmd.len = 1; + cmd.delay = 100; + + mutex_lock(&uc->lock); + + set_bit(RESET_PENDING, &uc->flags); + + ret = ccg_send_command(uc, &cmd); + if (ret != RESET_COMPLETE) + goto err_clear_flag; + + ret = 0; + +err_clear_flag: + clear_bit(RESET_PENDING, &uc->flags); + + mutex_unlock(&uc->lock); + + return ret; +} + +static int +ccg_cmd_write_flash_row(struct ucsi_ccg *uc, u16 row, + const void *data, u8 fcmd) +{ + struct i2c_client *client = uc->client; + struct ccg_cmd cmd; + u8 buf[CCG4_ROW_SIZE + 2]; + u8 *p; + int ret; + + /* Copy the data into the flash read/write memory. */ + buf[0] = REG_FLASH_RW_MEM & 0xFF; + buf[1] = REG_FLASH_RW_MEM >> 8; + + memcpy(buf + 2, data, CCG4_ROW_SIZE); + + mutex_lock(&uc->lock); + + ret = i2c_master_send(client, buf, CCG4_ROW_SIZE + 2); + if (ret != CCG4_ROW_SIZE + 2) { + dev_err(uc->dev, "REG_FLASH_RW_MEM write fail %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + /* Use the FLASH_ROW_READ_WRITE register to trigger */ + /* writing of data to the desired flash row */ + p = (u8 *)&cmd.data; + cmd.reg = CCGX_RAB_FLASH_ROW_RW; + p[0] = FLASH_SIG; + p[1] = fcmd; + p[2] = row & 0xFF; + p[3] = row >> 8; + cmd.len = 4; + cmd.delay = 50; + if (fcmd == FLASH_FWCT_SIG_WR_CMD) + cmd.delay += 400; + if (row == 510) + cmd.delay += 220; + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "write flash row failed ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_VALIDATE_FW; + cmd.data = fwid; + cmd.len = 1; + cmd.delay = 500; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) + return ret; + + return 0; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) {