Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Marvell NFC driver: Firmware downloader
0004  *
0005  * Copyright (C) 2015, Marvell International Ltd.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <asm/unaligned.h>
0010 #include <linux/firmware.h>
0011 #include <linux/nfc.h>
0012 #include <net/nfc/nci.h>
0013 #include <net/nfc/nci_core.h>
0014 #include "nfcmrvl.h"
0015 
0016 #define FW_DNLD_TIMEOUT         15000
0017 
0018 #define NCI_OP_PROPRIETARY_BOOT_CMD nci_opcode_pack(NCI_GID_PROPRIETARY, \
0019                             NCI_OP_PROP_BOOT_CMD)
0020 
0021 /* FW download states */
0022 
0023 enum {
0024     STATE_RESET = 0,
0025     STATE_INIT,
0026     STATE_SET_REF_CLOCK,
0027     STATE_SET_HI_CONFIG,
0028     STATE_OPEN_LC,
0029     STATE_FW_DNLD,
0030     STATE_CLOSE_LC,
0031     STATE_BOOT
0032 };
0033 
0034 enum {
0035     SUBSTATE_WAIT_COMMAND = 0,
0036     SUBSTATE_WAIT_ACK_CREDIT,
0037     SUBSTATE_WAIT_NACK_CREDIT,
0038     SUBSTATE_WAIT_DATA_CREDIT,
0039 };
0040 
0041 /*
0042  * Patterns for responses
0043  */
0044 
0045 static const uint8_t nci_pattern_core_reset_ntf[] = {
0046     0x60, 0x00, 0x02, 0xA0, 0x01
0047 };
0048 
0049 static const uint8_t nci_pattern_core_init_rsp[] = {
0050     0x40, 0x01, 0x11
0051 };
0052 
0053 static const uint8_t nci_pattern_core_set_config_rsp[] = {
0054     0x40, 0x02, 0x02, 0x00, 0x00
0055 };
0056 
0057 static const uint8_t nci_pattern_core_conn_create_rsp[] = {
0058     0x40, 0x04, 0x04, 0x00
0059 };
0060 
0061 static const uint8_t nci_pattern_core_conn_close_rsp[] = {
0062     0x40, 0x05, 0x01, 0x00
0063 };
0064 
0065 static const uint8_t nci_pattern_core_conn_credits_ntf[] = {
0066     0x60, 0x06, 0x03, 0x01, NCI_CORE_LC_CONNID_PROP_FW_DL, 0x01
0067 };
0068 
0069 static const uint8_t nci_pattern_proprietary_boot_rsp[] = {
0070     0x4F, 0x3A, 0x01, 0x00
0071 };
0072 
0073 static struct sk_buff *alloc_lc_skb(struct nfcmrvl_private *priv, uint8_t plen)
0074 {
0075     struct sk_buff *skb;
0076     struct nci_data_hdr *hdr;
0077 
0078     skb = nci_skb_alloc(priv->ndev, (NCI_DATA_HDR_SIZE + plen), GFP_KERNEL);
0079     if (!skb)
0080         return NULL;
0081 
0082     hdr = skb_put(skb, NCI_DATA_HDR_SIZE);
0083     hdr->conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
0084     hdr->rfu = 0;
0085     hdr->plen = plen;
0086 
0087     nci_mt_set((__u8 *)hdr, NCI_MT_DATA_PKT);
0088     nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
0089 
0090     return skb;
0091 }
0092 
0093 static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error)
0094 {
0095     if (priv->fw_dnld.fw) {
0096         release_firmware(priv->fw_dnld.fw);
0097         priv->fw_dnld.fw = NULL;
0098         priv->fw_dnld.header = NULL;
0099         priv->fw_dnld.binary_config = NULL;
0100     }
0101 
0102     atomic_set(&priv->ndev->cmd_cnt, 0);
0103 
0104     if (timer_pending(&priv->ndev->cmd_timer))
0105         del_timer_sync(&priv->ndev->cmd_timer);
0106 
0107     if (timer_pending(&priv->fw_dnld.timer))
0108         del_timer_sync(&priv->fw_dnld.timer);
0109 
0110     nfc_info(priv->dev, "FW loading over (%d)]\n", error);
0111 
0112     if (error != 0) {
0113         /* failed, halt the chip to avoid power consumption */
0114         nfcmrvl_chip_halt(priv);
0115     }
0116 
0117     nfc_fw_download_done(priv->ndev->nfc_dev, priv->fw_dnld.name, error);
0118 }
0119 
0120 static void fw_dnld_timeout(struct timer_list *t)
0121 {
0122     struct nfcmrvl_private *priv = from_timer(priv, t, fw_dnld.timer);
0123 
0124     nfc_err(priv->dev, "FW loading timeout");
0125     priv->fw_dnld.state = STATE_RESET;
0126     fw_dnld_over(priv, -ETIMEDOUT);
0127 }
0128 
0129 static int process_state_reset(struct nfcmrvl_private *priv,
0130                    const struct sk_buff *skb)
0131 {
0132     if (sizeof(nci_pattern_core_reset_ntf) != skb->len ||
0133         memcmp(skb->data, nci_pattern_core_reset_ntf,
0134            sizeof(nci_pattern_core_reset_ntf)))
0135         return -EINVAL;
0136 
0137     nfc_info(priv->dev, "BootROM reset, start fw download\n");
0138 
0139     /* Start FW download state machine */
0140     priv->fw_dnld.state = STATE_INIT;
0141     nci_send_cmd(priv->ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
0142 
0143     return 0;
0144 }
0145 
0146 static int process_state_init(struct nfcmrvl_private *priv,
0147                   const struct sk_buff *skb)
0148 {
0149     struct nci_core_set_config_cmd cmd;
0150 
0151     if (sizeof(nci_pattern_core_init_rsp) >= skb->len ||
0152         memcmp(skb->data, nci_pattern_core_init_rsp,
0153            sizeof(nci_pattern_core_init_rsp)))
0154         return -EINVAL;
0155 
0156     cmd.num_params = 1;
0157     cmd.param.id = NFCMRVL_PROP_REF_CLOCK;
0158     cmd.param.len = 4;
0159     memcpy(cmd.param.val, &priv->fw_dnld.header->ref_clock, 4);
0160 
0161     nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len,
0162              &cmd);
0163 
0164     priv->fw_dnld.state = STATE_SET_REF_CLOCK;
0165     return 0;
0166 }
0167 
0168 static void create_lc(struct nfcmrvl_private *priv)
0169 {
0170     uint8_t param[2] = { NCI_CORE_LC_PROP_FW_DL, 0x0 };
0171 
0172     priv->fw_dnld.state = STATE_OPEN_LC;
0173     nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, param);
0174 }
0175 
0176 static int process_state_set_ref_clock(struct nfcmrvl_private *priv,
0177                        const struct sk_buff *skb)
0178 {
0179     struct nci_core_set_config_cmd cmd;
0180 
0181     if (sizeof(nci_pattern_core_set_config_rsp) != skb->len ||
0182         memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len))
0183         return -EINVAL;
0184 
0185     cmd.num_params = 1;
0186     cmd.param.id = NFCMRVL_PROP_SET_HI_CONFIG;
0187 
0188     switch (priv->phy) {
0189     case NFCMRVL_PHY_UART:
0190         cmd.param.len = 5;
0191         memcpy(cmd.param.val,
0192                &priv->fw_dnld.binary_config->uart.baudrate,
0193                4);
0194         cmd.param.val[4] =
0195             priv->fw_dnld.binary_config->uart.flow_control;
0196         break;
0197     case NFCMRVL_PHY_I2C:
0198         cmd.param.len = 5;
0199         memcpy(cmd.param.val,
0200                &priv->fw_dnld.binary_config->i2c.clk,
0201                4);
0202         cmd.param.val[4] = 0;
0203         break;
0204     case NFCMRVL_PHY_SPI:
0205         cmd.param.len = 5;
0206         memcpy(cmd.param.val,
0207                &priv->fw_dnld.binary_config->spi.clk,
0208                4);
0209         cmd.param.val[4] = 0;
0210         break;
0211     default:
0212         create_lc(priv);
0213         return 0;
0214     }
0215 
0216     priv->fw_dnld.state = STATE_SET_HI_CONFIG;
0217     nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len,
0218              &cmd);
0219     return 0;
0220 }
0221 
0222 static int process_state_set_hi_config(struct nfcmrvl_private *priv,
0223                        const struct sk_buff *skb)
0224 {
0225     if (sizeof(nci_pattern_core_set_config_rsp) != skb->len ||
0226         memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len))
0227         return -EINVAL;
0228 
0229     create_lc(priv);
0230     return 0;
0231 }
0232 
0233 static int process_state_open_lc(struct nfcmrvl_private *priv,
0234                  const struct sk_buff *skb)
0235 {
0236     if (sizeof(nci_pattern_core_conn_create_rsp) >= skb->len ||
0237         memcmp(skb->data, nci_pattern_core_conn_create_rsp,
0238            sizeof(nci_pattern_core_conn_create_rsp)))
0239         return -EINVAL;
0240 
0241     priv->fw_dnld.state = STATE_FW_DNLD;
0242     priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
0243     priv->fw_dnld.offset = priv->fw_dnld.binary_config->offset;
0244     return 0;
0245 }
0246 
0247 static int process_state_fw_dnld(struct nfcmrvl_private *priv,
0248                  struct sk_buff *skb)
0249 {
0250     uint16_t len;
0251     uint16_t comp_len;
0252     struct sk_buff *out_skb;
0253 
0254     switch (priv->fw_dnld.substate) {
0255     case SUBSTATE_WAIT_COMMAND:
0256         /*
0257          * Command format:
0258          * B0..2: NCI header
0259          * B3   : Helper command (0xA5)
0260          * B4..5: le16 data size
0261          * B6..7: le16 data size complement (~)
0262          * B8..N: payload
0263          */
0264 
0265         /* Remove NCI HDR */
0266         skb_pull(skb, 3);
0267         if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) {
0268             nfc_err(priv->dev, "bad command");
0269             return -EINVAL;
0270         }
0271         skb_pull(skb, 1);
0272         len = get_unaligned_le16(skb->data);
0273         skb_pull(skb, 2);
0274         comp_len = get_unaligned_le16(skb->data);
0275         memcpy(&comp_len, skb->data, 2);
0276         skb_pull(skb, 2);
0277         if (((~len) & 0xFFFF) != comp_len) {
0278             nfc_err(priv->dev, "bad len complement: %x %x %x",
0279                 len, comp_len, (~len & 0xFFFF));
0280             out_skb = alloc_lc_skb(priv, 1);
0281             if (!out_skb)
0282                 return -ENOMEM;
0283             skb_put_u8(out_skb, 0xBF);
0284             nci_send_frame(priv->ndev, out_skb);
0285             priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT;
0286             return 0;
0287         }
0288         priv->fw_dnld.chunk_len = len;
0289         out_skb = alloc_lc_skb(priv, 1);
0290         if (!out_skb)
0291             return -ENOMEM;
0292         skb_put_u8(out_skb, HELPER_ACK_PACKET_FORMAT);
0293         nci_send_frame(priv->ndev, out_skb);
0294         priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT;
0295         break;
0296 
0297     case SUBSTATE_WAIT_ACK_CREDIT:
0298         if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
0299             memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
0300                skb->len)) {
0301             nfc_err(priv->dev, "bad packet: waiting for credit");
0302             return -EINVAL;
0303         }
0304         if (priv->fw_dnld.chunk_len == 0) {
0305             /* FW Loading is done */
0306             uint8_t conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
0307 
0308             priv->fw_dnld.state = STATE_CLOSE_LC;
0309             nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CLOSE_CMD,
0310                      1, &conn_id);
0311         } else {
0312             out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len);
0313             if (!out_skb)
0314                 return -ENOMEM;
0315             skb_put_data(out_skb,
0316                      ((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset,
0317                      priv->fw_dnld.chunk_len);
0318             nci_send_frame(priv->ndev, out_skb);
0319             priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT;
0320         }
0321         break;
0322 
0323     case SUBSTATE_WAIT_DATA_CREDIT:
0324         if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
0325             memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
0326                 skb->len)) {
0327             nfc_err(priv->dev, "bad packet: waiting for credit");
0328             return -EINVAL;
0329         }
0330         priv->fw_dnld.offset += priv->fw_dnld.chunk_len;
0331         priv->fw_dnld.chunk_len = 0;
0332         priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
0333         break;
0334 
0335     case SUBSTATE_WAIT_NACK_CREDIT:
0336         if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
0337             memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
0338                 skb->len)) {
0339             nfc_err(priv->dev, "bad packet: waiting for credit");
0340             return -EINVAL;
0341         }
0342         priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
0343         break;
0344     }
0345     return 0;
0346 }
0347 
0348 static int process_state_close_lc(struct nfcmrvl_private *priv,
0349                   const struct sk_buff *skb)
0350 {
0351     if (sizeof(nci_pattern_core_conn_close_rsp) != skb->len ||
0352         memcmp(skb->data, nci_pattern_core_conn_close_rsp, skb->len))
0353         return -EINVAL;
0354 
0355     priv->fw_dnld.state = STATE_BOOT;
0356     nci_send_cmd(priv->ndev, NCI_OP_PROPRIETARY_BOOT_CMD, 0, NULL);
0357     return 0;
0358 }
0359 
0360 static int process_state_boot(struct nfcmrvl_private *priv,
0361                   const struct sk_buff *skb)
0362 {
0363     if (sizeof(nci_pattern_proprietary_boot_rsp) != skb->len ||
0364         memcmp(skb->data, nci_pattern_proprietary_boot_rsp, skb->len))
0365         return -EINVAL;
0366 
0367     /*
0368      * Update HI config to use the right configuration for the next
0369      * data exchanges.
0370      */
0371     priv->if_ops->nci_update_config(priv,
0372                     &priv->fw_dnld.binary_config->config);
0373 
0374     if (priv->fw_dnld.binary_config == &priv->fw_dnld.header->helper) {
0375         /*
0376          * This is the case where an helper was needed and we have
0377          * uploaded it. Now we have to wait the next RESET NTF to start
0378          * FW download.
0379          */
0380         priv->fw_dnld.state = STATE_RESET;
0381         priv->fw_dnld.binary_config = &priv->fw_dnld.header->firmware;
0382         nfc_info(priv->dev, "FW loading: helper loaded");
0383     } else {
0384         nfc_info(priv->dev, "FW loading: firmware loaded");
0385         fw_dnld_over(priv, 0);
0386     }
0387     return 0;
0388 }
0389 
0390 static void fw_dnld_rx_work(struct work_struct *work)
0391 {
0392     int ret;
0393     struct sk_buff *skb;
0394     struct nfcmrvl_fw_dnld *fw_dnld = container_of(work,
0395                                struct nfcmrvl_fw_dnld,
0396                                rx_work);
0397     struct nfcmrvl_private *priv = container_of(fw_dnld,
0398                             struct nfcmrvl_private,
0399                             fw_dnld);
0400 
0401     while ((skb = skb_dequeue(&fw_dnld->rx_q))) {
0402         nfc_send_to_raw_sock(priv->ndev->nfc_dev, skb,
0403                      RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
0404         switch (fw_dnld->state) {
0405         case STATE_RESET:
0406             ret = process_state_reset(priv, skb);
0407             break;
0408         case STATE_INIT:
0409             ret = process_state_init(priv, skb);
0410             break;
0411         case STATE_SET_REF_CLOCK:
0412             ret = process_state_set_ref_clock(priv, skb);
0413             break;
0414         case STATE_SET_HI_CONFIG:
0415             ret = process_state_set_hi_config(priv, skb);
0416             break;
0417         case STATE_OPEN_LC:
0418             ret = process_state_open_lc(priv, skb);
0419             break;
0420         case STATE_FW_DNLD:
0421             ret = process_state_fw_dnld(priv, skb);
0422             break;
0423         case STATE_CLOSE_LC:
0424             ret = process_state_close_lc(priv, skb);
0425             break;
0426         case STATE_BOOT:
0427             ret = process_state_boot(priv, skb);
0428             break;
0429         default:
0430             ret = -EFAULT;
0431         }
0432 
0433         kfree_skb(skb);
0434 
0435         if (ret != 0) {
0436             nfc_err(priv->dev, "FW loading error");
0437             fw_dnld_over(priv, ret);
0438             break;
0439         }
0440     }
0441 }
0442 
0443 int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv)
0444 {
0445     char name[32];
0446 
0447     INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work);
0448     snprintf(name, sizeof(name), "%s_nfcmrvl_fw_dnld_rx_wq",
0449          dev_name(&priv->ndev->nfc_dev->dev));
0450     priv->fw_dnld.rx_wq = create_singlethread_workqueue(name);
0451     if (!priv->fw_dnld.rx_wq)
0452         return -ENOMEM;
0453     skb_queue_head_init(&priv->fw_dnld.rx_q);
0454     return 0;
0455 }
0456 
0457 void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv)
0458 {
0459     destroy_workqueue(priv->fw_dnld.rx_wq);
0460 }
0461 
0462 void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
0463                 struct sk_buff *skb)
0464 {
0465     /* Discard command timer */
0466     if (timer_pending(&priv->ndev->cmd_timer))
0467         del_timer_sync(&priv->ndev->cmd_timer);
0468 
0469     /* Allow next command */
0470     atomic_set(&priv->ndev->cmd_cnt, 1);
0471 
0472     /* Queue and trigger rx work */
0473     skb_queue_tail(&priv->fw_dnld.rx_q, skb);
0474     queue_work(priv->fw_dnld.rx_wq, &priv->fw_dnld.rx_work);
0475 }
0476 
0477 void nfcmrvl_fw_dnld_abort(struct nfcmrvl_private *priv)
0478 {
0479     fw_dnld_over(priv, -EHOSTDOWN);
0480 }
0481 
0482 int nfcmrvl_fw_dnld_start(struct nci_dev *ndev, const char *firmware_name)
0483 {
0484     struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
0485     struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld;
0486     int res;
0487 
0488     if (!priv->support_fw_dnld)
0489         return -ENOTSUPP;
0490 
0491     if (!firmware_name || !firmware_name[0])
0492         return -EINVAL;
0493 
0494     strcpy(fw_dnld->name, firmware_name);
0495 
0496     /*
0497      * Retrieve FW binary file and parse it to initialize FW download
0498      * state machine.
0499      */
0500 
0501     /* Retrieve FW binary */
0502     res = request_firmware(&fw_dnld->fw, firmware_name,
0503                    &ndev->nfc_dev->dev);
0504     if (res < 0) {
0505         nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name);
0506         return -ENOENT;
0507     }
0508 
0509     fw_dnld->header = (const struct nfcmrvl_fw *) priv->fw_dnld.fw->data;
0510 
0511     if (fw_dnld->header->magic != NFCMRVL_FW_MAGIC ||
0512         fw_dnld->header->phy != priv->phy) {
0513         nfc_err(priv->dev, "bad firmware binary %s magic=0x%x phy=%d",
0514             firmware_name, fw_dnld->header->magic,
0515             fw_dnld->header->phy);
0516         release_firmware(fw_dnld->fw);
0517         fw_dnld->header = NULL;
0518         return -EINVAL;
0519     }
0520 
0521     if (fw_dnld->header->helper.offset != 0) {
0522         nfc_info(priv->dev, "loading helper");
0523         fw_dnld->binary_config = &fw_dnld->header->helper;
0524     } else {
0525         nfc_info(priv->dev, "loading firmware");
0526         fw_dnld->binary_config = &fw_dnld->header->firmware;
0527     }
0528 
0529     /* Configure a timer for timeout */
0530     timer_setup(&priv->fw_dnld.timer, fw_dnld_timeout, 0);
0531     mod_timer(&priv->fw_dnld.timer,
0532           jiffies + msecs_to_jiffies(FW_DNLD_TIMEOUT));
0533 
0534     /* Ronfigure HI to be sure that it is the bootrom values */
0535     priv->if_ops->nci_update_config(priv,
0536                     &fw_dnld->header->bootrom.config);
0537 
0538     /* Allow first command */
0539     atomic_set(&priv->ndev->cmd_cnt, 1);
0540 
0541     /* First, reset the chip */
0542     priv->fw_dnld.state = STATE_RESET;
0543     nfcmrvl_chip_reset(priv);
0544 
0545     /* Now wait for CORE_RESET_NTF or timeout */
0546 
0547     return 0;
0548 }