mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-02 14:50:49 +00:00
plugin/synaptics-mst: add support for cayenne/spyder
This commit is contained in:
parent
7ae233b7cf
commit
98f78f4b15
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Mario Limonciello <mario.limonciello@dell.com>
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2021 Apollo Ling <apollo.ling@synaptics.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
@ -28,12 +29,20 @@ fu_synaptics_mst_family_to_string (FuSynapticsMstFamily family)
|
||||
return "leaf";
|
||||
if (family == FU_SYNAPTICS_MST_FAMILY_PANAMERA)
|
||||
return "panamera";
|
||||
if (family == FU_SYNAPTICS_MST_FAMILY_CAYENNE)
|
||||
return "cayenne";
|
||||
if (family == FU_SYNAPTICS_MST_FAMILY_SPYDER)
|
||||
return "spyder";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FuSynapticsMstFamily
|
||||
fu_synaptics_mst_family_from_chip_id (guint16 chip_id)
|
||||
{
|
||||
if (chip_id >= 0x7000 && chip_id < 0x8000)
|
||||
return FU_SYNAPTICS_MST_FAMILY_SPYDER;
|
||||
if ((chip_id >= 0x6000 && chip_id < 0x7000) || (chip_id >= 0x8000 && chip_id < 0x9000))
|
||||
return FU_SYNAPTICS_MST_FAMILY_CAYENNE;
|
||||
if (chip_id >= 0x5000 && chip_id < 0x6000)
|
||||
return FU_SYNAPTICS_MST_FAMILY_PANAMERA;
|
||||
if (chip_id >= 0x3000 && chip_id < 0x4000)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2016 Mario Limonciello <mario.limonciello@dell.com>
|
||||
* Copyright (C) 2017 Peichen Huang <peichenhuang@tw.synaptics.com>
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2021 Apollo Ling <apollo.ling@synaptics.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
@ -33,6 +34,8 @@ typedef enum {
|
||||
FU_SYNAPTICS_MST_FAMILY_TESLA,
|
||||
FU_SYNAPTICS_MST_FAMILY_LEAF,
|
||||
FU_SYNAPTICS_MST_FAMILY_PANAMERA,
|
||||
FU_SYNAPTICS_MST_FAMILY_CAYENNE,
|
||||
FU_SYNAPTICS_MST_FAMILY_SPYDER,
|
||||
/*<private >*/
|
||||
FU_SYNAPTICS_MST_FAMILY_LAST
|
||||
} FuSynapticsMstFamily;
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2016 Mario Limonciello <mario.limonciello@dell.com>
|
||||
* Copyright (C) 2017 Peichen Huang <peichenhuang@tw.synaptics.com>
|
||||
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
|
||||
* Copyright (C) 2021 Apollo Ling <apollo.ling@synaptics.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
@ -17,6 +18,8 @@ G_DECLARE_FINAL_TYPE (FuSynapticsMstConnection, fu_synaptics_mst_connection, FU,
|
||||
#define ADDR_CUSTOMER_ID 0X10E
|
||||
#define ADDR_BOARD_ID 0x10F
|
||||
|
||||
#define ADDR_MEMORY_CUSTOMER_ID_CAYENNE 0x9000024E
|
||||
#define ADDR_MEMORY_BOARD_ID_CAYENNE 0x9000024F
|
||||
#define ADDR_MEMORY_CUSTOMER_ID 0x170E
|
||||
#define ADDR_MEMORY_BOARD_ID 0x170F
|
||||
|
||||
@ -41,21 +44,23 @@ typedef enum {
|
||||
} SynapticsMstUpdcRc;
|
||||
|
||||
typedef enum {
|
||||
UPDC_ENABLE_RC = 0x01,
|
||||
UPDC_DISABLE_RC = 0x02,
|
||||
UPDC_GET_ID = 0x03,
|
||||
UPDC_GET_VERSION = 0x04,
|
||||
UPDC_ENABLE_FLASH_CHIP_ERASE = 0x08,
|
||||
UPDC_CAL_EEPROM_CHECKSUM = 0x11,
|
||||
UPDC_FLASH_ERASE = 0x14,
|
||||
UPDC_CAL_EEPROM_CHECK_CRC8 = 0x16,
|
||||
UPDC_CAL_EEPROM_CHECK_CRC16 = 0x17,
|
||||
UPDC_WRITE_TO_EEPROM = 0X20,
|
||||
UPDC_WRITE_TO_MEMORY = 0x21,
|
||||
UPDC_WRITE_TO_TX_DPCD = 0x22,
|
||||
UPDC_READ_FROM_EEPROM = 0x30,
|
||||
UPDC_READ_FROM_MEMORY = 0x31,
|
||||
UPDC_READ_FROM_TX_DPCD = 0x32,
|
||||
UPDC_ENABLE_RC = 0x01,
|
||||
UPDC_DISABLE_RC = 0x02,
|
||||
UPDC_GET_ID = 0x03,
|
||||
UPDC_GET_VERSION = 0x04,
|
||||
UPDC_FLASH_MAPPING = 0x07,
|
||||
UPDC_ENABLE_FLASH_CHIP_ERASE = 0x08,
|
||||
UPDC_CAL_EEPROM_CHECKSUM = 0x11,
|
||||
UPDC_FLASH_ERASE = 0x14,
|
||||
UPDC_CAL_EEPROM_CHECK_CRC8 = 0x16,
|
||||
UPDC_CAL_EEPROM_CHECK_CRC16 = 0x17,
|
||||
UPDC_ACTIVATE_FIRMWARE = 0X18,
|
||||
UPDC_WRITE_TO_EEPROM = 0X20,
|
||||
UPDC_WRITE_TO_MEMORY = 0x21,
|
||||
UPDC_WRITE_TO_TX_DPCD = 0x22,
|
||||
UPDC_READ_FROM_EEPROM = 0x30,
|
||||
UPDC_READ_FROM_MEMORY = 0x31,
|
||||
UPDC_READ_FROM_TX_DPCD = 0x32,
|
||||
} SynapticsMstUpdcCmd;
|
||||
|
||||
FuSynapticsMstConnection *fu_synaptics_mst_connection_new (gint fd,
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright (C) 2016 Mario Limonciello <mario.limonciello@dell.com>
|
||||
* Copyright (C) 2017 Peichen Huang <peichenhuang@tw.synaptics.com>
|
||||
* Copyright (C) 2018 Ryan Chang <ryan.chang@synaptics.com>
|
||||
* Copyright (C) 2021 Apollo Ling <apollo.ling@synaptics.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
@ -771,20 +772,150 @@ fu_synaptics_mst_device_panamera_prepare_write (FuSynapticsMstDevice *self, GErr
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_synaptics_mst_device_update_cayenne_firmware(FuSynapticsMstDevice *self,
|
||||
guint32 payload_len,
|
||||
const guint8 *payload_data,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(FuSynapticsMstConnection) connection = NULL;
|
||||
guint32 data_to_write = 0;
|
||||
guint32 offset = 0;
|
||||
guint32 write_loops = 0;
|
||||
|
||||
payload_len = 0x50000;
|
||||
write_loops = (payload_len / BLOCK_UNIT);
|
||||
data_to_write = payload_len;
|
||||
|
||||
if (payload_len % BLOCK_UNIT)
|
||||
write_loops++;
|
||||
|
||||
connection = fu_synaptics_mst_connection_new(fu_udev_device_get_fd(FU_UDEV_DEVICE(self)),
|
||||
self->layer,
|
||||
self->rad);
|
||||
for (guint32 retries_cnt = 0;; retries_cnt++) {
|
||||
guint32 checksum = 0;
|
||||
guint32 flash_checksum = 0;
|
||||
|
||||
if (!fu_synaptics_mst_device_set_flash_sector_erase(self, 0xffff, 0, error))
|
||||
return FALSE;
|
||||
g_debug("Waiting for flash clear to settle");
|
||||
g_usleep(FLASH_SETTLE_TIME);
|
||||
|
||||
for (guint32 i = 0; i < write_loops; i++) {
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
guint8 length = BLOCK_UNIT;
|
||||
|
||||
if (data_to_write < BLOCK_UNIT)
|
||||
length = data_to_write;
|
||||
if (!fu_synaptics_mst_connection_rc_set_command(connection,
|
||||
UPDC_WRITE_TO_EEPROM,
|
||||
length,
|
||||
offset,
|
||||
payload_data + offset,
|
||||
&error_local)) {
|
||||
g_warning("Failed to write flash offset 0x%04x: %s, retrying",
|
||||
offset,
|
||||
error_local->message);
|
||||
/* repeat once */
|
||||
if (!fu_synaptics_mst_connection_rc_set_command(
|
||||
connection,
|
||||
UPDC_WRITE_TO_EEPROM,
|
||||
length,
|
||||
offset,
|
||||
payload_data + offset,
|
||||
error)) {
|
||||
g_prefix_error(error,
|
||||
"can't write flash offset 0x%04x: ",
|
||||
offset);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
offset += length;
|
||||
data_to_write -= length;
|
||||
fu_device_set_progress_full(FU_DEVICE(self),
|
||||
(goffset)i * 100,
|
||||
(goffset)(write_loops - 1) * 100);
|
||||
}
|
||||
|
||||
/* verify CRC */
|
||||
checksum = fu_synaptics_mst_device_get_crc(0, 16, payload_len, payload_data);
|
||||
if (!fu_synaptics_mst_connection_rc_special_get_command(connection,
|
||||
UPDC_CAL_EEPROM_CHECK_CRC16,
|
||||
payload_len,
|
||||
0,
|
||||
NULL,
|
||||
4,
|
||||
(guint8 *)(&flash_checksum),
|
||||
error)) {
|
||||
g_prefix_error(error, "Failed to get flash checksum: ");
|
||||
return FALSE;
|
||||
}
|
||||
if (checksum == flash_checksum)
|
||||
break;
|
||||
g_debug("attempt %u: checksum %x didn't match %x",
|
||||
retries_cnt,
|
||||
flash_checksum,
|
||||
checksum);
|
||||
|
||||
if (retries_cnt > MAX_RETRY_COUNTS) {
|
||||
g_set_error(error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVALID_DATA,
|
||||
"checksum %x mismatched %x",
|
||||
flash_checksum,
|
||||
checksum);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fu_synaptics_mst_connection_rc_set_command(connection,
|
||||
UPDC_ACTIVATE_FIRMWARE,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
error)) {
|
||||
g_prefix_error(error, "active firmware failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_synaptics_mst_device_restart (FuSynapticsMstDevice *self, GError **error)
|
||||
{
|
||||
g_autoptr(FuSynapticsMstConnection) connection = NULL;
|
||||
guint8 buf[4] = {0xF5, 0, 0 ,0};
|
||||
gint offset;
|
||||
g_autoptr(GError) error_local = NULL;
|
||||
|
||||
switch (self->family) {
|
||||
case FU_SYNAPTICS_MST_FAMILY_TESLA:
|
||||
case FU_SYNAPTICS_MST_FAMILY_LEAF:
|
||||
case FU_SYNAPTICS_MST_FAMILY_PANAMERA:
|
||||
offset = 0x2000FC;
|
||||
break;
|
||||
case FU_SYNAPTICS_MST_FAMILY_CAYENNE:
|
||||
case FU_SYNAPTICS_MST_FAMILY_SPYDER:
|
||||
offset = 0x2020021C;
|
||||
break;
|
||||
default:
|
||||
g_set_error(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"Unsupported chip family");
|
||||
return FALSE;
|
||||
}
|
||||
/* issue the reboot command, ignore return code (triggers before returning) */
|
||||
connection = fu_synaptics_mst_connection_new (fu_udev_device_get_fd (FU_UDEV_DEVICE (self)),
|
||||
self->layer, self->rad);
|
||||
if (!fu_synaptics_mst_connection_rc_set_command (connection,
|
||||
UPDC_WRITE_TO_MEMORY,
|
||||
4, (gint) 0x2000FC, (guint8*) &buf,
|
||||
&error_local))
|
||||
if (!fu_synaptics_mst_connection_rc_set_command(connection,
|
||||
UPDC_WRITE_TO_MEMORY,
|
||||
4,
|
||||
offset,
|
||||
(guint8 *)&buf,
|
||||
&error_local))
|
||||
g_debug ("failed to restart: %s", error_local->message);
|
||||
|
||||
return TRUE;
|
||||
@ -853,7 +984,18 @@ fu_synaptics_mst_device_write_firmware (FuDevice *device,
|
||||
return FALSE;
|
||||
|
||||
/* update firmware */
|
||||
if (self->family == FU_SYNAPTICS_MST_FAMILY_PANAMERA) {
|
||||
switch (self->family) {
|
||||
case FU_SYNAPTICS_MST_FAMILY_TESLA:
|
||||
case FU_SYNAPTICS_MST_FAMILY_LEAF:
|
||||
if (!fu_synaptics_mst_device_update_tesla_leaf_firmware(self,
|
||||
payload_len,
|
||||
payload_data,
|
||||
error)) {
|
||||
g_prefix_error(error, "Firmware update failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case FU_SYNAPTICS_MST_FAMILY_PANAMERA:
|
||||
if (!fu_synaptics_mst_device_panamera_prepare_write (self, error)) {
|
||||
g_prefix_error (error, "Failed to prepare for write: ");
|
||||
return FALSE;
|
||||
@ -871,14 +1013,23 @@ fu_synaptics_mst_device_write_firmware (FuDevice *device,
|
||||
g_prefix_error (error, "Firmware update failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!fu_synaptics_mst_device_update_tesla_leaf_firmware (self,
|
||||
payload_len,
|
||||
payload_data,
|
||||
error)) {
|
||||
break;
|
||||
case FU_SYNAPTICS_MST_FAMILY_CAYENNE:
|
||||
case FU_SYNAPTICS_MST_FAMILY_SPYDER:
|
||||
if (!fu_synaptics_mst_device_update_cayenne_firmware(self,
|
||||
payload_len,
|
||||
payload_data,
|
||||
error)) {
|
||||
g_prefix_error (error, "Firmware update failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_set_error(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"Unsupported chip family");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* wait for flash clear to settle */
|
||||
@ -901,6 +1052,8 @@ fu_synaptics_mst_device_read_board_id (FuSynapticsMstDevice *self,
|
||||
guint8 *byte,
|
||||
GError **error)
|
||||
{
|
||||
gint offset;
|
||||
|
||||
/* in test mode we need to open a different file node instead */
|
||||
if (fu_udev_device_get_dev (FU_UDEV_DEVICE (self)) == NULL) {
|
||||
g_autofree gchar *filename = NULL;
|
||||
@ -940,12 +1093,31 @@ fu_synaptics_mst_device_read_board_id (FuSynapticsMstDevice *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (self->family) {
|
||||
case FU_SYNAPTICS_MST_FAMILY_TESLA:
|
||||
case FU_SYNAPTICS_MST_FAMILY_LEAF:
|
||||
case FU_SYNAPTICS_MST_FAMILY_PANAMERA:
|
||||
offset = (gint)ADDR_MEMORY_CUSTOMER_ID;
|
||||
break;
|
||||
case FU_SYNAPTICS_MST_FAMILY_CAYENNE:
|
||||
case FU_SYNAPTICS_MST_FAMILY_SPYDER:
|
||||
offset = (gint)ADDR_MEMORY_CUSTOMER_ID_CAYENNE;
|
||||
break;
|
||||
default:
|
||||
g_set_error(error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"Unsupported chip family");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get board ID via MCU address 0x170E instead of flash access due to HDCP2.2 running */
|
||||
if (!fu_synaptics_mst_connection_rc_get_command (connection,
|
||||
UPDC_READ_FROM_MEMORY,
|
||||
2,
|
||||
(gint)ADDR_MEMORY_CUSTOMER_ID, byte,
|
||||
error)) {
|
||||
if (!fu_synaptics_mst_connection_rc_get_command(connection,
|
||||
UPDC_READ_FROM_MEMORY,
|
||||
2,
|
||||
offset,
|
||||
byte,
|
||||
error)) {
|
||||
g_prefix_error (error, "Memory query failed: ");
|
||||
return FALSE;
|
||||
}
|
||||
@ -1067,11 +1239,6 @@ fu_synaptics_mst_device_rescan (FuDevice *device, GError **error)
|
||||
version = g_strdup_printf ("%1d.%02d.%02d", buf_ver[0], buf_ver[1], buf_ver[2]);
|
||||
fu_device_set_version (FU_DEVICE (self), version);
|
||||
|
||||
/* read board ID */
|
||||
if (!fu_synaptics_mst_device_read_board_id (self, connection, buf_ver, error))
|
||||
return FALSE;
|
||||
self->board_id = fu_common_read_uint16 (buf_ver, G_BIG_ENDIAN);
|
||||
|
||||
/* read board chip_id */
|
||||
if (!fu_synaptics_mst_connection_read (connection, REG_CHIP_ID,
|
||||
buf_ver, 2, error)) {
|
||||
@ -1094,6 +1261,11 @@ fu_synaptics_mst_device_rescan (FuDevice *device, GError **error)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* read board ID */
|
||||
if (!fu_synaptics_mst_device_read_board_id(self, connection, buf_ver, error))
|
||||
return FALSE;
|
||||
self->board_id = fu_common_read_uint16(buf_ver, G_BIG_ENDIAN);
|
||||
|
||||
/* recursively look for cascade devices */
|
||||
if (!fu_device_locker_close (locker, error)) {
|
||||
g_prefix_error (error, "failed to close parent: ");
|
||||
|
Loading…
Reference in New Issue
Block a user