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 17 struct s3fwrn5_fw_version { 18 __u8 major; 19 __u8 build1; 20 __u8 build2; 21 __u8 target; 22 }; 23 24 static 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 53 static 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 77 static 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 104 out: 105 kfree_skb(rsp); 106 return ret; 107 } 108 109 static 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 177 out: 178 kfree_skb(rsp); 179 return ret; 180 } 181 182 static 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 236 err: 237 kfree_skb(rsp); 238 return ret; 239 } 240 241 static 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 283 int 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 321 static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info) 322 { 323 release_firmware(fw_info->fw.fw); 324 } 325 326 static 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 352 static inline bool 353 s3fwrn5_fw_is_custom(const struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo) 354 { 355 return !!bootinfo->hw_version[2]; 356 } 357 358 int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info) 359 { 360 struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo; 361 int ret; 362 363 /* Get bootloader info */ 364 365 ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo); 366 if (ret < 0) { 367 dev_err(&fw_info->ndev->nfc_dev->dev, 368 "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(&fw_info->ndev->nfc_dev->dev, 377 "Unknown hardware version\n"); 378 goto err; 379 } 380 381 fw_info->sector_size = bootinfo.sector_size; 382 383 fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ? 384 fw_info->fw.custom_sig_size : fw_info->fw.sig_size; 385 fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ? 386 fw_info->fw.custom_sig : fw_info->fw.sig; 387 388 return 0; 389 390 err: 391 s3fwrn5_fw_release_firmware(fw_info); 392 return ret; 393 } 394 395 bool s3fwrn5_fw_check_version(const struct s3fwrn5_fw_info *fw_info, u32 version) 396 { 397 struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version; 398 struct s3fwrn5_fw_version *old = (void *) &version; 399 400 if (new->major > old->major) 401 return true; 402 if (new->build1 > old->build1) 403 return true; 404 if (new->build2 > old->build2) 405 return true; 406 407 return false; 408 } 409 410 int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info) 411 { 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 ret = PTR_ERR(tfm); 425 dev_err(&fw_info->ndev->nfc_dev->dev, 426 "Cannot allocate shash (code=%d)\n", ret); 427 goto out; 428 } 429 430 ret = crypto_shash_tfm_digest(tfm, fw->image, image_size, hash_data); 431 432 crypto_free_shash(tfm); 433 if (ret) { 434 dev_err(&fw_info->ndev->nfc_dev->dev, 435 "Cannot compute hash (code=%d)\n", ret); 436 goto out; 437 } 438 439 /* Firmware update process */ 440 441 dev_info(&fw_info->ndev->nfc_dev->dev, 442 "Firmware update: %s\n", fw_info->fw_name); 443 444 ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data, 445 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size); 446 if (ret < 0) { 447 dev_err(&fw_info->ndev->nfc_dev->dev, 448 "Unable to enter update mode\n"); 449 goto out; 450 } 451 452 for (off = 0; off < image_size; off += fw_info->sector_size) { 453 ret = s3fwrn5_fw_update_sector(fw_info, 454 fw_info->base_addr + off, fw->image + off); 455 if (ret < 0) { 456 dev_err(&fw_info->ndev->nfc_dev->dev, 457 "Firmware update error (code=%d)\n", ret); 458 goto out; 459 } 460 } 461 462 ret = s3fwrn5_fw_complete_update_mode(fw_info); 463 if (ret < 0) { 464 dev_err(&fw_info->ndev->nfc_dev->dev, 465 "Unable to complete update mode\n"); 466 goto out; 467 } 468 469 dev_info(&fw_info->ndev->nfc_dev->dev, 470 "Firmware update: success\n"); 471 472 out: 473 return ret; 474 } 475 476 void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name) 477 { 478 fw_info->parity = 0x00; 479 fw_info->rsp = NULL; 480 fw_info->fw.fw = NULL; 481 strcpy(fw_info->fw_name, fw_name); 482 init_completion(&fw_info->completion); 483 } 484 485 void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info) 486 { 487 s3fwrn5_fw_release_firmware(fw_info); 488 } 489 490 int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) 491 { 492 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 493 struct s3fwrn5_fw_info *fw_info = &info->fw_info; 494 495 if (WARN_ON(fw_info->rsp)) { 496 kfree_skb(skb); 497 return -EINVAL; 498 } 499 500 fw_info->rsp = skb; 501 502 complete(&fw_info->completion); 503 504 return 0; 505 } 506