root/drivers/nfc/s3fwrn5/firmware.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3fwrn5_fw_send_msg
  2. s3fwrn5_fw_prep_msg
  3. s3fwrn5_fw_get_bootinfo
  4. s3fwrn5_fw_enter_update_mode
  5. s3fwrn5_fw_update_sector
  6. s3fwrn5_fw_complete_update_mode
  7. s3fwrn5_fw_request_firmware
  8. s3fwrn5_fw_release_firmware
  9. s3fwrn5_fw_get_base_addr
  10. s3fwrn5_fw_is_custom
  11. s3fwrn5_fw_setup
  12. s3fwrn5_fw_check_version
  13. s3fwrn5_fw_download
  14. s3fwrn5_fw_init
  15. s3fwrn5_fw_cleanup
  16. s3fwrn5_fw_recv_frame

   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 
  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 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 
 283 static 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                 return -EINVAL;
 298 
 299         memcpy(fw->date, fw->fw->data + 0x00, 12);
 300         fw->date[12] = '\0';
 301 
 302         memcpy(&fw->version, fw->fw->data + 0x10, 4);
 303 
 304         memcpy(&sig_off, fw->fw->data + 0x14, 4);
 305         fw->sig = fw->fw->data + sig_off;
 306         memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
 307 
 308         memcpy(&image_off, fw->fw->data + 0x1C, 4);
 309         fw->image = fw->fw->data + image_off;
 310         memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
 311 
 312         memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
 313         fw->custom_sig = fw->fw->data + custom_sig_off;
 314         memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
 315 
 316         return 0;
 317 }
 318 
 319 static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
 320 {
 321         release_firmware(fw_info->fw.fw);
 322 }
 323 
 324 static int s3fwrn5_fw_get_base_addr(
 325         struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
 326 {
 327         int i;
 328         static const struct {
 329                 u8 version[4];
 330                 u32 base_addr;
 331         } match[] = {
 332                 {{0x05, 0x00, 0x00, 0x00}, 0x00005000},
 333                 {{0x05, 0x00, 0x00, 0x01}, 0x00003000},
 334                 {{0x05, 0x00, 0x00, 0x02}, 0x00003000},
 335                 {{0x05, 0x00, 0x00, 0x03}, 0x00003000},
 336                 {{0x05, 0x00, 0x00, 0x05}, 0x00003000}
 337         };
 338 
 339         for (i = 0; i < ARRAY_SIZE(match); ++i)
 340                 if (bootinfo->hw_version[0] == match[i].version[0] &&
 341                         bootinfo->hw_version[1] == match[i].version[1] &&
 342                         bootinfo->hw_version[3] == match[i].version[3]) {
 343                         *base_addr = match[i].base_addr;
 344                         return 0;
 345                 }
 346 
 347         return -EINVAL;
 348 }
 349 
 350 static inline bool
 351 s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
 352 {
 353         return !!bootinfo->hw_version[2];
 354 }
 355 
 356 int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
 357 {
 358         struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
 359         int ret;
 360 
 361         /* Get firmware data */
 362 
 363         ret = s3fwrn5_fw_request_firmware(fw_info);
 364         if (ret < 0) {
 365                 dev_err(&fw_info->ndev->nfc_dev->dev,
 366                         "Failed to get fw file, ret=%02x\n", ret);
 367                 return ret;
 368         }
 369 
 370         /* Get bootloader info */
 371 
 372         ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
 373         if (ret < 0) {
 374                 dev_err(&fw_info->ndev->nfc_dev->dev,
 375                         "Failed to get bootinfo, ret=%02x\n", ret);
 376                 goto err;
 377         }
 378 
 379         /* Match hardware version to obtain firmware base address */
 380 
 381         ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
 382         if (ret < 0) {
 383                 dev_err(&fw_info->ndev->nfc_dev->dev,
 384                         "Unknown hardware version\n");
 385                 goto err;
 386         }
 387 
 388         fw_info->sector_size = bootinfo.sector_size;
 389 
 390         fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
 391                 fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
 392         fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
 393                 fw_info->fw.custom_sig : fw_info->fw.sig;
 394 
 395         return 0;
 396 
 397 err:
 398         s3fwrn5_fw_release_firmware(fw_info);
 399         return ret;
 400 }
 401 
 402 bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
 403 {
 404         struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
 405         struct s3fwrn5_fw_version *old = (void *) &version;
 406 
 407         if (new->major > old->major)
 408                 return true;
 409         if (new->build1 > old->build1)
 410                 return true;
 411         if (new->build2 > old->build2)
 412                 return true;
 413 
 414         return false;
 415 }
 416 
 417 int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
 418 {
 419         struct s3fwrn5_fw_image *fw = &fw_info->fw;
 420         u8 hash_data[SHA1_DIGEST_SIZE];
 421         struct crypto_shash *tfm;
 422         u32 image_size, off;
 423         int ret;
 424 
 425         image_size = fw_info->sector_size * fw->image_sectors;
 426 
 427         /* Compute SHA of firmware data */
 428 
 429         tfm = crypto_alloc_shash("sha1", 0, 0);
 430         if (IS_ERR(tfm)) {
 431                 ret = PTR_ERR(tfm);
 432                 dev_err(&fw_info->ndev->nfc_dev->dev,
 433                         "Cannot allocate shash (code=%d)\n", ret);
 434                 goto out;
 435         }
 436 
 437         {
 438                 SHASH_DESC_ON_STACK(desc, tfm);
 439 
 440                 desc->tfm = tfm;
 441 
 442                 ret = crypto_shash_digest(desc, fw->image, image_size,
 443                                           hash_data);
 444                 shash_desc_zero(desc);
 445         }
 446 
 447         crypto_free_shash(tfm);
 448         if (ret) {
 449                 dev_err(&fw_info->ndev->nfc_dev->dev,
 450                         "Cannot compute hash (code=%d)\n", ret);
 451                 goto out;
 452         }
 453 
 454         /* Firmware update process */
 455 
 456         dev_info(&fw_info->ndev->nfc_dev->dev,
 457                 "Firmware update: %s\n", fw_info->fw_name);
 458 
 459         ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
 460                 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
 461         if (ret < 0) {
 462                 dev_err(&fw_info->ndev->nfc_dev->dev,
 463                         "Unable to enter update mode\n");
 464                 goto out;
 465         }
 466 
 467         for (off = 0; off < image_size; off += fw_info->sector_size) {
 468                 ret = s3fwrn5_fw_update_sector(fw_info,
 469                         fw_info->base_addr + off, fw->image + off);
 470                 if (ret < 0) {
 471                         dev_err(&fw_info->ndev->nfc_dev->dev,
 472                                 "Firmware update error (code=%d)\n", ret);
 473                         goto out;
 474                 }
 475         }
 476 
 477         ret = s3fwrn5_fw_complete_update_mode(fw_info);
 478         if (ret < 0) {
 479                 dev_err(&fw_info->ndev->nfc_dev->dev,
 480                         "Unable to complete update mode\n");
 481                 goto out;
 482         }
 483 
 484         dev_info(&fw_info->ndev->nfc_dev->dev,
 485                 "Firmware update: success\n");
 486 
 487 out:
 488         return ret;
 489 }
 490 
 491 void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
 492 {
 493         fw_info->parity = 0x00;
 494         fw_info->rsp = NULL;
 495         fw_info->fw.fw = NULL;
 496         strcpy(fw_info->fw_name, fw_name);
 497         init_completion(&fw_info->completion);
 498 }
 499 
 500 void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
 501 {
 502         s3fwrn5_fw_release_firmware(fw_info);
 503 }
 504 
 505 int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
 506 {
 507         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
 508         struct s3fwrn5_fw_info *fw_info = &info->fw_info;
 509 
 510         BUG_ON(fw_info->rsp);
 511 
 512         fw_info->rsp = skb;
 513 
 514         complete(&fw_info->completion);
 515 
 516         return 0;
 517 }

/* [<][>][^][v][top][bottom][index][help] */