diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/greybus/firmware.c | 51 | ||||
-rw-r--r-- | drivers/staging/greybus/greybus_protocols.h | 7 |
2 files changed, 57 insertions, 1 deletions
diff --git a/drivers/staging/greybus/firmware.c b/drivers/staging/greybus/firmware.c index e41526b62ab6..cd2184cec758 100644 --- a/drivers/staging/greybus/firmware.c +++ b/drivers/staging/greybus/firmware.c @@ -11,9 +11,14 @@ #include "greybus.h" +#define ES2_UNIPRO_MFG_ID 0x00000126 +#define ES2_UNIPRO_PROD_ID 0x00001000 + struct gb_firmware { struct gb_connection *connection; const struct firmware *fw; + u32 vendor_id; + u32 product_id; }; static void free_firmware(struct gb_firmware *firmware) @@ -22,6 +27,45 @@ static void free_firmware(struct gb_firmware *firmware) firmware->fw = NULL; } +/* + * The es2 chip doesn't have VID/PID programmed into the hardware and we need to + * hack that up to distinguish different modules and their firmware blobs. + * + * This fetches VID/PID (over firmware protocol) for es2 chip only, when VID/PID + * already sent during hotplug are 0. + * + * Otherwise, we keep firmware->vendor_id/product_id same as what's passed + * during hotplug. + */ +static void firmware_es2_fixup_vid_pid(struct gb_firmware *firmware) +{ + struct gb_firmware_get_vid_pid_response response; + struct gb_connection *connection = firmware->connection; + struct gb_interface *intf = connection->bundle->intf; + int ret; + + /* + * Use VID/PID specified at hotplug if: + * - Bridge ASIC chip isn't ES2 + * - Received non-zero Vendor/Product ids + */ + if (intf->unipro_mfg_id != ES2_UNIPRO_MFG_ID || + intf->unipro_prod_id != ES2_UNIPRO_PROD_ID || + intf->vendor_id != 0 || intf->product_id != 0) + return; + + ret = gb_operation_sync(connection, GB_FIRMWARE_TYPE_GET_VID_PID, + NULL, 0, &response, sizeof(response)); + if (ret) { + dev_err(&connection->bundle->dev, + "Firmware get vid/pid operation failed (%d)\n", ret); + return; + } + + firmware->vendor_id = le32_to_cpu(response.vendor_id); + firmware->product_id = le32_to_cpu(response.product_id); +} + /* This returns path of the firmware blob on the disk */ static int download_firmware(struct gb_firmware *firmware, u8 stage) { @@ -41,7 +85,7 @@ static int download_firmware(struct gb_firmware *firmware, u8 stage) snprintf(firmware_name, sizeof(firmware_name), "ara:%08x:%08x:%08x:%08x:%02x.tftf", intf->unipro_mfg_id, intf->unipro_prod_id, - intf->vendor_id, intf->product_id, stage); + firmware->vendor_id, firmware->product_id, stage); return request_firmware(&firmware->fw, firmware_name, &connection->bundle->dev); @@ -183,6 +227,11 @@ static int gb_firmware_connection_init(struct gb_connection *connection) firmware->connection = connection; connection->private = firmware; + firmware->vendor_id = connection->intf->vendor_id; + firmware->product_id = connection->intf->product_id; + + firmware_es2_fixup_vid_pid(firmware); + /* * Module's Bootrom needs a way to know (currently), when to start * sending requests to the AP. The version request is sent before this diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h index 9fcbbe4eb636..00593b0a3597 100644 --- a/drivers/staging/greybus/greybus_protocols.h +++ b/drivers/staging/greybus/greybus_protocols.h @@ -158,6 +158,7 @@ struct gb_control_disconnected_request { #define GB_FIRMWARE_TYPE_GET_FIRMWARE 0x03 #define GB_FIRMWARE_TYPE_READY_TO_BOOT 0x04 #define GB_FIRMWARE_TYPE_AP_READY 0x05 /* Request with no-payload */ +#define GB_FIRMWARE_TYPE_GET_VID_PID 0x06 /* Request with no-payload */ /* Greybus firmware boot stages */ #define GB_FIRMWARE_BOOT_STAGE_ONE 0x01 /* Reserved for the boot ROM */ @@ -197,6 +198,12 @@ struct gb_firmware_ready_to_boot_request { } __packed; /* Firmware protocol Ready to boot response has no payload */ +/* Firmware protocol get VID/PID request has no payload */ +struct gb_firmware_get_vid_pid_response { + __le32 vendor_id; + __le32 product_id; +} __packed; + /* Power Supply */ |