From 9e04fb7b1627ad55b63c4e0927f696ecb1a2563a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 26 Apr 2016 10:20:49 +0530 Subject: [PATCH] greybus: firmware: Add firmware management bundle driver 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/fw-core.c | 123 +++++++++++++++++++++ drivers/staging/greybus/greybus_manifest.h | 3 + 3 files changed, 128 insertions(+) create mode 100644 drivers/staging/greybus/fw-core.c diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index 5bdccccbe171..1a120d928485 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -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 index 000000000000..4720d595cc2b --- /dev/null +++ b/drivers/staging/greybus/fw-core.c @@ -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 +#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 "); +MODULE_DESCRIPTION("Greybus Firmware Bundle Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/greybus/greybus_manifest.h b/drivers/staging/greybus/greybus_manifest.h index 460fced979a4..5d00f7de5041 100644 --- a/drivers/staging/greybus/greybus_manifest.h +++ b/drivers/staging/greybus/greybus_manifest.h @@ -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, -- 2.20.1