From 7bf7fa12fcb24fccb99d7957e44b8be6e0b82986 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 14 May 2016 23:42:25 +0530 Subject: [PATCH] greybus: Documentation: Document firmware-management interfaces This patch adds a new 'firmware' folder in Documentation, which contains two files: - firmware-management: This describes the userspace interface for interacting with firmware-management bundle. - firmware.c: Sample application to test firmware load for Interface Firmware and firmware updates to Backend Interface Firmware. Signed-off-by: Viresh Kumar Reviewed-by: Jun Li Tested-by: Karthik Ravi Shankar Signed-off-by: Greg Kroah-Hartman --- .../firmware/firmware-management | 190 ++++++++++++++++++ .../greybus/Documentation/firmware/firmware.c | 146 ++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 drivers/staging/greybus/Documentation/firmware/firmware-management create mode 100644 drivers/staging/greybus/Documentation/firmware/firmware.c diff --git a/drivers/staging/greybus/Documentation/firmware/firmware-management b/drivers/staging/greybus/Documentation/firmware/firmware-management new file mode 100644 index 000000000000..f70d3cd26be1 --- /dev/null +++ b/drivers/staging/greybus/Documentation/firmware/firmware-management @@ -0,0 +1,190 @@ + +Firmware Management +------------------- + Copyright 2016 Google Inc. + Copyright 2016 Linaro Ltd. + +Interface-Manifest +------------------ + +All firmware packages on the Modules or Interfaces are managed by a special +Firmware Management Protocol. To support Firmware Management by the AP, 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 part 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 2] + bundle = 1 + protocol = 0x18 + + ; (Optional) Firmware Download Protocol on CPort 2 + [cport-descriptor 1] + 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 + + + +Sysfs Interfaces - Firmware Management +-------------------------------------- + +The Firmware Management Protocol interacts with Userspace using the character +device interface. The character device will be present in /dev/ directory +and will be named fw-mgmt-. The number is assigned at runtime. + +Identifying the Character Device +================================ + +There can be multiple devices present in /dev/ directory with name fw-mgmt-N and +user first needs to identify the character device used for firmware-management +for a particular interface. + +The Firmware Management core creates a device of class 'gb_fw_mgmt', which shall +be used by the user to identify the right character device for it. The class +device is created within the Bundle directory for a particular Interface. + +For example this is how the class-device can be present: + +/sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/gb_fw_mgmt/fw-mgmt-0 + +The last name in this path: fw-mgmt-0 is precisely the name of the char device +and so the device in this case will be: + +/dev/fw-mgmt-0. + +Operations on the Char device +============================= + +The Character device (fw-mgmt-0 in example) can be opened by the userspace +application and it can perform various 'ioctl' operations on the device. The +device doesn't support any read/write operations. + +Following are the IOCTLs and their data structures available to the user: + +/* IOCTL support */ +#define GB_FW_LOAD_METHOD_UNIPRO 0x01 +#define GB_FW_LOAD_METHOD_INTERNAL 0x02 + +#define GB_FW_LOAD_STATUS_FAILED 0x00 +#define GB_FW_LOAD_STATUS_UNVALIDATED 0x01 +#define GB_FW_LOAD_STATUS_VALIDATED 0x02 +#define GB_FW_LOAD_STATUS_VALIDATION_FAILED 0x03 + +#define GB_FW_BACKEND_FW_STATUS_SUCCESS 0x01 +#define GB_FW_BACKEND_FW_STATUS_FAIL_FIND 0x02 +#define GB_FW_BACKEND_FW_STATUS_FAIL_FETCH 0x03 +#define GB_FW_BACKEND_FW_STATUS_FAIL_WRITE 0x04 +#define GB_FW_BACKEND_FW_STATUS_INT 0x05 + +struct fw_mgmt_ioc_get_fw { + __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_LEN]; + __u16 major; + __u16 minor; +} __packed; + +struct fw_mgmt_ioc_intf_load_and_validate { + __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_LEN]; + __u8 load_method; + __u8 status; + __u16 major; + __u16 minor; +} __packed; + +struct fw_mgmt_ioc_backend_fw_update { + __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_LEN]; + __u8 status; +} __packed; + +#define FW_MGMT_IOCTL_BASE 'S' +#define FW_MGMT_IOC_GET_INTF_FW _IOR(FW_MGMT_IOCTL_BASE, 0, struct fw_mgmt_ioc_get_fw) +#define FW_MGMT_IOC_GET_BACKEND_FW _IOWR(FW_MGMT_IOCTL_BASE, 1, struct fw_mgmt_ioc_get_fw) +#define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate) +#define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update) +#define FW_MGMT_IOC_SET_TIMEOUT_MS _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int) +#define FW_MGMT_IOC_MODE_SWITCH _IO(FW_MGMT_IOCTL_BASE, 5) + +1. FW_MGMT_IOC_GET_INTF_FW: + + This ioctl shall be used the user to get the version and firmware-tag of the + currently running Interface Firmware. All the fields of the 'struct + fw_mgmt_ioc_get_fw' are filled by the kernel. + +2. FW_MGMT_IOC_GET_BACKEND_FW: + + This ioctl shall be used the user to get the version of a currently running + Backend Interface Firmware identified by a firmware-tag. The user is required + to fill the 'firmware_tag' field of the 'struct fw_mgmt_ioc_get_fw' in this + case. The 'major' and 'minor' fields are set by the kernel in response. + +3. FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE: + + This ioctl shall be used the user to load an Interface Firmware package on an + Interface. The user needs to fill the 'firmware_tag' and 'load_method' fields + of the 'struct fw_mgmt_ioc_intf_load_and_validate'. The 'status', 'major' and + 'minor' fields are set by the kernel in response. + +4. FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE: + + This ioctl shall be used the user to request an Interface to update a Backend + Interface Firmware. The user is required to fill the 'firmware_tag' field of + the 'struct fw_mgmt_ioc_get_fw' in this case. The 'status' field is set by + the kernel in response. + +5. FW_MGMT_IOC_SET_TIMEOUT_MS: + + This ioctl shall be used the user to increase the timeout interval within + which the firmware must get loaded by the Module. The default timeout is 1 + second. The user needs to pass the timeout in milliseconds. + +6. FW_MGMT_IOC_MODE_SWITCH: + + This ioctl shall be used the user to mode-switch the module to the previously + loaded interface firmware. If the interface firmware isn't loaded previously, + or if another unsuccessful FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE operation is + started after loading interface firmware, then the firmware core wouldn't + allow mode-switch. + + +Sysfs Interfaces - Firmware Download +------------------------------------ + +The Firmware Download Protocol uses the existing Linux Kernel's Firmware class +and the interface provided to userspace are described in: +Documentation/firmware_class/. + + +Sysfs Interfaces - SPI Flash +---------------------------- + +The SPI flash is exposed in userspace as a MTD device and is created +within the Bundle directory. For example, this is how the path may look like: + +$ ls /sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/spi_master/spi32766/spi32766.0/mtd +mtd0 mtd0ro + + +Sample Application +------------------ + +The current directly also provides a firmware.c test application, which can be +referenced while developing userspace application to talk to firmware-management +protocol. diff --git a/drivers/staging/greybus/Documentation/firmware/firmware.c b/drivers/staging/greybus/Documentation/firmware/firmware.c new file mode 100644 index 000000000000..e36786013ead --- /dev/null +++ b/drivers/staging/greybus/Documentation/firmware/firmware.c @@ -0,0 +1,146 @@ +/* Sample code to test firmware-management protocol */ + +#include +#include +#include +#include +#include +#include + +#include "../../greybus_firmware.h" + +static const char *firmware_tag = "03"; /* S3 firmware */ + +static struct fw_mgmt_ioc_get_fw fw_info; +static struct fw_mgmt_ioc_intf_load_and_validate intf_load; +static struct fw_mgmt_ioc_backend_fw_update backend_update; + +int main(int argc, char *argv[]) +{ + unsigned int timeout = 10000; + char *fwdev; + int fd, ret; + + /* Make sure arguments are correct */ + if (argc != 2) { + printf("\nUsage: ./firmware \n"); + return 0; + } + + fwdev = argv[1]; + + printf("Opening %s firmware management device\n", fwdev); + + fd = open(fwdev, O_RDWR); + if (fd < 0) { + printf("Failed to open: %s\n", fwdev); + ret = -1; + goto close_fd; + } + + /* Set Timeout */ + printf("Setting timeout to %u ms\n", timeout); + + ret = ioctl(fd, FW_MGMT_IOC_SET_TIMEOUT_MS, &timeout); + if (ret < 0) { + printf("Failed to set timeout: %s (%d)\n", fwdev, ret); + ret = -1; + goto close_fd; + } + + /* Get Interface Firmware Version */ + printf("Get Interface Firmware Version\n"); + + ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &fw_info); + if (ret < 0) { + printf("Failed to get interface firmware version: %s (%d)\n", + fwdev, ret); + ret = -1; + goto close_fd; + } + + printf("Interface Firmware tag (%s), major (%d), minor (%d)\n", + fw_info.firmware_tag, fw_info.major, fw_info.minor); + + /* Try Interface Firmware load over Unipro */ + printf("Loading Interface Firmware\n"); + + intf_load.load_method = GB_FW_U_LOAD_METHOD_UNIPRO; + intf_load.status = 0; + intf_load.major = 0; + intf_load.minor = 0; + strncpy((char *)&intf_load.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_LEN); + + ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load); + if (ret < 0) { + printf("Failed to load interface firmware: %s (%d)\n", fwdev, + ret); + ret = -1; + goto close_fd; + } + + if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED && + intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) { + printf("Load status says loading failed: %d\n", + intf_load.status); + ret = -1; + goto close_fd; + } + + printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n", + firmware_tag, intf_load.major, intf_load.minor, + intf_load.status); + + /* Get Backend Firmware Version */ + printf("Getting Backend Firmware Version\n"); + + strncpy((char *)&fw_info.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_LEN); + fw_info.major = 0; + fw_info.minor = 0; + + ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &fw_info); + if (ret < 0) { + printf("Failed to get backend firmware version: %s (%d)\n", + fwdev, ret); + goto mode_switch; + } + + printf("Backend Firmware tag (%s), major (%d), minor (%d)\n", + fw_info.firmware_tag, fw_info.major, fw_info.minor); + + /* Try Backend Firmware Update over Unipro */ + printf("Updating Backend Firmware\n"); + + backend_update.status = 0; + strncpy((char *)&backend_update.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_LEN); + + ret = ioctl(fd, FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE, &backend_update); + if (ret < 0) { + printf("Failed to load backend firmware: %s (%d)\n", fwdev, ret); + goto mode_switch; + } + + printf("Backend Firmware (%s) Load done: status: %d\n", + firmware_tag, backend_update.status); + + if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) { + printf("Load status says loading failed: %d\n", + backend_update.status); + } + +mode_switch: + /* Initiate Mode-switch to the newly loaded firmware */ + printf("Initiate Mode switch\n"); + + ret = ioctl(fd, FW_MGMT_IOC_MODE_SWITCH); + if (ret < 0) + printf("Failed to initiate mode-switch (%d)\n", ret); + +close_fd: + close(fd); + + return ret; +} -- 2.39.5