1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 /* 3 * Sample code to test firmware-management protocol 4 * 5 * Copyright(c) 2016 Google Inc. All rights reserved. 6 * Copyright(c) 2016 Linaro Ltd. All rights reserved. 7 */ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include <sys/ioctl.h> 14 #include <sys/stat.h> 15 #include <fcntl.h> 16 17 #include "../../greybus_firmware.h" 18 19 #define FW_DEV_DEFAULT "/dev/gb-fw-mgmt-0" 20 #define FW_TAG_INT_DEFAULT "s3f" 21 #define FW_TAG_BCND_DEFAULT "bf_01" 22 #define FW_UPDATE_TYPE_DEFAULT 0 23 #define FW_TIMEOUT_DEFAULT 10000 24 25 static const char *firmware_tag; 26 static const char *fwdev = FW_DEV_DEFAULT; 27 static unsigned int fw_update_type = FW_UPDATE_TYPE_DEFAULT; 28 static unsigned int fw_timeout = FW_TIMEOUT_DEFAULT; 29 30 static struct fw_mgmt_ioc_get_intf_version intf_fw_info; 31 static struct fw_mgmt_ioc_get_backend_version backend_fw_info; 32 static struct fw_mgmt_ioc_intf_load_and_validate intf_load; 33 static struct fw_mgmt_ioc_backend_fw_update backend_update; 34 35 static void usage(void) 36 { 37 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"); 38 } 39 40 static int update_intf_firmware(int fd) 41 { 42 int ret; 43 44 /* Get Interface Firmware Version */ 45 printf("Get Interface Firmware Version\n"); 46 47 ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &intf_fw_info); 48 if (ret < 0) { 49 printf("Failed to get interface firmware version: %s (%d)\n", 50 fwdev, ret); 51 return -1; 52 } 53 54 printf("Interface Firmware tag (%s), major (%d), minor (%d)\n", 55 intf_fw_info.firmware_tag, intf_fw_info.major, 56 intf_fw_info.minor); 57 58 /* Try Interface Firmware load over Unipro */ 59 printf("Loading Interface Firmware\n"); 60 61 intf_load.load_method = GB_FW_U_LOAD_METHOD_UNIPRO; 62 intf_load.status = 0; 63 intf_load.major = 0; 64 intf_load.minor = 0; 65 66 strncpy((char *)&intf_load.firmware_tag, firmware_tag, 67 GB_FIRMWARE_U_TAG_MAX_SIZE); 68 69 ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load); 70 if (ret < 0) { 71 printf("Failed to load interface firmware: %s (%d)\n", fwdev, 72 ret); 73 return -1; 74 } 75 76 if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED && 77 intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) { 78 printf("Load status says loading failed: %d\n", 79 intf_load.status); 80 return -1; 81 } 82 83 printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n", 84 firmware_tag, intf_load.major, intf_load.minor, 85 intf_load.status); 86 87 /* Initiate Mode-switch to the newly loaded firmware */ 88 printf("Initiate Mode switch\n"); 89 90 ret = ioctl(fd, FW_MGMT_IOC_MODE_SWITCH); 91 if (ret < 0) 92 printf("Failed to initiate mode-switch (%d)\n", ret); 93 94 return ret; 95 } 96 97 static int update_backend_firmware(int fd) 98 { 99 int ret; 100 101 /* Get Backend Firmware Version */ 102 printf("Getting Backend Firmware Version\n"); 103 104 strncpy((char *)&backend_fw_info.firmware_tag, firmware_tag, 105 GB_FIRMWARE_U_TAG_MAX_SIZE); 106 107 retry_fw_version: 108 ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &backend_fw_info); 109 if (ret < 0) { 110 printf("Failed to get backend firmware version: %s (%d)\n", 111 fwdev, ret); 112 return -1; 113 } 114 115 printf("Backend Firmware tag (%s), major (%d), minor (%d), status (%d)\n", 116 backend_fw_info.firmware_tag, backend_fw_info.major, 117 backend_fw_info.minor, backend_fw_info.status); 118 119 if (backend_fw_info.status == GB_FW_U_BACKEND_VERSION_STATUS_RETRY) 120 goto retry_fw_version; 121 122 if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS) 123 && (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) { 124 printf("Failed to get backend firmware version: %s (%d)\n", 125 fwdev, backend_fw_info.status); 126 return -1; 127 } 128 129 /* Try Backend Firmware Update over Unipro */ 130 printf("Updating Backend Firmware\n"); 131 132 strncpy((char *)&backend_update.firmware_tag, firmware_tag, 133 GB_FIRMWARE_U_TAG_MAX_SIZE); 134 135 retry_fw_update: 136 backend_update.status = 0; 137 138 ret = ioctl(fd, FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE, &backend_update); 139 if (ret < 0) { 140 printf("Failed to load backend firmware: %s (%d)\n", fwdev, ret); 141 return -1; 142 } 143 144 if (backend_update.status == GB_FW_U_BACKEND_FW_STATUS_RETRY) { 145 printf("Retrying firmware update: %d\n", backend_update.status); 146 goto retry_fw_update; 147 } 148 149 if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) { 150 printf("Load status says loading failed: %d\n", 151 backend_update.status); 152 } else { 153 printf("Backend Firmware (%s) Load done: status: %d\n", 154 firmware_tag, backend_update.status); 155 } 156 157 return 0; 158 } 159 160 int main(int argc, char *argv[]) 161 { 162 int fd, ret; 163 char *endptr; 164 165 if (argc > 1 && 166 (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { 167 usage(); 168 return -1; 169 } 170 171 if (argc > 1) 172 fwdev = argv[1]; 173 174 if (argc > 2) 175 fw_update_type = strtoul(argv[2], &endptr, 10); 176 177 if (argc > 3) 178 firmware_tag = argv[3]; 179 else if (!fw_update_type) 180 firmware_tag = FW_TAG_INT_DEFAULT; 181 else 182 firmware_tag = FW_TAG_BCND_DEFAULT; 183 184 if (argc > 4) 185 fw_timeout = strtoul(argv[4], &endptr, 10); 186 187 printf("Trying Firmware update: fwdev: %s, type: %s, tag: %s, timeout: %u\n", 188 fwdev, fw_update_type == 0 ? "interface" : "backend", 189 firmware_tag, fw_timeout); 190 191 printf("Opening %s firmware management device\n", fwdev); 192 193 fd = open(fwdev, O_RDWR); 194 if (fd < 0) { 195 printf("Failed to open: %s\n", fwdev); 196 return -1; 197 } 198 199 /* Set Timeout */ 200 printf("Setting timeout to %u ms\n", fw_timeout); 201 202 ret = ioctl(fd, FW_MGMT_IOC_SET_TIMEOUT_MS, &fw_timeout); 203 if (ret < 0) { 204 printf("Failed to set timeout: %s (%d)\n", fwdev, ret); 205 ret = -1; 206 goto close_fd; 207 } 208 209 if (!fw_update_type) 210 ret = update_intf_firmware(fd); 211 else 212 ret = update_backend_firmware(fd); 213 214 close_fd: 215 close(fd); 216 217 return ret; 218 } 219