diff --git a/plugins/vli/fu-vli-pd-device.c b/plugins/vli/fu-vli-pd-device.c index 2e39e01a7..024f71596 100644 --- a/plugins/vli/fu-vli-pd-device.c +++ b/plugins/vli/fu-vli-pd-device.c @@ -392,6 +392,65 @@ fu_vli_pd_device_write_gpios (FuVliPdDevice *self, GError **error) return TRUE; } +static gboolean +fu_vli_pd_device_write_dual_firmware (FuVliPdDevice *self, GBytes *fw, GError **error) +{ + const guint8 *buf = NULL; + const guint8 *sbuf = NULL; + gsize bufsz = 0; + gsize sbufsz = 0; + guint16 crc_actual; + guint16 crc_file = 0x0; + guint32 sec_addr = 0x28000; + g_autoptr(GBytes) spi_fw = NULL; + + /* check spi fw1 crc16 */ + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_VERIFY); + spi_fw = fu_vli_device_spi_read (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + fu_device_get_firmware_size_max (FU_DEVICE (self)), + error); + if (spi_fw == NULL) + return FALSE; + sbuf = g_bytes_get_data (spi_fw, &sbufsz); + if (sbufsz != 0x8000) + sec_addr = 0x30000; + if (!fu_common_read_uint16_safe (sbuf, sbufsz, sbufsz - 2, &crc_file, + G_LITTLE_ENDIAN, error)) { + g_prefix_error (error, "failed to read file CRC: "); + return FALSE; + } + crc_actual = fu_vli_common_crc16 (sbuf, sbufsz - 2); + fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_WRITE); + + /* update fw2 first if fw1 correct */ + buf = g_bytes_get_data (fw, &bufsz); + if (crc_actual == crc_file) { + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + sec_addr, + buf, bufsz, error)) + return FALSE; + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + buf, bufsz, error)) + return FALSE; + + /* else update fw1 first */ + } else { + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + fu_vli_device_get_offset (FU_VLI_DEVICE (self)), + buf, bufsz, error)) + return FALSE; + if (!fu_vli_device_spi_write (FU_VLI_DEVICE (self), + sec_addr, + buf, bufsz, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + static gboolean fu_vli_pd_device_write_firmware (FuDevice *device, FuFirmware *firmware, @@ -419,6 +478,11 @@ fu_vli_pd_device_write_firmware (FuDevice *device, if (!fu_vli_pd_device_write_reg (self, 0x0003, tmp | 0x44, error)) return FALSE; + /* dual image on VL103 */ + if (fu_vli_device_get_kind (FU_VLI_DEVICE (device)) == FU_VLI_DEVICE_KIND_VL103 && + fu_device_has_flag (device, FWUPD_DEVICE_FLAG_DUAL_IMAGE)) + return fu_vli_pd_device_write_dual_firmware (self, fw, error); + /* erase */ fu_device_set_status (FU_DEVICE (self), FWUPD_STATUS_DEVICE_ERASE); if (!fu_vli_device_spi_erase_all (FU_VLI_DEVICE (self), error)) diff --git a/plugins/vli/vli-pd.quirk b/plugins/vli/vli-pd.quirk index 586c6aeda..2c8a39e61 100644 --- a/plugins/vli/vli-pd.quirk +++ b/plugins/vli/vli-pd.quirk @@ -18,6 +18,7 @@ DeviceKind = VL102 [DeviceInstanceId=USB\VID_2109&PID_0103] Plugin = vli GType = FuVliPdDevice +Flags = dual-image DeviceKind = VL103 [DeviceInstanceId=USB\VID_2109&PID_0104] Plugin = vli @@ -52,6 +53,7 @@ GType = FuVliPdDevice [DeviceInstanceId=USB\VID_17EF&PID_7212] Plugin = vli GType = FuVliPdDevice +Flag = dual-image # Lenovo [DeviceInstanceId=USB\VID_17EF&PID_7215]