linux/drivers/staging/greybus/Documentation/firmware/firmware.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2/*
   3 * Sample code to test firmware-management protocol
   4 *
   5 * This file is provided under a dual BSD/GPLv2 license.  When using or
   6 * redistributing this file, you may do so under either license.
   7 *
   8 * GPL LICENSE SUMMARY
   9 *
  10 * Copyright(c) 2016 Google Inc. All rights reserved.
  11 * Copyright(c) 2016 Linaro Ltd. All rights reserved.
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of version 2 of the GNU General Public License as
  15 * published by the Free Software Foundation.
  16 *
  17 * This program is distributed in the hope that it will be useful, but
  18 * WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20 * General Public License version 2 for more details.
  21 *
  22 * BSD LICENSE
  23 *
  24 * Copyright(c) 2016 Google Inc. All rights reserved.
  25 * Copyright(c) 2016 Linaro Ltd. All rights reserved.
  26 *
  27 * Redistribution and use in source and binary forms, with or without
  28 * modification, are permitted provided that the following conditions
  29 * are met:
  30 *
  31 *  * Redistributions of source code must retain the above copyright
  32 *    notice, this list of conditions and the following disclaimer.
  33 *  * Redistributions in binary form must reproduce the above copyright
  34 *    notice, this list of conditions and the following disclaimer in
  35 *    the documentation and/or other materials provided with the
  36 *    distribution.
  37 *  * Neither the name of Google Inc. or Linaro Ltd. nor the names of
  38 *    its contributors may be used to endorse or promote products
  39 *    derived from this software without specific prior written
  40 *    permission.
  41 *
  42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
  46 * LINARO LTD. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  47 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  48 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  49 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  50 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  53 */
  54
  55#include <stdio.h>
  56#include <stdlib.h>
  57#include <string.h>
  58#include <unistd.h>
  59#include <sys/ioctl.h>
  60#include <sys/stat.h>
  61#include <fcntl.h>
  62
  63#include "../../greybus_firmware.h"
  64
  65#define FW_DEV_DEFAULT          "/dev/gb-fw-mgmt-0"
  66#define FW_TAG_INT_DEFAULT      "s3f"
  67#define FW_TAG_BCND_DEFAULT     "bf_01"
  68#define FW_UPDATE_TYPE_DEFAULT  0
  69#define FW_TIMEOUT_DEFAULT      10000
  70
  71static const char *firmware_tag;
  72static const char *fwdev = FW_DEV_DEFAULT;
  73static unsigned int fw_update_type = FW_UPDATE_TYPE_DEFAULT;
  74static unsigned int fw_timeout = FW_TIMEOUT_DEFAULT;
  75
  76static struct fw_mgmt_ioc_get_intf_version intf_fw_info;
  77static struct fw_mgmt_ioc_get_backend_version backend_fw_info;
  78static struct fw_mgmt_ioc_intf_load_and_validate intf_load;
  79static struct fw_mgmt_ioc_backend_fw_update backend_update;
  80
  81static void usage(void)
  82{
  83        printf("\nUsage: ./firmware <gb-fw-mgmt-X (default: gb-fw-mgmt-0)> <interface: 0, backend: 1 (default: 0)> <firmware-tag> (default: \"s3f\"/\"bf_01\") <timeout (default: 10000 ms)>\n");
  84}
  85
  86static int update_intf_firmware(int fd)
  87{
  88        int ret;
  89
  90        /* Get Interface Firmware Version */
  91        printf("Get Interface Firmware Version\n");
  92
  93        ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &intf_fw_info);
  94        if (ret < 0) {
  95                printf("Failed to get interface firmware version: %s (%d)\n",
  96                        fwdev, ret);
  97                return -1;
  98        }
  99
 100        printf("Interface Firmware tag (%s), major (%d), minor (%d)\n",
 101                intf_fw_info.firmware_tag, intf_fw_info.major,
 102                intf_fw_info.minor);
 103
 104        /* Try Interface Firmware load over Unipro */
 105        printf("Loading Interface Firmware\n");
 106
 107        intf_load.load_method = GB_FW_U_LOAD_METHOD_UNIPRO;
 108        intf_load.status = 0;
 109        intf_load.major = 0;
 110        intf_load.minor = 0;
 111
 112        strncpy((char *)&intf_load.firmware_tag, firmware_tag,
 113                GB_FIRMWARE_U_TAG_MAX_SIZE);
 114
 115        ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load);
 116        if (ret < 0) {
 117                printf("Failed to load interface firmware: %s (%d)\n", fwdev,
 118                        ret);
 119                return -1;
 120        }
 121
 122        if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED &&
 123            intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) {
 124                printf("Load status says loading failed: %d\n",
 125                        intf_load.status);
 126                return -1;
 127        }
 128
 129        printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n",
 130                firmware_tag, intf_load.major, intf_load.minor,
 131                intf_load.status);
 132
 133        /* Initiate Mode-switch to the newly loaded firmware */
 134        printf("Initiate Mode switch\n");
 135
 136        ret = ioctl(fd, FW_MGMT_IOC_MODE_SWITCH);
 137        if (ret < 0)
 138                printf("Failed to initiate mode-switch (%d)\n", ret);
 139
 140        return ret;
 141}
 142
 143static int update_backend_firmware(int fd)
 144{
 145        int ret;
 146
 147        /* Get Backend Firmware Version */
 148        printf("Getting Backend Firmware Version\n");
 149
 150        strncpy((char *)&backend_fw_info.firmware_tag, firmware_tag,
 151                GB_FIRMWARE_U_TAG_MAX_SIZE);
 152
 153retry_fw_version:
 154        ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &backend_fw_info);
 155        if (ret < 0) {
 156                printf("Failed to get backend firmware version: %s (%d)\n",
 157                        fwdev, ret);
 158                return -1;
 159        }
 160
 161        printf("Backend Firmware tag (%s), major (%d), minor (%d), status (%d)\n",
 162                backend_fw_info.firmware_tag, backend_fw_info.major,
 163                backend_fw_info.minor, backend_fw_info.status);
 164
 165        if (backend_fw_info.status == GB_FW_U_BACKEND_VERSION_STATUS_RETRY)
 166                goto retry_fw_version;
 167
 168        if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS)
 169            && (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) {
 170                printf("Failed to get backend firmware version: %s (%d)\n",
 171                        fwdev, backend_fw_info.status);
 172                return -1;
 173        }
 174
 175        /* Try Backend Firmware Update over Unipro */
 176        printf("Updating Backend Firmware\n");
 177
 178        strncpy((char *)&backend_update.firmware_tag, firmware_tag,
 179                GB_FIRMWARE_U_TAG_MAX_SIZE);
 180
 181retry_fw_update:
 182        backend_update.status = 0;
 183
 184        ret = ioctl(fd, FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE, &backend_update);
 185        if (ret < 0) {
 186                printf("Failed to load backend firmware: %s (%d)\n", fwdev, ret);
 187                return -1;
 188        }
 189
 190        if (backend_update.status == GB_FW_U_BACKEND_FW_STATUS_RETRY) {
 191                printf("Retrying firmware update: %d\n", backend_update.status);
 192                goto retry_fw_update;
 193        }
 194
 195        if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) {
 196                printf("Load status says loading failed: %d\n",
 197                        backend_update.status);
 198        } else {
 199                printf("Backend Firmware (%s) Load done: status: %d\n",
 200                                firmware_tag, backend_update.status);
 201        }
 202
 203        return 0;
 204}
 205
 206int main(int argc, char *argv[])
 207{
 208        int fd, ret;
 209        char *endptr;
 210
 211        if (argc > 1 &&
 212            (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
 213                usage();
 214                return -1;
 215        }
 216
 217        if (argc > 1)
 218                fwdev = argv[1];
 219
 220        if (argc > 2)
 221                fw_update_type = strtoul(argv[2], &endptr, 10);
 222
 223        if (argc > 3)
 224                firmware_tag = argv[3];
 225        else if (!fw_update_type)
 226                firmware_tag = FW_TAG_INT_DEFAULT;
 227        else
 228                firmware_tag = FW_TAG_BCND_DEFAULT;
 229
 230        if (argc > 4)
 231                fw_timeout = strtoul(argv[4], &endptr, 10);
 232
 233        printf("Trying Firmware update: fwdev: %s, type: %s, tag: %s, timeout: %u\n",
 234                fwdev, fw_update_type == 0 ? "interface" : "backend",
 235                firmware_tag, fw_timeout);
 236
 237        printf("Opening %s firmware management device\n", fwdev);
 238
 239        fd = open(fwdev, O_RDWR);
 240        if (fd < 0) {
 241                printf("Failed to open: %s\n", fwdev);
 242                return -1;
 243        }
 244
 245        /* Set Timeout */
 246        printf("Setting timeout to %u ms\n", fw_timeout);
 247
 248        ret = ioctl(fd, FW_MGMT_IOC_SET_TIMEOUT_MS, &fw_timeout);
 249        if (ret < 0) {
 250                printf("Failed to set timeout: %s (%d)\n", fwdev, ret);
 251                ret = -1;
 252                goto close_fd;
 253        }
 254
 255        if (!fw_update_type)
 256                ret = update_intf_firmware(fd);
 257        else
 258                ret = update_backend_firmware(fd);
 259
 260close_fd:
 261        close(fd);
 262
 263        return ret;
 264}
 265