summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/greybus/firmware.c51
-rw-r--r--drivers/staging/greybus/greybus_protocols.h7
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 */