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 71 static const char *firmware_tag; 72 static const char *fwdev = FW_DEV_DEFAULT; 73 static unsigned int fw_update_type = FW_UPDATE_TYPE_DEFAULT; 74 static unsigned int fw_timeout = FW_TIMEOUT_DEFAULT; 75 76 static struct fw_mgmt_ioc_get_intf_version intf_fw_info; 77 static struct fw_mgmt_ioc_get_backend_version backend_fw_info; 78 static struct fw_mgmt_ioc_intf_load_and_validate intf_load; 79 static struct fw_mgmt_ioc_backend_fw_update backend_update; 80 81 static 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 86 static 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 143 static 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 153 retry_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 181 retry_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 206 int 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 260 close_fd: 261 close(fd); 262 263 return ret; 264 } 265