On Thu, Jan 17, 2019 at 05:12:38PM -0800, Ajay Gupta wrote:
> This will be needed to check if latest fw is already flashed.
> 
> Signed-off-by: Ajay Gupta <[email protected]>
> ---
>  drivers/usb/typec/ucsi/ucsi_ccg.c | 139 ++++++++++++++++++++++++++++++
>  1 file changed, 139 insertions(+)
> 
> diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
> b/drivers/usb/typec/ucsi/ucsi_ccg.c
> index 5f341934a5af..6069a9f60d1e 100644
> --- a/drivers/usb/typec/ucsi/ucsi_ccg.c
> +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
> @@ -9,6 +9,7 @@
>   */
>  #include <linux/acpi.h>
>  #include <linux/delay.h>
> +#include <linux/firmware.h>
>  #include <linux/i2c.h>
>  #include <linux/module.h>
>  #include <linux/pci.h>
> @@ -17,6 +18,8 @@
>  #include <asm/unaligned.h>
>  #include "ucsi.h"
>  
> +static int secondary_fw_min_ver = 41;
> +module_param(secondary_fw_min_ver, int, 0660);
>  #define CCGX_RAB_DEVICE_MODE                 0x0000
>  #define CCGX_RAB_INTR_REG                    0x0006
>  #define  DEV_INT                             BIT(0)
> @@ -68,6 +71,27 @@
>  #define FW2_METADATA_ROW        0x1FE
>  #define FW_CFG_TABLE_SIG_SIZE        256
>  
> +enum enum_fw_mode {
> +     BOOT,   /* bootloader */
> +     FW1,    /* FW partition-1 */
> +     FW2,    /* FW partition-2 */
> +     FW_INVALID,
> +};
> +
> +enum enum_flash_mode {
> +     SECONDARY_BL,   /* update secondary using bootloader */
> +     SECONDARY,      /* update secondary using primary */
> +     PRIMARY,        /* update primary */
> +     FLASH_NOT_NEEDED,       /* update not required */
> +     FLASH_INVALID,
> +};
> +
> +static const char * const ccg_fw_names[] = {
> +     /* 0x00 */ "ccg_boot.cyacd",
> +     /* 0x01 */ "ccg_2.cyacd",
> +     /* 0x02 */ "ccg_1.cyacd",
> +};
> +
>  struct ccg_dev_info {
>       u8 fw_mode:2;
>       u8 two_pd_ports:2;
> @@ -95,6 +119,20 @@ struct version_info {
>       struct version_format app;
>  };
>  
> +struct fw_config_table {
> +     u32 identity;
> +     u16 table_size;
> +     u8 fwct_version;
> +     u8 is_key_change;
> +     u8 guid[16];
> +     struct version_format base;
> +     struct version_format app;
> +     u8 primary_fw_digest[32];
> +     u32 key_exp_length;
> +     u8 key_modulus[256];
> +     u8 key_exp[4];
> +};
> +
>  /* CCGx response codes */
>  enum ccg_resp_code {
>       CMD_NO_RESP             = 0x00,
> @@ -737,6 +775,107 @@ static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, 
> unsigned int fwid)
>       return 0;
>  }
>  
> +static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name,
> +                              struct version_format *app)
> +{
> +     const struct firmware *fw = NULL;
> +     struct device *dev = uc->dev;
> +     struct fw_config_table fw_cfg;
> +     u32 cur_version, new_version;
> +     bool is_later = false;
> +
> +     if (request_firmware(&fw, fw_name, dev) != 0) {
> +             dev_err(dev, "error: Failed to open cyacd file %s\n", fw_name);
> +             return false;
> +     }
> +
> +     /*
> +      * check if signed fw
> +      * last part of fw image is fw cfg table and signature
> +      */
> +     if (fw->size < sizeof(fw_cfg) + FW_CFG_TABLE_SIG_SIZE)
> +             goto not_signed_fw;
> +
> +     memcpy((uint8_t *)&fw_cfg, fw->data + fw->size -
> +            sizeof(fw_cfg) - FW_CFG_TABLE_SIG_SIZE, sizeof(fw_cfg));
> +
> +     if (fw_cfg.identity != ('F' | ('W' << 8) | ('C' << 16) | ('T' << 24))) {
> +             dev_info(dev, "not a signed image\n");
> +             goto not_signed_fw;
> +     }
> +
> +     /* compare input version with FWCT version */
> +     cur_version = app->build | (app->patch << 16) |
> +                     ((app->min | (app->maj << 4)) << 24);
> +
> +     new_version = fw_cfg.app.build | (fw_cfg.app.patch << 16) |
> +                     ((fw_cfg.app.min | (fw_cfg.app.maj << 4)) << 24);
> +
> +     dev_dbg(dev, "compare current %08x and new version %08x\n",
> +             cur_version, new_version);
> +
> +     if (new_version > cur_version) {
> +             dev_dbg(dev, "new firmware file version is later\n");
> +             is_later = true;
> +     } else {
> +             dev_dbg(dev, "new firmware file version is same or earlier\n");
> +     }
> +
> +not_signed_fw:
> +     release_firmware(fw);
> +     return is_later;
> +}
> +
> +static int ccg_fw_update_needed(struct ucsi_ccg *uc,
> +                             enum enum_flash_mode *mode)
> +{
> +     struct device *dev = uc->dev;
> +     int err;
> +     struct version_info version[3];
> +
> +     err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
> +                    sizeof(uc->info));
> +     if (err) {
> +             dev_err(dev, "read device mode failed\n");
> +             return err;
> +     }
> +
> +     err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)version,
> +                    sizeof(version));
> +     if (err) {
> +             dev_err(dev, "read device mode failed\n");
> +             return err;
> +     }
> +
> +     dev_dbg(dev, "check if fw upgrade required %x %x %x %x %x %x %x %x\n",
> +             version[FW1].base.build, version[FW1].base.patch,
> +             version[FW1].base.min, version[FW1].base.maj,
> +             version[FW2].app.build, version[FW2].app.patch,
> +             version[FW2].app.min, version[FW2].app.maj);
> +
> +     if (memcmp(&version[FW1], "\0\0\0\0\0\0\0\0",
> +                sizeof(struct version_info)) == 0) {
> +             dev_info(dev, "secondary fw is not flashed\n");
> +             *mode = SECONDARY_BL;
> +     } else if (version[FW1].base.build < secondary_fw_min_ver) {
> +             dev_info(dev, "secondary fw version is too low (< %d)\n",
> +                      secondary_fw_min_ver);
> +             *mode = SECONDARY;
> +     } else if (memcmp(&version[FW2], "\0\0\0\0\0\0\0\0",
> +                sizeof(struct version_info)) == 0) {
> +             dev_info(dev, "primary fw is not flashed\n");
> +             *mode = PRIMARY;
> +     } else if (ccg_check_fw_version(uc, ccg_fw_names[PRIMARY],
> +                &version[FW2].app)) {
> +             dev_info(dev, "found primary fw with later version\n");
> +             *mode = PRIMARY;
> +     } else {
> +             dev_info(dev, "secondary and primary fw are the latest\n");
> +             *mode = FLASH_NOT_NEEDED;
> +     }
> +     return 0;
> +}

Before sending a new version, can you first explain what are you
trying to do here?

I would assume that you just want to read the version of your current
fw, and if there is a newer version of the firmware available, you
upgrade it, and that's it.

Perhaps I'm missing something?


thanks,

-- 
heikki

Reply via email to