summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/greybus/core.c9
-rw-r--r--drivers/staging/greybus/firmware.c131
-rw-r--r--drivers/staging/greybus/firmware.h4
-rw-r--r--drivers/staging/greybus/greybus.h1
-rw-r--r--drivers/staging/greybus/greybus_protocols.h11
-rw-r--r--drivers/staging/greybus/legacy.c1
6 files changed, 130 insertions, 27 deletions
diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
index b9303c0..2fb9574 100644
--- a/drivers/staging/greybus/core.c
+++ b/drivers/staging/greybus/core.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define CREATE_TRACE_POINTS
+#include "firmware.h"
#include "greybus.h"
#include "greybus_trace.h"
#include "legacy.h"
@@ -243,9 +244,9 @@ static int __init gb_init(void)
goto error_operation;
}
- retval = gb_firmware_protocol_init();
+ retval = gb_firmware_init();
if (retval) {
- pr_err("gb_firmware_protocol_init failed\n");
+ pr_err("gb_firmware_init failed\n");
goto error_firmware;
}
@@ -258,7 +259,7 @@ static int __init gb_init(void)
return 0; /* Success */
error_legacy:
- gb_firmware_protocol_exit();
+ gb_firmware_exit();
error_firmware:
gb_operation_exit();
error_operation:
@@ -275,7 +276,7 @@ module_init(gb_init);
static void __exit gb_exit(void)
{
gb_legacy_exit();
- gb_firmware_protocol_exit();
+ gb_firmware_exit();
gb_operation_exit();
gb_hd_exit();
bus_unregister(&greybus_bus_type);
diff --git a/drivers/staging/greybus/firmware.c b/drivers/staging/greybus/firmware.c
index 3789510..17ce573 100644
--- a/drivers/staging/greybus/firmware.c
+++ b/drivers/staging/greybus/firmware.c
@@ -9,11 +9,15 @@
#include <linux/firmware.h>
+#include "firmware.h"
#include "greybus.h"
+
struct gb_firmware {
struct gb_connection *connection;
const struct firmware *fw;
+ u8 protocol_major;
+ u8 protocol_minor;
};
static void free_firmware(struct gb_firmware *firmware)
@@ -223,8 +227,10 @@ static int gb_firmware_ready_to_boot(struct gb_operation *op)
return 0;
}
-static int gb_firmware_request_recv(u8 type, struct gb_operation *op)
+static int gb_firmware_request_handler(struct gb_operation *op)
{
+ u8 type = op->type;
+
switch (type) {
case GB_FIRMWARE_TYPE_FIRMWARE_SIZE:
return gb_firmware_size_request(op);
@@ -239,60 +245,147 @@ static int gb_firmware_request_recv(u8 type, struct gb_operation *op)
}
}
-static int gb_firmware_connection_init(struct gb_connection *connection)
+static int gb_firmware_get_version(struct gb_firmware *firmware)
{
+ struct gb_bundle *bundle = firmware->connection->bundle;
+ struct gb_firmware_version_request request;
+ struct gb_firmware_version_response response;
+ int ret;
+
+ request.major = GB_FIRMWARE_VERSION_MAJOR;
+ request.minor = GB_FIRMWARE_VERSION_MINOR;
+
+ ret = gb_operation_sync(firmware->connection,
+ GB_FIRMWARE_TYPE_VERSION,
+ &request, sizeof(request), &response,
+ sizeof(response));
+ if (ret) {
+ dev_err(&bundle->dev,
+ "failed to get protocol version: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (response.major > request.major) {
+ dev_err(&bundle->dev,
+ "unsupported major protocol version (%u > %u)\n",
+ response.major, request.major);
+ return -ENOTSUPP;
+ }
+
+ firmware->protocol_major = response.major;
+ firmware->protocol_minor = response.minor;
+
+ dev_dbg(&bundle->dev, "%s - %u.%u\n", __func__, response.major,
+ response.minor);
+
+ return 0;
+}
+
+static int gb_firmware_probe(struct gb_bundle *bundle,
+ const struct greybus_bundle_id *id)
+{
+ struct greybus_descriptor_cport *cport_desc;
+ struct gb_connection *connection;
struct gb_firmware *firmware;
int ret;
+ if (bundle->num_cports != 1)
+ return -ENODEV;
+
+ cport_desc = &bundle->cport_desc[0];
+ if (cport_desc->protocol_id != GREYBUS_PROTOCOL_FIRMWARE)
+ return -ENODEV;
+
firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware)
return -ENOMEM;
- firmware->connection = connection;
+ connection = gb_connection_create(bundle,
+ le16_to_cpu(cport_desc->id),
+ gb_firmware_request_handler);
+ if (IS_ERR(connection)) {
+ ret = PTR_ERR(connection);
+ goto err_free_firmware;
+ }
+
connection->private = firmware;
+ firmware->connection = connection;
+
+ greybus_set_drvdata(bundle, firmware);
+
+ ret = gb_connection_enable_tx(connection);
+ if (ret)
+ goto err_connection_destroy;
+
+ ret = gb_firmware_get_version(firmware);
+ if (ret)
+ goto err_connection_disable;
+
firmware_es2_fixup_vid_pid(firmware);
+ ret = gb_connection_enable(connection);
+ if (ret)
+ goto err_connection_disable;
+
/* Tell bootrom we're ready. */
ret = gb_operation_sync(connection, GB_FIRMWARE_TYPE_AP_READY, NULL, 0,
NULL, 0);
if (ret) {
dev_err(&connection->bundle->dev,
"failed to send AP READY: %d\n", ret);
- goto err_free_firmware;
+ goto err_connection_disable;
}
- dev_dbg(&connection->bundle->dev, "%s: AP_READY sent\n", __func__);
+ dev_dbg(&bundle->dev, "AP_READY sent\n");
return 0;
+err_connection_disable:
+ gb_connection_disable(connection);
+err_connection_destroy:
+ gb_connection_destroy(connection);
err_free_firmware:
kfree(firmware);
return ret;
}
-static void gb_firmware_connection_exit(struct gb_connection *connection)
+static void gb_firmware_disconnect(struct gb_bundle *bundle)
{
- struct gb_firmware *firmware = connection->private;
+ struct gb_firmware *firmware = greybus_get_drvdata(bundle);
+
+ dev_dbg(&bundle->dev, "%s\n", __func__);
+
+ gb_connection_disable(firmware->connection);
/* Release firmware */
if (firmware->fw)
free_firmware(firmware);
- connection->private = NULL;
+ gb_connection_destroy(firmware->connection);
kfree(firmware);
-
- dev_dbg(&connection->bundle->dev, "%s\n", __func__);
}
-static struct gb_protocol firmware_protocol = {
- .name = "firmware",
- .id = GREYBUS_PROTOCOL_FIRMWARE,
- .major = GB_FIRMWARE_VERSION_MAJOR,
- .minor = GB_FIRMWARE_VERSION_MINOR,
- .connection_init = gb_firmware_connection_init,
- .connection_exit = gb_firmware_connection_exit,
- .request_recv = gb_firmware_request_recv,
+static const struct greybus_bundle_id gb_firmware_id_table[] = {
+ { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FIRMWARE) },
+ { }
};
-gb_builtin_protocol_driver(firmware_protocol);
+
+static struct greybus_driver gb_firmware_driver = {
+ .name = "firmware",
+ .probe = gb_firmware_probe,
+ .disconnect = gb_firmware_disconnect,
+ .id_table = gb_firmware_id_table,
+};
+
+int gb_firmware_init(void)
+{
+ return greybus_register(&gb_firmware_driver);
+}
+
+void gb_firmware_exit(void)
+{
+ greybus_deregister(&gb_firmware_driver);
+}
diff --git a/drivers/staging/greybus/firmware.h b/drivers/staging/greybus/firmware.h
index 548d297..f25744c 100644
--- a/drivers/staging/greybus/firmware.h
+++ b/drivers/staging/greybus/firmware.h
@@ -10,7 +10,7 @@
#ifndef __FIRMWARE_H
#define __FIRMWARE_H
-int gb_firmware_protocol_init(void);
-void gb_firmware_protocol_exit(void);
+int gb_firmware_init(void);
+void gb_firmware_exit(void);
#endif /* __FIRMWARE_H */
diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h
index 2767946..2fc79fa 100644
--- a/drivers/staging/greybus/greybus.h
+++ b/drivers/staging/greybus/greybus.h
@@ -27,7 +27,6 @@
#include "manifest.h"
#include "hd.h"
#include "svc.h"
-#include "firmware.h"
#include "control.h"
#include "interface.h"
#include "bundle.h"
diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h
index 3f51fb5..89db932 100644
--- a/drivers/staging/greybus/greybus_protocols.h
+++ b/drivers/staging/greybus/greybus_protocols.h
@@ -203,6 +203,7 @@ struct gb_control_interface_version_response {
#define GB_FIRMWARE_VERSION_MINOR 0x01
/* Greybus firmware request types */
+#define GB_FIRMWARE_TYPE_VERSION 0x01
#define GB_FIRMWARE_TYPE_FIRMWARE_SIZE 0x02
#define GB_FIRMWARE_TYPE_GET_FIRMWARE 0x03
#define GB_FIRMWARE_TYPE_READY_TO_BOOT 0x04
@@ -226,6 +227,16 @@ struct gb_control_interface_version_response {
/* Max firmware data fetch size in bytes */
#define GB_FIRMWARE_FETCH_MAX 2000
+struct gb_firmware_version_request {
+ __u8 major;
+ __u8 minor;
+} __packed;
+
+struct gb_firmware_version_response {
+ __u8 major;
+ __u8 minor;
+} __packed;
+
/* Firmware protocol firmware size request/response */
struct gb_firmware_size_request {
__u8 stage;
diff --git a/drivers/staging/greybus/legacy.c b/drivers/staging/greybus/legacy.c
index 900521a..057029d 100644
--- a/drivers/staging/greybus/legacy.c
+++ b/drivers/staging/greybus/legacy.c
@@ -247,7 +247,6 @@ static const struct greybus_bundle_id legacy_id_table[] = {
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOOPBACK) },
- { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FIRMWARE) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
{ }
};
OpenPOWER on IntegriCloud