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/sha.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 stucture: 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 283static 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 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 s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo; 361 int ret; 362 363 /* Get firmware data */ 364 365 ret = s3fwrn5_fw_request_firmware(fw_info); 366 if (ret < 0) { 367 dev_err(&fw_info->ndev->nfc_dev->dev, 368 "Failed to get fw file, ret=%02x\n", ret); 369 return ret; 370 } 371 372 /* Get bootloader info */ 373 374 ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo); 375 if (ret < 0) { 376 dev_err(&fw_info->ndev->nfc_dev->dev, 377 "Failed to get bootinfo, ret=%02x\n", ret); 378 goto err; 379 } 380 381 /* Match hardware version to obtain firmware base address */ 382 383 ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr); 384 if (ret < 0) { 385 dev_err(&fw_info->ndev->nfc_dev->dev, 386 "Unknown hardware version\n"); 387 goto err; 388 } 389 390 fw_info->sector_size = bootinfo.sector_size; 391 392 fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ? 393 fw_info->fw.custom_sig_size : fw_info->fw.sig_size; 394 fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ? 395 fw_info->fw.custom_sig : fw_info->fw.sig; 396 397 return 0; 398 399err: 400 s3fwrn5_fw_release_firmware(fw_info); 401 return ret; 402} 403 404bool s3fwrn5_fw_check_version(const struct s3fwrn5_fw_info *fw_info, u32 version) 405{ 406 struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version; 407 struct s3fwrn5_fw_version *old = (void *) &version; 408 409 if (new->major > old->major) 410 return true; 411 if (new->build1 > old->build1) 412 return true; 413 if (new->build2 > old->build2) 414 return true; 415 416 return false; 417} 418 419int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info) 420{ 421 struct s3fwrn5_fw_image *fw = &fw_info->fw; 422 u8 hash_data[SHA1_DIGEST_SIZE]; 423 struct crypto_shash *tfm; 424 u32 image_size, off; 425 int ret; 426 427 image_size = fw_info->sector_size * fw->image_sectors; 428 429 /* Compute SHA of firmware data */ 430 431 tfm = crypto_alloc_shash("sha1", 0, 0); 432 if (IS_ERR(tfm)) { 433 ret = PTR_ERR(tfm); 434 dev_err(&fw_info->ndev->nfc_dev->dev, 435 "Cannot allocate shash (code=%d)\n", ret); 436 goto out; 437 } 438 439 ret = crypto_shash_tfm_digest(tfm, fw->image, image_size, hash_data); 440 441 crypto_free_shash(tfm); 442 if (ret) { 443 dev_err(&fw_info->ndev->nfc_dev->dev, 444 "Cannot compute hash (code=%d)\n", ret); 445 goto out; 446 } 447 448 /* Firmware update process */ 449 450 dev_info(&fw_info->ndev->nfc_dev->dev, 451 "Firmware update: %s\n", fw_info->fw_name); 452 453 ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data, 454 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size); 455 if (ret < 0) { 456 dev_err(&fw_info->ndev->nfc_dev->dev, 457 "Unable to enter update mode\n"); 458 goto out; 459 } 460 461 for (off = 0; off < image_size; off += fw_info->sector_size) { 462 ret = s3fwrn5_fw_update_sector(fw_info, 463 fw_info->base_addr + off, fw->image + off); 464 if (ret < 0) { 465 dev_err(&fw_info->ndev->nfc_dev->dev, 466 "Firmware update error (code=%d)\n", ret); 467 goto out; 468 } 469 } 470 471 ret = s3fwrn5_fw_complete_update_mode(fw_info); 472 if (ret < 0) { 473 dev_err(&fw_info->ndev->nfc_dev->dev, 474 "Unable to complete update mode\n"); 475 goto out; 476 } 477 478 dev_info(&fw_info->ndev->nfc_dev->dev, 479 "Firmware update: success\n"); 480 481out: 482 return ret; 483} 484 485void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name) 486{ 487 fw_info->parity = 0x00; 488 fw_info->rsp = NULL; 489 fw_info->fw.fw = NULL; 490 strcpy(fw_info->fw_name, fw_name); 491 init_completion(&fw_info->completion); 492} 493 494void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info) 495{ 496 s3fwrn5_fw_release_firmware(fw_info); 497} 498 499int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) 500{ 501 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 502 struct s3fwrn5_fw_info *fw_info = &info->fw_info; 503 504 if (WARN_ON(fw_info->rsp)) { 505 kfree_skb(skb); 506 return -EINVAL; 507 } 508 509 fw_info->rsp = skb; 510 511 complete(&fw_info->completion); 512 513 return 0; 514} 515