On Fri, Feb 01, 2019 at 05:05:08PM -0800, Ajay Gupta wrote: > From: Ajay Gupta <ajayg@xxxxxxxxxx> > > 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@xxxxxxxxxx> > --- > 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, -- heikki