greybus: firmware: Add firmware management bundle driver
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 26 Apr 2016 04:50:49 +0000 (10:20 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 27 Apr 2016 18:10:44 +0000 (11:10 -0700)
All firmware packages on the Modules or Interfaces are now managed by a
special Firmware Management Protocol. The Interface Manifest shall
at least contain the Firmware Management Bundle and a Firmware
Management Protocol CPort within it.

The bundle may contain additional CPorts based on the extra
functionality required to manage firmware packages.

For example, this is how the Firmware Management Bundle of the Interface
Manifest may look like:

; Firmware Management Bundle (Bundle 1):
[bundle-descriptor 1]
class = 0x16

; (Mandatory) Firmware Management Protocol on CPort 1
[cport-descriptor 1]
bundle = 1
protocol = 0x18

; (Optional) Firmware Download Protocol on CPort 2
[cport-descriptor 2]
bundle = 1
protocol = 0x17

; (Optional) SPI protocol on CPort 3
[cport-descriptor 3]
bundle = 1
protocol = 0x0b

; (Optional) Component Authentication Protocol (CAP) on CPort 4
[cport-descriptor 4]
bundle = 1
protocol = 0xXX //TBD

This patch adds the basic firmware-management bundle driver, which just
creates a firmware-management connection. Support for individual
protocols will be added separately.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Makefile
drivers/staging/greybus/fw-core.c [new file with mode: 0644]
drivers/staging/greybus/greybus_manifest.h

index 5bdcccc..1a120d9 100644 (file)
@@ -39,6 +39,7 @@ gb-audio-apbridgea-y := audio_apbridgea.o
 gb-audio-manager-y += audio_manager.o
 gb-audio-manager-y += audio_manager_module.o
 gb-camera-y := camera.o
+gb-firmware-y := fw-core.o
 
 obj-m += greybus.o
 obj-m += gb-phy.o
@@ -60,6 +61,7 @@ endif
 obj-m += gb-audio-gb.o
 obj-m += gb-audio-apbridgea.o
 obj-m += gb-audio-manager.o
+obj-m += gb-firmware.o
 
 KERNELVER              ?= $(shell uname -r)
 KERNELDIR              ?= /lib/modules/$(KERNELVER)/build
diff --git a/drivers/staging/greybus/fw-core.c b/drivers/staging/greybus/fw-core.c
new file mode 100644 (file)
index 0000000..4720d59
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Greybus Firmware Core Bundle Driver.
+ *
+ * Copyright 2016 Google Inc.
+ * Copyright 2016 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/firmware.h>
+#include "greybus.h"
+
+struct gb_fw_core {
+       struct gb_connection    *mgmt_connection;
+};
+
+static int gb_fw_core_probe(struct gb_bundle *bundle,
+                           const struct greybus_bundle_id *id)
+{
+       struct greybus_descriptor_cport *cport_desc;
+       struct gb_connection *connection;
+       struct gb_fw_core *fw_core;
+       int ret, i;
+       u16 cport_id;
+       u8 protocol_id;
+
+       fw_core = kzalloc(sizeof(*fw_core), GFP_KERNEL);
+       if (!fw_core)
+               return -ENOMEM;
+
+       /* Parse CPorts and create connections */
+       for (i = 0; i < bundle->num_cports; i++) {
+               cport_desc = &bundle->cport_desc[i];
+               cport_id = le16_to_cpu(cport_desc->id);
+               protocol_id = cport_desc->protocol_id;
+
+               switch (protocol_id) {
+               case GREYBUS_PROTOCOL_FW_MANAGEMENT:
+                       /* Disallow multiple Firmware Management CPorts */
+                       if (fw_core->mgmt_connection) {
+                               dev_err(&bundle->dev,
+                                       "multiple management CPorts found\n");
+                               ret = -EINVAL;
+                               goto err_destroy_connections;
+                       }
+
+                       connection = gb_connection_create(bundle, cport_id,
+                                                         NULL);
+                       if (IS_ERR(connection)) {
+                               ret = PTR_ERR(connection);
+                               dev_err(&bundle->dev,
+                                       "failed to create management connection (%d)\n",
+                                       ret);
+                               goto err_free_fw_core;
+                       }
+
+                       fw_core->mgmt_connection = connection;
+                       break;
+               default:
+                       dev_err(&bundle->dev, "invalid protocol id (0x%02x)\n",
+                               protocol_id);
+                       ret = -EINVAL;
+                       goto err_free_fw_core;
+               }
+       }
+
+       /* Firmware Management connection is mandatory */
+       if (!fw_core->mgmt_connection) {
+               dev_err(&bundle->dev, "missing management connection\n");
+               ret = -ENODEV;
+               goto err_free_fw_core;
+       }
+
+       greybus_set_drvdata(bundle, fw_core);
+
+       return 0;
+
+err_destroy_connections:
+       gb_connection_destroy(fw_core->mgmt_connection);
+err_free_fw_core:
+       kfree(fw_core);
+
+       return ret;
+}
+
+static void gb_fw_core_disconnect(struct gb_bundle *bundle)
+{
+       struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
+
+       gb_connection_destroy(fw_core->mgmt_connection);
+
+       kfree(fw_core);
+}
+
+static const struct greybus_bundle_id gb_fw_core_id_table[] = {
+       { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FW_MANAGEMENT) },
+       { }
+};
+
+static struct greybus_driver gb_fw_core_driver = {
+       .name           = "gb-firmware",
+       .probe          = gb_fw_core_probe,
+       .disconnect     = gb_fw_core_disconnect,
+       .id_table       = gb_fw_core_id_table,
+};
+
+static int fw_core_init(void)
+{
+       return greybus_register(&gb_fw_core_driver);
+}
+module_init(fw_core_init);
+
+static void __exit fw_core_exit(void)
+{
+       greybus_deregister(&gb_fw_core_driver);
+}
+module_exit(fw_core_exit);
+
+MODULE_ALIAS("greybus:firmware");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("Greybus Firmware Bundle Driver");
+MODULE_LICENSE("GPL v2");
index 460fced..5d00f7d 100644 (file)
@@ -45,6 +45,8 @@ enum greybus_protocol {
        GREYBUS_PROTOCOL_SVC            = 0x14,
        GREYBUS_PROTOCOL_BOOTROM        = 0x15,
        GREYBUS_PROTOCOL_CAMERA_DATA    = 0x16,
+       GREYBUS_PROTOCOL_FW_DOWNLOAD    = 0x17,
+       GREYBUS_PROTOCOL_FW_MANAGEMENT  = 0x18,
                /* ... */
        GREYBUS_PROTOCOL_RAW            = 0xfe,
        GREYBUS_PROTOCOL_VENDOR         = 0xff,
@@ -73,6 +75,7 @@ enum greybus_class_type {
        /* 0x13 is unused */
        /* 0x14 is unused */
        GREYBUS_CLASS_BOOTROM           = 0x15,
+       GREYBUS_CLASS_FW_MANAGEMENT     = 0x16,
                /* ... */
        GREYBUS_CLASS_RAW               = 0xfe,
        GREYBUS_CLASS_VENDOR            = 0xff,