0001
0002
0003
0004
0005
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
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
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
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
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
0258
0259
0260
0261
0262
0263
0264
0265
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
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
0369
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
0377
0378
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
0466 if (timer_pending(&priv->ndev->cmd_timer))
0467 del_timer_sync(&priv->ndev->cmd_timer);
0468
0469
0470 atomic_set(&priv->ndev->cmd_cnt, 1);
0471
0472
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
0498
0499
0500
0501
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
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
0535 priv->if_ops->nci_update_config(priv,
0536 &fw_dnld->header->bootrom.config);
0537
0538
0539 atomic_set(&priv->ndev->cmd_cnt, 1);
0540
0541
0542 priv->fw_dnld.state = STATE_RESET;
0543 nfcmrvl_chip_reset(priv);
0544
0545
0546
0547 return 0;
0548 }