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 del_timer_sync(&priv->ndev->cmd_timer); in fw_dnld_over()
107 if (timer_pending(&priv->fw_dnld.timer)) in fw_dnld_over()
108 del_timer_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()
124 nfc_err(priv->dev, "FW loading timeout"); in fw_dnld_timeout()
125 priv->fw_dnld.state = STATE_RESET; in fw_dnld_timeout()
126 fw_dnld_over(priv, -ETIMEDOUT); in fw_dnld_timeout()
132 if (sizeof(nci_pattern_core_reset_ntf) != skb->len || in process_state_reset()
133 memcmp(skb->data, nci_pattern_core_reset_ntf, in process_state_reset()
135 return -EINVAL; in process_state_reset()
137 nfc_info(priv->dev, "BootROM reset, start fw download\n"); in process_state_reset()
140 priv->fw_dnld.state = STATE_INIT; in process_state_reset()
141 nci_send_cmd(priv->ndev, NCI_OP_CORE_INIT_CMD, 0, NULL); in process_state_reset()
151 if (sizeof(nci_pattern_core_init_rsp) >= skb->len || in process_state_init()
152 memcmp(skb->data, nci_pattern_core_init_rsp, in process_state_init()
154 return -EINVAL; in process_state_init()
159 memcpy(cmd.param.val, &priv->fw_dnld.header->ref_clock, 4); in process_state_init()
161 nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len, in process_state_init()
164 priv->fw_dnld.state = STATE_SET_REF_CLOCK; in process_state_init()
172 priv->fw_dnld.state = STATE_OPEN_LC; in create_lc()
173 nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, param); in create_lc()
181 if (sizeof(nci_pattern_core_set_config_rsp) != skb->len || in process_state_set_ref_clock()
182 memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len)) in process_state_set_ref_clock()
183 return -EINVAL; in process_state_set_ref_clock()
188 switch (priv->phy) { in process_state_set_ref_clock()
192 &priv->fw_dnld.binary_config->uart.baudrate, in process_state_set_ref_clock()
195 priv->fw_dnld.binary_config->uart.flow_control; in process_state_set_ref_clock()
200 &priv->fw_dnld.binary_config->i2c.clk, in process_state_set_ref_clock()
207 &priv->fw_dnld.binary_config->spi.clk, in process_state_set_ref_clock()
216 priv->fw_dnld.state = STATE_SET_HI_CONFIG; in process_state_set_ref_clock()
217 nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len, in process_state_set_ref_clock()
225 if (sizeof(nci_pattern_core_set_config_rsp) != skb->len || in process_state_set_hi_config()
226 memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len)) in process_state_set_hi_config()
227 return -EINVAL; in process_state_set_hi_config()
236 if (sizeof(nci_pattern_core_conn_create_rsp) >= skb->len || in process_state_open_lc()
237 memcmp(skb->data, nci_pattern_core_conn_create_rsp, in process_state_open_lc()
239 return -EINVAL; in process_state_open_lc()
241 priv->fw_dnld.state = STATE_FW_DNLD; in process_state_open_lc()
242 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_open_lc()
243 priv->fw_dnld.offset = priv->fw_dnld.binary_config->offset; in process_state_open_lc()
254 switch (priv->fw_dnld.substate) { in process_state_fw_dnld()
267 if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) { in process_state_fw_dnld()
268 nfc_err(priv->dev, "bad command"); in process_state_fw_dnld()
269 return -EINVAL; in process_state_fw_dnld()
272 len = get_unaligned_le16(skb->data); in process_state_fw_dnld()
274 comp_len = get_unaligned_le16(skb->data); in process_state_fw_dnld()
275 memcpy(&comp_len, skb->data, 2); in process_state_fw_dnld()
278 nfc_err(priv->dev, "bad len complement: %x %x %x", in process_state_fw_dnld()
282 return -ENOMEM; in process_state_fw_dnld()
284 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
285 priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT; in process_state_fw_dnld()
288 priv->fw_dnld.chunk_len = len; in process_state_fw_dnld()
291 return -ENOMEM; in process_state_fw_dnld()
293 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
294 priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT; in process_state_fw_dnld()
298 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
299 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
300 skb->len)) { in process_state_fw_dnld()
301 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
302 return -EINVAL; in process_state_fw_dnld()
304 if (priv->fw_dnld.chunk_len == 0) { in process_state_fw_dnld()
308 priv->fw_dnld.state = STATE_CLOSE_LC; in process_state_fw_dnld()
309 nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CLOSE_CMD, in process_state_fw_dnld()
312 out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len); in process_state_fw_dnld()
314 return -ENOMEM; in process_state_fw_dnld()
316 ((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset, in process_state_fw_dnld()
317 priv->fw_dnld.chunk_len); in process_state_fw_dnld()
318 nci_send_frame(priv->ndev, out_skb); in process_state_fw_dnld()
319 priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT; in process_state_fw_dnld()
324 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
325 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
326 skb->len)) { in process_state_fw_dnld()
327 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
328 return -EINVAL; in process_state_fw_dnld()
330 priv->fw_dnld.offset += priv->fw_dnld.chunk_len; in process_state_fw_dnld()
331 priv->fw_dnld.chunk_len = 0; in process_state_fw_dnld()
332 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_fw_dnld()
336 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len || in process_state_fw_dnld()
337 memcmp(nci_pattern_core_conn_credits_ntf, skb->data, in process_state_fw_dnld()
338 skb->len)) { in process_state_fw_dnld()
339 nfc_err(priv->dev, "bad packet: waiting for credit"); in process_state_fw_dnld()
340 return -EINVAL; in process_state_fw_dnld()
342 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND; in process_state_fw_dnld()
351 if (sizeof(nci_pattern_core_conn_close_rsp) != skb->len || in process_state_close_lc()
352 memcmp(skb->data, nci_pattern_core_conn_close_rsp, skb->len)) in process_state_close_lc()
353 return -EINVAL; in process_state_close_lc()
355 priv->fw_dnld.state = STATE_BOOT; in process_state_close_lc()
356 nci_send_cmd(priv->ndev, NCI_OP_PROPRIETARY_BOOT_CMD, 0, NULL); in process_state_close_lc()
363 if (sizeof(nci_pattern_proprietary_boot_rsp) != skb->len || in process_state_boot()
364 memcmp(skb->data, nci_pattern_proprietary_boot_rsp, skb->len)) in process_state_boot()
365 return -EINVAL; in process_state_boot()
371 priv->if_ops->nci_update_config(priv, in process_state_boot()
372 &priv->fw_dnld.binary_config->config); in process_state_boot()
374 if (priv->fw_dnld.binary_config == &priv->fw_dnld.header->helper) { in process_state_boot()
380 priv->fw_dnld.state = STATE_RESET; in process_state_boot()
381 priv->fw_dnld.binary_config = &priv->fw_dnld.header->firmware; in process_state_boot()
382 nfc_info(priv->dev, "FW loading: helper loaded"); in process_state_boot()
384 nfc_info(priv->dev, "FW loading: firmware loaded"); in process_state_boot()
401 while ((skb = skb_dequeue(&fw_dnld->rx_q))) { in fw_dnld_rx_work()
402 nfc_send_to_raw_sock(priv->ndev->nfc_dev, skb, in fw_dnld_rx_work()
404 switch (fw_dnld->state) { in fw_dnld_rx_work()
430 ret = -EFAULT; in fw_dnld_rx_work()
436 nfc_err(priv->dev, "FW loading error"); in fw_dnld_rx_work()
447 INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work); in nfcmrvl_fw_dnld_init()
449 dev_name(&priv->ndev->nfc_dev->dev)); in nfcmrvl_fw_dnld_init()
450 priv->fw_dnld.rx_wq = create_singlethread_workqueue(name); in nfcmrvl_fw_dnld_init()
451 if (!priv->fw_dnld.rx_wq) in nfcmrvl_fw_dnld_init()
452 return -ENOMEM; in nfcmrvl_fw_dnld_init()
453 skb_queue_head_init(&priv->fw_dnld.rx_q); in nfcmrvl_fw_dnld_init()
459 destroy_workqueue(priv->fw_dnld.rx_wq); in nfcmrvl_fw_dnld_deinit()
466 if (timer_pending(&priv->ndev->cmd_timer)) in nfcmrvl_fw_dnld_recv_frame()
467 del_timer_sync(&priv->ndev->cmd_timer); in nfcmrvl_fw_dnld_recv_frame()
470 atomic_set(&priv->ndev->cmd_cnt, 1); in nfcmrvl_fw_dnld_recv_frame()
473 skb_queue_tail(&priv->fw_dnld.rx_q, skb); in nfcmrvl_fw_dnld_recv_frame()
474 queue_work(priv->fw_dnld.rx_wq, &priv->fw_dnld.rx_work); in nfcmrvl_fw_dnld_recv_frame()
479 fw_dnld_over(priv, -EHOSTDOWN); in nfcmrvl_fw_dnld_abort()
485 struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld; in nfcmrvl_fw_dnld_start()
488 if (!priv->support_fw_dnld) in nfcmrvl_fw_dnld_start()
489 return -ENOTSUPP; in nfcmrvl_fw_dnld_start()
492 return -EINVAL; in nfcmrvl_fw_dnld_start()
494 strcpy(fw_dnld->name, firmware_name); in nfcmrvl_fw_dnld_start()
502 res = request_firmware(&fw_dnld->fw, firmware_name, in nfcmrvl_fw_dnld_start()
503 &ndev->nfc_dev->dev); in nfcmrvl_fw_dnld_start()
505 nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name); in nfcmrvl_fw_dnld_start()
506 return -ENOENT; in nfcmrvl_fw_dnld_start()
509 fw_dnld->header = (const struct nfcmrvl_fw *) priv->fw_dnld.fw->data; in nfcmrvl_fw_dnld_start()
511 if (fw_dnld->header->magic != NFCMRVL_FW_MAGIC || in nfcmrvl_fw_dnld_start()
512 fw_dnld->header->phy != priv->phy) { in nfcmrvl_fw_dnld_start()
513 nfc_err(priv->dev, "bad firmware binary %s magic=0x%x phy=%d", in nfcmrvl_fw_dnld_start()
514 firmware_name, fw_dnld->header->magic, in nfcmrvl_fw_dnld_start()
515 fw_dnld->header->phy); in nfcmrvl_fw_dnld_start()
516 release_firmware(fw_dnld->fw); in nfcmrvl_fw_dnld_start()
517 fw_dnld->header = NULL; in nfcmrvl_fw_dnld_start()
518 return -EINVAL; in nfcmrvl_fw_dnld_start()
521 if (fw_dnld->header->helper.offset != 0) { in nfcmrvl_fw_dnld_start()
522 nfc_info(priv->dev, "loading helper"); in nfcmrvl_fw_dnld_start()
523 fw_dnld->binary_config = &fw_dnld->header->helper; in nfcmrvl_fw_dnld_start()
525 nfc_info(priv->dev, "loading firmware"); in nfcmrvl_fw_dnld_start()
526 fw_dnld->binary_config = &fw_dnld->header->firmware; in nfcmrvl_fw_dnld_start()
530 timer_setup(&priv->fw_dnld.timer, fw_dnld_timeout, 0); in nfcmrvl_fw_dnld_start()
531 mod_timer(&priv->fw_dnld.timer, in nfcmrvl_fw_dnld_start()
535 priv->if_ops->nci_update_config(priv, in nfcmrvl_fw_dnld_start()
536 &fw_dnld->header->bootrom.config); in nfcmrvl_fw_dnld_start()
539 atomic_set(&priv->ndev->cmd_cnt, 1); in nfcmrvl_fw_dnld_start()
542 priv->fw_dnld.state = STATE_RESET; in nfcmrvl_fw_dnld_start()