firmware.c (10988B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * NCI based driver for Samsung S3FWRN5 NFC chip 4 * 5 * Copyright (C) 2015 Samsung Electrnoics 6 * Robert Baldyga <r.baldyga@samsung.com> 7 */ 8 9#include <linux/completion.h> 10#include <linux/firmware.h> 11#include <crypto/hash.h> 12#include <crypto/sha1.h> 13 14#include "s3fwrn5.h" 15#include "firmware.h" 16 17struct s3fwrn5_fw_version { 18 __u8 major; 19 __u8 build1; 20 __u8 build2; 21 __u8 target; 22}; 23 24static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info, 25 struct sk_buff *msg, struct sk_buff **rsp) 26{ 27 struct s3fwrn5_info *info = 28 container_of(fw_info, struct s3fwrn5_info, fw_info); 29 long ret; 30 31 reinit_completion(&fw_info->completion); 32 33 ret = s3fwrn5_write(info, msg); 34 if (ret < 0) 35 return ret; 36 37 ret = wait_for_completion_interruptible_timeout( 38 &fw_info->completion, msecs_to_jiffies(1000)); 39 if (ret < 0) 40 return ret; 41 else if (ret == 0) 42 return -ENXIO; 43 44 if (!fw_info->rsp) 45 return -EINVAL; 46 47 *rsp = fw_info->rsp; 48 fw_info->rsp = NULL; 49 50 return 0; 51} 52 53static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info, 54 struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len) 55{ 56 struct s3fwrn5_fw_header hdr; 57 struct sk_buff *skb; 58 59 hdr.type = type | fw_info->parity; 60 fw_info->parity ^= 0x80; 61 hdr.code = code; 62 hdr.len = len; 63 64 skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL); 65 if (!skb) 66 return -ENOMEM; 67 68 skb_put_data(skb, &hdr, S3FWRN5_FW_HDR_SIZE); 69 if (len) 70 skb_put_data(skb, data, len); 71 72 *msg = skb; 73 74 return 0; 75} 76 77static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info, 78 struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo) 79{ 80 struct sk_buff *msg, *rsp = NULL; 81 struct s3fwrn5_fw_header *hdr; 82 int ret; 83 84 /* Send GET_BOOTINFO command */ 85 86 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 87 S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0); 88 if (ret < 0) 89 return ret; 90 91 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 92 kfree_skb(msg); 93 if (ret < 0) 94 return ret; 95 96 hdr = (struct s3fwrn5_fw_header *) rsp->data; 97 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 98 ret = -EINVAL; 99 goto out; 100 } 101 102 memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10); 103 104out: 105 kfree_skb(rsp); 106 return ret; 107} 108 109static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info, 110 const void *hash_data, u16 hash_size, 111 const void *sig_data, u16 sig_size) 112{ 113 struct s3fwrn5_fw_cmd_enter_updatemode args; 114 struct sk_buff *msg, *rsp = NULL; 115 struct s3fwrn5_fw_header *hdr; 116 int ret; 117 118 /* Send ENTER_UPDATE_MODE command */ 119 120 args.hashcode_size = hash_size; 121 args.signature_size = sig_size; 122 123 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 124 S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args)); 125 if (ret < 0) 126 return ret; 127 128 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 129 kfree_skb(msg); 130 if (ret < 0) 131 return ret; 132 133 hdr = (struct s3fwrn5_fw_header *) rsp->data; 134 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 135 ret = -EPROTO; 136 goto out; 137 } 138 139 kfree_skb(rsp); 140 141 /* Send hashcode data */ 142 143 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0, 144 hash_data, hash_size); 145 if (ret < 0) 146 return ret; 147 148 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 149 kfree_skb(msg); 150 if (ret < 0) 151 return ret; 152 153 hdr = (struct s3fwrn5_fw_header *) rsp->data; 154 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 155 ret = -EPROTO; 156 goto out; 157 } 158 159 kfree_skb(rsp); 160 161 /* Send signature data */ 162 163 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0, 164 sig_data, sig_size); 165 if (ret < 0) 166 return ret; 167 168 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 169 kfree_skb(msg); 170 if (ret < 0) 171 return ret; 172 173 hdr = (struct s3fwrn5_fw_header *) rsp->data; 174 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) 175 ret = -EPROTO; 176 177out: 178 kfree_skb(rsp); 179 return ret; 180} 181 182static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info, 183 u32 base_addr, const void *data) 184{ 185 struct s3fwrn5_fw_cmd_update_sector args; 186 struct sk_buff *msg, *rsp = NULL; 187 struct s3fwrn5_fw_header *hdr; 188 int ret, i; 189 190 /* Send UPDATE_SECTOR command */ 191 192 args.base_address = base_addr; 193 194 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 195 S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args)); 196 if (ret < 0) 197 return ret; 198 199 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 200 kfree_skb(msg); 201 if (ret < 0) 202 return ret; 203 204 hdr = (struct s3fwrn5_fw_header *) rsp->data; 205 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 206 ret = -EPROTO; 207 goto err; 208 } 209 210 kfree_skb(rsp); 211 212 /* Send data split into 256-byte packets */ 213 214 for (i = 0; i < 16; ++i) { 215 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, 216 S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256); 217 if (ret < 0) 218 break; 219 220 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 221 kfree_skb(msg); 222 if (ret < 0) 223 break; 224 225 hdr = (struct s3fwrn5_fw_header *) rsp->data; 226 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 227 ret = -EPROTO; 228 goto err; 229 } 230 231 kfree_skb(rsp); 232 } 233 234 return ret; 235 236err: 237 kfree_skb(rsp); 238 return ret; 239} 240 241static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info) 242{ 243 struct sk_buff *msg, *rsp = NULL; 244 struct s3fwrn5_fw_header *hdr; 245 int ret; 246 247 /* Send COMPLETE_UPDATE_MODE command */ 248 249 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 250 S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0); 251 if (ret < 0) 252 return ret; 253 254 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 255 kfree_skb(msg); 256 if (ret < 0) 257 return ret; 258 259 hdr = (struct s3fwrn5_fw_header *) rsp->data; 260 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) 261 ret = -EPROTO; 262 263 kfree_skb(rsp); 264 265 return ret; 266} 267 268/* 269 * Firmware header structure: 270 * 271 * 0x00 - 0x0B : Date and time string (w/o NUL termination) 272 * 0x10 - 0x13 : Firmware version 273 * 0x14 - 0x17 : Signature address 274 * 0x18 - 0x1B : Signature size 275 * 0x1C - 0x1F : Firmware image address 276 * 0x20 - 0x23 : Firmware sectors count 277 * 0x24 - 0x27 : Custom signature address 278 * 0x28 - 0x2B : Custom signature size 279 */ 280 281#define S3FWRN5_FW_IMAGE_HEADER_SIZE 44 282 283int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info) 284{ 285 struct s3fwrn5_fw_image *fw = &fw_info->fw; 286 u32 sig_off; 287 u32 image_off; 288 u32 custom_sig_off; 289 int ret; 290 291 ret = request_firmware(&fw->fw, fw_info->fw_name, 292 &fw_info->ndev->nfc_dev->dev); 293 if (ret < 0) 294 return ret; 295 296 if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE) { 297 release_firmware(fw->fw); 298 return -EINVAL; 299 } 300 301 memcpy(fw->date, fw->fw->data + 0x00, 12); 302 fw->date[12] = '\0'; 303 304 memcpy(&fw->version, fw->fw->data + 0x10, 4); 305 306 memcpy(&sig_off, fw->fw->data + 0x14, 4); 307 fw->sig = fw->fw->data + sig_off; 308 memcpy(&fw->sig_size, fw->fw->data + 0x18, 4); 309 310 memcpy(&image_off, fw->fw->data + 0x1C, 4); 311 fw->image = fw->fw->data + image_off; 312 memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4); 313 314 memcpy(&custom_sig_off, fw->fw->data + 0x24, 4); 315 fw->custom_sig = fw->fw->data + custom_sig_off; 316 memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4); 317 318 return 0; 319} 320 321static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info) 322{ 323 release_firmware(fw_info->fw.fw); 324} 325 326static int s3fwrn5_fw_get_base_addr( 327 struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr) 328{ 329 int i; 330 static const struct { 331 u8 version[4]; 332 u32 base_addr; 333 } match[] = { 334 {{0x05, 0x00, 0x00, 0x00}, 0x00005000}, 335 {{0x05, 0x00, 0x00, 0x01}, 0x00003000}, 336 {{0x05, 0x00, 0x00, 0x02}, 0x00003000}, 337 {{0x05, 0x00, 0x00, 0x03}, 0x00003000}, 338 {{0x05, 0x00, 0x00, 0x05}, 0x00003000} 339 }; 340 341 for (i = 0; i < ARRAY_SIZE(match); ++i) 342 if (bootinfo->hw_version[0] == match[i].version[0] && 343 bootinfo->hw_version[1] == match[i].version[1] && 344 bootinfo->hw_version[3] == match[i].version[3]) { 345 *base_addr = match[i].base_addr; 346 return 0; 347 } 348 349 return -EINVAL; 350} 351 352static inline bool 353s3fwrn5_fw_is_custom(const struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo) 354{ 355 return !!bootinfo->hw_version[2]; 356} 357 358int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info) 359{ 360 struct device *dev = &fw_info->ndev->nfc_dev->dev; 361 struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo; 362 int ret; 363 364 /* Get bootloader info */ 365 366 ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo); 367 if (ret < 0) { 368 dev_err(dev, "Failed to get bootinfo, ret=%02x\n", ret); 369 goto err; 370 } 371 372 /* Match hardware version to obtain firmware base address */ 373 374 ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr); 375 if (ret < 0) { 376 dev_err(dev, "Unknown hardware version\n"); 377 goto err; 378 } 379 380 fw_info->sector_size = bootinfo.sector_size; 381 382 fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ? 383 fw_info->fw.custom_sig_size : fw_info->fw.sig_size; 384 fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ? 385 fw_info->fw.custom_sig : fw_info->fw.sig; 386 387 return 0; 388 389err: 390 s3fwrn5_fw_release_firmware(fw_info); 391 return ret; 392} 393 394bool s3fwrn5_fw_check_version(const struct s3fwrn5_fw_info *fw_info, u32 version) 395{ 396 struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version; 397 struct s3fwrn5_fw_version *old = (void *) &version; 398 399 if (new->major > old->major) 400 return true; 401 if (new->build1 > old->build1) 402 return true; 403 if (new->build2 > old->build2) 404 return true; 405 406 return false; 407} 408 409int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info) 410{ 411 struct device *dev = &fw_info->ndev->nfc_dev->dev; 412 struct s3fwrn5_fw_image *fw = &fw_info->fw; 413 u8 hash_data[SHA1_DIGEST_SIZE]; 414 struct crypto_shash *tfm; 415 u32 image_size, off; 416 int ret; 417 418 image_size = fw_info->sector_size * fw->image_sectors; 419 420 /* Compute SHA of firmware data */ 421 422 tfm = crypto_alloc_shash("sha1", 0, 0); 423 if (IS_ERR(tfm)) { 424 dev_err(dev, "Cannot allocate shash (code=%pe)\n", tfm); 425 return PTR_ERR(tfm); 426 } 427 428 ret = crypto_shash_tfm_digest(tfm, fw->image, image_size, hash_data); 429 430 crypto_free_shash(tfm); 431 if (ret) { 432 dev_err(dev, "Cannot compute hash (code=%d)\n", ret); 433 return ret; 434 } 435 436 /* Firmware update process */ 437 438 dev_info(dev, "Firmware update: %s\n", fw_info->fw_name); 439 440 ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data, 441 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size); 442 if (ret < 0) { 443 dev_err(dev, "Unable to enter update mode\n"); 444 return ret; 445 } 446 447 for (off = 0; off < image_size; off += fw_info->sector_size) { 448 ret = s3fwrn5_fw_update_sector(fw_info, 449 fw_info->base_addr + off, fw->image + off); 450 if (ret < 0) { 451 dev_err(dev, "Firmware update error (code=%d)\n", ret); 452 return ret; 453 } 454 } 455 456 ret = s3fwrn5_fw_complete_update_mode(fw_info); 457 if (ret < 0) { 458 dev_err(dev, "Unable to complete update mode\n"); 459 return ret; 460 } 461 462 dev_info(dev, "Firmware update: success\n"); 463 464 return ret; 465} 466 467void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name) 468{ 469 fw_info->parity = 0x00; 470 fw_info->rsp = NULL; 471 fw_info->fw.fw = NULL; 472 strcpy(fw_info->fw_name, fw_name); 473 init_completion(&fw_info->completion); 474} 475 476void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info) 477{ 478 s3fwrn5_fw_release_firmware(fw_info); 479} 480 481int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) 482{ 483 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 484 struct s3fwrn5_fw_info *fw_info = &info->fw_info; 485 486 if (WARN_ON(fw_info->rsp)) { 487 kfree_skb(skb); 488 return -EINVAL; 489 } 490 491 fw_info->rsp = skb; 492 493 complete(&fw_info->completion); 494 495 return 0; 496}