Lines Matching +full:nfc +full:- +full:uart
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Marvell NFC driver: Firmware downloader
11 #include <linux/nfc.h>
12 #include <net/nfc/nci.h>
13 #include <net/nfc/nci_core.h>
78 skb = nci_skb_alloc(priv->ndev, (NCI_DATA_HDR_SIZE + plen), GFP_KERNEL); in alloc_lc_skb()
83 hdr->conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL; in alloc_lc_skb()
84 hdr->rfu = 0; in alloc_lc_skb()
85 hdr->plen = plen; in alloc_lc_skb()
95 if (priv->fw_dnld.fw) { in fw_dnld_over()
96 release_firmware(priv->fw_dnld.fw); in fw_dnld_over()
97 priv->fw_dnld.fw = NULL; in fw_dnld_over()
98 priv->fw_dnld.header = NULL; in fw_dnld_over()
99 priv->fw_dnld.binary_config = NULL; in fw_dnld_over()
102 atomic_set(&priv->ndev->cmd_cnt, 0); in fw_dnld_over()
104 if (timer_pending(&priv->ndev->cmd_timer)) in fw_dnld_over()
105 timer_delete_sync(&priv->ndev->cmd_timer); in fw_dnld_over()
107 if (timer_pending(&priv->fw_dnld.timer)) in fw_dnld_over()
108 timer_delete_sync(&priv->fw_dnld.timer); in fw_dnld_over()
110 nfc_info(priv->dev, "FW loading over (%d)]\n", error); in fw_dnld_over()
117 nfc_fw_download_done(priv->ndev->nfc_dev, priv->fw_dnld.name, error); in fw_dnld_over()
125 nfc_err(priv->dev, "FW loading timeout"); in fw_dnld_timeout()
126 priv->fw_dnld.state = STATE_RESET; in fw_dnld_timeout()
127 fw_dnld_over(priv, -ETIMEDOUT); in fw_dnld_timeout()
133 if (sizeof(nci_pattern_core_reset_ntf) != skb->len || in process_state_reset()
134 memcmp(skb->data, nci_pattern_core_reset_ntf, in process_state_reset()
136 return -EINVAL; in process_state_reset()
138 nfc_info(priv->dev, "BootROM reset, start fw download\n"); in process_state_reset()
141 priv->fw_dnld.state = STATE_INIT; in process_state_reset()
142 nci_send_cmd(priv->ndev, NCI_OP_CORE_INIT_CMD, 0, NULL); in process_state_reset()
152 if (sizeof(nci_pattern_core_init_rsp) >= skb->len || in process_state_init()
153 memcmp(skb->data, nci_pattern_core_init_rsp, in process_state_init()
155 return -EINVAL; in process_state_init()
160 memcpy(cmd.param.val, &priv->fw_dnld.header->ref_clock, 4); in process_state_init()
162 nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len, in process_state_init()
165 priv->fw_dnld.state = STATE_SET_REF_CLOCK; in process_state_init()
173 priv->fw_dnld.state = STATE_OPEN_LC; in create_lc()
174 nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, param); in create_lc()
182 if (sizeof(nci_pattern_core_set_config_rsp) != skb->len || in process_state_set_ref_clock()
183 memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len)) in process_state_set_ref_clock()
184 return -EINVAL; in process_state_set_ref_clock()
189 switch (priv->phy) { in process_state_set_ref_clock()
193 &priv->fw_dnld.binary_config->uart.baudrate, in process_state_set_ref_clock()
196 priv->fw_dnld.binary_config->uart.flow_control; in process_state_set_ref_clock()
201 &priv->fw_dnld.binary_config->i2c.clk, in process_state_set_ref_clock()
208 &priv->fw_dnld.binary_config->spi.clk, in process_state_set_ref_clock()
217 priv->fw_dnld.state = STATE_SET_HI_CONFIG; in process_state_set_ref_clock()
218 nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len, in process_state_set_ref_clock()
226 if (sizeof(nci_pattern_core_set_config_rsp) != skb->len || in process_state_set_hi_config()
227 memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len)) in process_state_set_hi_config()
228 return -EINVAL; in process_state_set_hi_config()
237 if (sizeof(nci_pattern_core_conn_create_rsp) >= skb->len || in process_state_open_lc()
238 memcmp(skb->data, nci_pattern_core_conn_create_rsp, in process_state_open_lc()
240 return -EINVAL; in process_state_open_lc()
242 priv->fw_dnld.state = STATE_FW_DNLD; in process_state_open_lc()
243 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_open_lc()
244 priv->fw_dnld.offset = priv->fw_dnld.binary_config->offset; in process_state_open_lc()
255 switch (priv->fw_dnld.substate) { in process_state_fw_dnld()
268 if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) { in process_state_fw_dnld()
269 nfc_err(priv->dev, "bad command"); in process_state_fw_dnld()
270 return -EINVAL; in process_state_fw_dnld()
273 len = get_unaligned_le16(skb->data); in process_state_fw_dnld()
275 comp_len = get_unaligned_le16(skb->data); in process_state_fw_dnld()
276 memcpy(&comp_len, skb->data, 2); in process_state_fw_dnld()
279 nfc_err(priv->dev, "bad len complement: %x %x %x", in process_state_fw_dnld()
283 return -ENOMEM; in process_state_fw_dnld()
285 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
286 priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT; in process_state_fw_dnld()
289 priv->fw_dnld.chunk_len = len; in process_state_fw_dnld()
292 return -ENOMEM; in process_state_fw_dnld()
294 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
295 priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT; in process_state_fw_dnld()
299 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
300 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
301 skb->len)) { in process_state_fw_dnld()
302 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
303 return -EINVAL; in process_state_fw_dnld()
305 if (priv->fw_dnld.chunk_len == 0) { in process_state_fw_dnld()
309 priv->fw_dnld.state = STATE_CLOSE_LC; in process_state_fw_dnld()
310 nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CLOSE_CMD, in process_state_fw_dnld()
313 out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len); in process_state_fw_dnld()
315 return -ENOMEM; in process_state_fw_dnld()
317 ((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset, in process_state_fw_dnld()
318 priv->fw_dnld.chunk_len); in process_state_fw_dnld()
319 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
320 priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT; in process_state_fw_dnld()
325 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
326 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
327 skb->len)) { in process_state_fw_dnld()
328 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
329 return -EINVAL; in process_state_fw_dnld()
331 priv->fw_dnld.offset += priv->fw_dnld.chunk_len; in process_state_fw_dnld()
332 priv->fw_dnld.chunk_len = 0; in process_state_fw_dnld()
333 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_fw_dnld()
337 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
338 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
339 skb->len)) { in process_state_fw_dnld()
340 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
341 return -EINVAL; in process_state_fw_dnld()
343 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_fw_dnld()
352 if (sizeof(nci_pattern_core_conn_close_rsp) != skb->len || in process_state_close_lc()
353 memcmp(skb->data, nci_pattern_core_conn_close_rsp, skb->len)) in process_state_close_lc()
354 return -EINVAL; in process_state_close_lc()
356 priv->fw_dnld.state = STATE_BOOT; in process_state_close_lc()
357 nci_send_cmd(priv->ndev, NCI_OP_PROPRIETARY_BOOT_CMD, 0, NULL); in process_state_close_lc()
364 if (sizeof(nci_pattern_proprietary_boot_rsp) != skb->len || in process_state_boot()
365 memcmp(skb->data, nci_pattern_proprietary_boot_rsp, skb->len)) in process_state_boot()
366 return -EINVAL; in process_state_boot()
372 priv->if_ops->nci_update_config(priv, in process_state_boot()
373 &priv->fw_dnld.binary_config->config); in process_state_boot()
375 if (priv->fw_dnld.binary_config == &priv->fw_dnld.header->helper) { in process_state_boot()
381 priv->fw_dnld.state = STATE_RESET; in process_state_boot()
382 priv->fw_dnld.binary_config = &priv->fw_dnld.header->firmware; in process_state_boot()
383 nfc_info(priv->dev, "FW loading: helper loaded"); in process_state_boot()
385 nfc_info(priv->dev, "FW loading: firmware loaded"); in process_state_boot()
402 while ((skb = skb_dequeue(&fw_dnld->rx_q))) { in fw_dnld_rx_work()
403 nfc_send_to_raw_sock(priv->ndev->nfc_dev, skb, in fw_dnld_rx_work()
405 switch (fw_dnld->state) { in fw_dnld_rx_work()
431 ret = -EFAULT; in fw_dnld_rx_work()
437 nfc_err(priv->dev, "FW loading error"); in fw_dnld_rx_work()
448 INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work); in nfcmrvl_fw_dnld_init()
450 dev_name(&priv->ndev->nfc_dev->dev)); in nfcmrvl_fw_dnld_init()
451 priv->fw_dnld.rx_wq = create_singlethread_workqueue(name); in nfcmrvl_fw_dnld_init()
452 if (!priv->fw_dnld.rx_wq) in nfcmrvl_fw_dnld_init()
453 return -ENOMEM; in nfcmrvl_fw_dnld_init()
454 skb_queue_head_init(&priv->fw_dnld.rx_q); in nfcmrvl_fw_dnld_init()
460 destroy_workqueue(priv->fw_dnld.rx_wq); in nfcmrvl_fw_dnld_deinit()
467 if (timer_pending(&priv->ndev->cmd_timer)) in nfcmrvl_fw_dnld_recv_frame()
468 timer_delete_sync(&priv->ndev->cmd_timer); in nfcmrvl_fw_dnld_recv_frame()
471 atomic_set(&priv->ndev->cmd_cnt, 1); in nfcmrvl_fw_dnld_recv_frame()
474 skb_queue_tail(&priv->fw_dnld.rx_q, skb); in nfcmrvl_fw_dnld_recv_frame()
475 queue_work(priv->fw_dnld.rx_wq, &priv->fw_dnld.rx_work); in nfcmrvl_fw_dnld_recv_frame()
480 fw_dnld_over(priv, -EHOSTDOWN); in nfcmrvl_fw_dnld_abort()
486 struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld; in nfcmrvl_fw_dnld_start()
489 if (!priv->support_fw_dnld) in nfcmrvl_fw_dnld_start()
490 return -ENOTSUPP; in nfcmrvl_fw_dnld_start()
493 return -EINVAL; in nfcmrvl_fw_dnld_start()
495 strcpy(fw_dnld->name, firmware_name); in nfcmrvl_fw_dnld_start()
503 res = request_firmware(&fw_dnld->fw, firmware_name, in nfcmrvl_fw_dnld_start()
504 &ndev->nfc_dev->dev); in nfcmrvl_fw_dnld_start()
506 nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name); in nfcmrvl_fw_dnld_start()
507 return -ENOENT; in nfcmrvl_fw_dnld_start()
510 fw_dnld->header = (const struct nfcmrvl_fw *) priv->fw_dnld.fw->data; in nfcmrvl_fw_dnld_start()
512 if (fw_dnld->header->magic != NFCMRVL_FW_MAGIC || in nfcmrvl_fw_dnld_start()
513 fw_dnld->header->phy != priv->phy) { in nfcmrvl_fw_dnld_start()
514 nfc_err(priv->dev, "bad firmware binary %s magic=0x%x phy=%d", in nfcmrvl_fw_dnld_start()
515 firmware_name, fw_dnld->header->magic, in nfcmrvl_fw_dnld_start()
516 fw_dnld->header->phy); in nfcmrvl_fw_dnld_start()
517 release_firmware(fw_dnld->fw); in nfcmrvl_fw_dnld_start()
518 fw_dnld->header = NULL; in nfcmrvl_fw_dnld_start()
519 return -EINVAL; in nfcmrvl_fw_dnld_start()
522 if (fw_dnld->header->helper.offset != 0) { in nfcmrvl_fw_dnld_start()
523 nfc_info(priv->dev, "loading helper"); in nfcmrvl_fw_dnld_start()
524 fw_dnld->binary_config = &fw_dnld->header->helper; in nfcmrvl_fw_dnld_start()
526 nfc_info(priv->dev, "loading firmware"); in nfcmrvl_fw_dnld_start()
527 fw_dnld->binary_config = &fw_dnld->header->firmware; in nfcmrvl_fw_dnld_start()
531 timer_setup(&priv->fw_dnld.timer, fw_dnld_timeout, 0); in nfcmrvl_fw_dnld_start()
532 mod_timer(&priv->fw_dnld.timer, in nfcmrvl_fw_dnld_start()
536 priv->if_ops->nci_update_config(priv, in nfcmrvl_fw_dnld_start()
537 &fw_dnld->header->bootrom.config); in nfcmrvl_fw_dnld_start()
540 atomic_set(&priv->ndev->cmd_cnt, 1); in nfcmrvl_fw_dnld_start()
543 priv->fw_dnld.state = STATE_RESET; in nfcmrvl_fw_dnld_start()