2 * Marvell NFC driver: Firmware downloader
4 * Copyright (C) 2015, Marvell International Ltd.
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available on the worldwide web at
11 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
15 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
16 * this warranty disclaimer.
19 #include <linux/module.h>
20 #include <linux/unaligned/access_ok.h>
21 #include <linux/firmware.h>
22 #include <linux/nfc.h>
23 #include <net/nfc/nci.h>
24 #include <net/nfc/nci_core.h>
27 #define FW_DNLD_TIMEOUT 15000
29 #define NCI_OP_PROPRIETARY_BOOT_CMD nci_opcode_pack(NCI_GID_PROPRIETARY, \
32 /* FW download states */
46 SUBSTATE_WAIT_COMMAND
= 0,
47 SUBSTATE_WAIT_ACK_CREDIT
,
48 SUBSTATE_WAIT_NACK_CREDIT
,
49 SUBSTATE_WAIT_DATA_CREDIT
,
53 ** Patterns for responses
56 static const uint8_t nci_pattern_core_reset_ntf
[] = {
57 0x60, 0x00, 0x02, 0xA0, 0x01
60 static const uint8_t nci_pattern_core_init_rsp
[] = {
64 static const uint8_t nci_pattern_core_set_config_rsp
[] = {
65 0x40, 0x02, 0x02, 0x00, 0x00
68 static const uint8_t nci_pattern_core_conn_create_rsp
[] = {
69 0x40, 0x04, 0x04, 0x00
72 static const uint8_t nci_pattern_core_conn_close_rsp
[] = {
73 0x40, 0x05, 0x01, 0x00
76 static const uint8_t nci_pattern_core_conn_credits_ntf
[] = {
77 0x60, 0x06, 0x03, 0x01, NCI_CORE_LC_CONNID_PROP_FW_DL
, 0x01
80 static const uint8_t nci_pattern_proprietary_boot_rsp
[] = {
81 0x4F, 0x3A, 0x01, 0x00
84 static struct sk_buff
*alloc_lc_skb(struct nfcmrvl_private
*priv
, uint8_t plen
)
87 struct nci_data_hdr
*hdr
;
89 skb
= nci_skb_alloc(priv
->ndev
, (NCI_DATA_HDR_SIZE
+ plen
), GFP_KERNEL
);
91 pr_err("no memory for data\n");
95 hdr
= (struct nci_data_hdr
*) skb_put(skb
, NCI_DATA_HDR_SIZE
);
96 hdr
->conn_id
= NCI_CORE_LC_CONNID_PROP_FW_DL
;
100 nci_mt_set((__u8
*)hdr
, NCI_MT_DATA_PKT
);
101 nci_pbf_set((__u8
*)hdr
, NCI_PBF_LAST
);
106 static void fw_dnld_over(struct nfcmrvl_private
*priv
, u32 error
)
108 if (priv
->fw_dnld
.fw
) {
109 release_firmware(priv
->fw_dnld
.fw
);
110 priv
->fw_dnld
.fw
= NULL
;
111 priv
->fw_dnld
.header
= NULL
;
112 priv
->fw_dnld
.binary_config
= NULL
;
115 atomic_set(&priv
->ndev
->cmd_cnt
, 0);
116 del_timer_sync(&priv
->ndev
->cmd_timer
);
118 del_timer_sync(&priv
->fw_dnld
.timer
);
120 nfc_info(priv
->dev
, "FW loading over (%d)]\n", error
);
123 /* failed, halt the chip to avoid power consumption */
124 nfcmrvl_chip_halt(priv
);
127 nfc_fw_download_done(priv
->ndev
->nfc_dev
, priv
->fw_dnld
.name
, error
);
130 static void fw_dnld_timeout(unsigned long arg
)
132 struct nfcmrvl_private
*priv
= (struct nfcmrvl_private
*) arg
;
134 nfc_err(priv
->dev
, "FW loading timeout");
135 priv
->fw_dnld
.state
= STATE_RESET
;
136 fw_dnld_over(priv
, -ETIMEDOUT
);
139 static int process_state_reset(struct nfcmrvl_private
*priv
,
142 if (sizeof(nci_pattern_core_reset_ntf
) != skb
->len
||
143 memcmp(skb
->data
, nci_pattern_core_reset_ntf
,
144 sizeof(nci_pattern_core_reset_ntf
)))
147 nfc_info(priv
->dev
, "BootROM reset, start fw download\n");
149 /* Start FW download state machine */
150 priv
->fw_dnld
.state
= STATE_INIT
;
151 nci_send_cmd(priv
->ndev
, NCI_OP_CORE_INIT_CMD
, 0, NULL
);
156 static int process_state_init(struct nfcmrvl_private
*priv
, struct sk_buff
*skb
)
158 struct nci_core_set_config_cmd cmd
;
160 if (sizeof(nci_pattern_core_init_rsp
) >= skb
->len
||
161 memcmp(skb
->data
, nci_pattern_core_init_rsp
,
162 sizeof(nci_pattern_core_init_rsp
)))
166 cmd
.param
.id
= NFCMRVL_PROP_REF_CLOCK
;
168 memcpy(cmd
.param
.val
, &priv
->fw_dnld
.header
->ref_clock
, 4);
170 nci_send_cmd(priv
->ndev
, NCI_OP_CORE_SET_CONFIG_CMD
, 3 + cmd
.param
.len
,
173 priv
->fw_dnld
.state
= STATE_SET_REF_CLOCK
;
177 static void create_lc(struct nfcmrvl_private
*priv
)
179 uint8_t param
[2] = { NCI_CORE_LC_PROP_FW_DL
, 0x0 };
181 priv
->fw_dnld
.state
= STATE_OPEN_LC
;
182 nci_send_cmd(priv
->ndev
, NCI_OP_CORE_CONN_CREATE_CMD
, 2, param
);
185 static int process_state_set_ref_clock(struct nfcmrvl_private
*priv
,
188 struct nci_core_set_config_cmd cmd
;
190 if (sizeof(nci_pattern_core_set_config_rsp
) != skb
->len
||
191 memcmp(skb
->data
, nci_pattern_core_set_config_rsp
, skb
->len
))
195 cmd
.param
.id
= NFCMRVL_PROP_SET_HI_CONFIG
;
198 case NFCMRVL_PHY_UART
:
200 memcpy(cmd
.param
.val
,
201 &priv
->fw_dnld
.binary_config
->uart
.baudrate
,
204 priv
->fw_dnld
.binary_config
->uart
.flow_control
;
206 case NFCMRVL_PHY_I2C
:
208 memcpy(cmd
.param
.val
,
209 &priv
->fw_dnld
.binary_config
->i2c
.clk
,
211 cmd
.param
.val
[4] = 0;
213 case NFCMRVL_PHY_SPI
:
215 memcpy(cmd
.param
.val
,
216 &priv
->fw_dnld
.binary_config
->spi
.clk
,
218 cmd
.param
.val
[4] = 0;
225 priv
->fw_dnld
.state
= STATE_SET_HI_CONFIG
;
226 nci_send_cmd(priv
->ndev
, NCI_OP_CORE_SET_CONFIG_CMD
, 3 + cmd
.param
.len
,
231 static int process_state_set_hi_config(struct nfcmrvl_private
*priv
,
234 if (sizeof(nci_pattern_core_set_config_rsp
) != skb
->len
||
235 memcmp(skb
->data
, nci_pattern_core_set_config_rsp
, skb
->len
))
242 static int process_state_open_lc(struct nfcmrvl_private
*priv
,
245 if (sizeof(nci_pattern_core_conn_create_rsp
) >= skb
->len
||
246 memcmp(skb
->data
, nci_pattern_core_conn_create_rsp
,
247 sizeof(nci_pattern_core_conn_create_rsp
)))
250 priv
->fw_dnld
.state
= STATE_FW_DNLD
;
251 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_COMMAND
;
252 priv
->fw_dnld
.offset
= priv
->fw_dnld
.binary_config
->offset
;
256 static int process_state_fw_dnld(struct nfcmrvl_private
*priv
,
261 struct sk_buff
*out_skb
;
263 switch (priv
->fw_dnld
.substate
) {
264 case SUBSTATE_WAIT_COMMAND
:
268 * B3 : Helper command (0xA5)
269 * B4..5: le16 data size
270 * B6..7: le16 data size complement (~)
276 if (skb
->data
[0] != HELPER_CMD_PACKET_FORMAT
|| skb
->len
!= 5) {
277 nfc_err(priv
->dev
, "bad command");
281 memcpy(&len
, skb
->data
, 2);
283 memcpy(&comp_len
, skb
->data
, 2);
285 len
= get_unaligned_le16(&len
);
286 comp_len
= get_unaligned_le16(&comp_len
);
287 if (((~len
) & 0xFFFF) != comp_len
) {
288 nfc_err(priv
->dev
, "bad len complement: %x %x %x",
289 len
, comp_len
, (~len
& 0xFFFF));
290 out_skb
= alloc_lc_skb(priv
, 1);
293 *skb_put(out_skb
, 1) = 0xBF;
294 nci_send_frame(priv
->ndev
, out_skb
);
295 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_NACK_CREDIT
;
298 priv
->fw_dnld
.chunk_len
= len
;
299 out_skb
= alloc_lc_skb(priv
, 1);
302 *skb_put(out_skb
, 1) = HELPER_ACK_PACKET_FORMAT
;
303 nci_send_frame(priv
->ndev
, out_skb
);
304 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_ACK_CREDIT
;
307 case SUBSTATE_WAIT_ACK_CREDIT
:
308 if (sizeof(nci_pattern_core_conn_credits_ntf
) != skb
->len
||
309 memcmp(nci_pattern_core_conn_credits_ntf
, skb
->data
,
311 nfc_err(priv
->dev
, "bad packet: waiting for credit");
314 if (priv
->fw_dnld
.chunk_len
== 0) {
315 /* FW Loading is done */
316 uint8_t conn_id
= NCI_CORE_LC_CONNID_PROP_FW_DL
;
318 priv
->fw_dnld
.state
= STATE_CLOSE_LC
;
319 nci_send_cmd(priv
->ndev
, NCI_OP_CORE_CONN_CLOSE_CMD
,
322 out_skb
= alloc_lc_skb(priv
, priv
->fw_dnld
.chunk_len
);
325 memcpy(skb_put(out_skb
, priv
->fw_dnld
.chunk_len
),
326 ((uint8_t *)priv
->fw_dnld
.fw
->data
) +
327 priv
->fw_dnld
.offset
,
328 priv
->fw_dnld
.chunk_len
);
329 nci_send_frame(priv
->ndev
, out_skb
);
330 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_DATA_CREDIT
;
334 case SUBSTATE_WAIT_DATA_CREDIT
:
335 if (sizeof(nci_pattern_core_conn_credits_ntf
) != skb
->len
||
336 memcmp(nci_pattern_core_conn_credits_ntf
, skb
->data
,
338 nfc_err(priv
->dev
, "bad packet: waiting for credit");
341 priv
->fw_dnld
.offset
+= priv
->fw_dnld
.chunk_len
;
342 priv
->fw_dnld
.chunk_len
= 0;
343 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_COMMAND
;
346 case SUBSTATE_WAIT_NACK_CREDIT
:
347 if (sizeof(nci_pattern_core_conn_credits_ntf
) != skb
->len
||
348 memcmp(nci_pattern_core_conn_credits_ntf
, skb
->data
,
350 nfc_err(priv
->dev
, "bad packet: waiting for credit");
353 priv
->fw_dnld
.substate
= SUBSTATE_WAIT_COMMAND
;
359 static int process_state_close_lc(struct nfcmrvl_private
*priv
,
362 if (sizeof(nci_pattern_core_conn_close_rsp
) != skb
->len
||
363 memcmp(skb
->data
, nci_pattern_core_conn_close_rsp
, skb
->len
))
366 priv
->fw_dnld
.state
= STATE_BOOT
;
367 nci_send_cmd(priv
->ndev
, NCI_OP_PROPRIETARY_BOOT_CMD
, 0, NULL
);
371 static int process_state_boot(struct nfcmrvl_private
*priv
, struct sk_buff
*skb
)
373 if (sizeof(nci_pattern_proprietary_boot_rsp
) != skb
->len
||
374 memcmp(skb
->data
, nci_pattern_proprietary_boot_rsp
, skb
->len
))
378 * Update HI config to use the right configuration for the next
381 priv
->if_ops
->nci_update_config(priv
,
382 &priv
->fw_dnld
.binary_config
->config
);
384 if (priv
->fw_dnld
.binary_config
== &priv
->fw_dnld
.header
->helper
) {
386 * This is the case where an helper was needed and we have
387 * uploaded it. Now we have to wait the next RESET NTF to start
390 priv
->fw_dnld
.state
= STATE_RESET
;
391 priv
->fw_dnld
.binary_config
= &priv
->fw_dnld
.header
->firmware
;
392 nfc_info(priv
->dev
, "FW loading: helper loaded");
394 nfc_info(priv
->dev
, "FW loading: firmware loaded");
395 fw_dnld_over(priv
, 0);
400 static void fw_dnld_rx_work(struct work_struct
*work
)
404 struct nfcmrvl_fw_dnld
*fw_dnld
= container_of(work
,
405 struct nfcmrvl_fw_dnld
,
407 struct nfcmrvl_private
*priv
= container_of(fw_dnld
,
408 struct nfcmrvl_private
,
411 while ((skb
= skb_dequeue(&fw_dnld
->rx_q
))) {
412 nfc_send_to_raw_sock(priv
->ndev
->nfc_dev
, skb
,
413 RAW_PAYLOAD_NCI
, NFC_DIRECTION_RX
);
414 switch (fw_dnld
->state
) {
416 ret
= process_state_reset(priv
, skb
);
419 ret
= process_state_init(priv
, skb
);
421 case STATE_SET_REF_CLOCK
:
422 ret
= process_state_set_ref_clock(priv
, skb
);
424 case STATE_SET_HI_CONFIG
:
425 ret
= process_state_set_hi_config(priv
, skb
);
428 ret
= process_state_open_lc(priv
, skb
);
431 ret
= process_state_fw_dnld(priv
, skb
);
434 ret
= process_state_close_lc(priv
, skb
);
437 ret
= process_state_boot(priv
, skb
);
446 nfc_err(priv
->dev
, "FW loading error");
447 fw_dnld_over(priv
, ret
);
453 int nfcmrvl_fw_dnld_init(struct nfcmrvl_private
*priv
)
457 INIT_WORK(&priv
->fw_dnld
.rx_work
, fw_dnld_rx_work
);
458 snprintf(name
, sizeof(name
), "%s_nfcmrvl_fw_dnld_rx_wq",
459 dev_name(priv
->dev
));
460 priv
->fw_dnld
.rx_wq
= create_singlethread_workqueue(name
);
461 if (!priv
->fw_dnld
.rx_wq
)
463 skb_queue_head_init(&priv
->fw_dnld
.rx_q
);
467 void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private
*priv
)
469 destroy_workqueue(priv
->fw_dnld
.rx_wq
);
472 void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private
*priv
,
475 /* Allow next command */
476 atomic_set(&priv
->ndev
->cmd_cnt
, 1);
477 del_timer_sync(&priv
->ndev
->cmd_timer
);
479 /* Queue and trigger rx work */
480 skb_queue_tail(&priv
->fw_dnld
.rx_q
, skb
);
481 queue_work(priv
->fw_dnld
.rx_wq
, &priv
->fw_dnld
.rx_work
);
484 void nfcmrvl_fw_dnld_abort(struct nfcmrvl_private
*priv
)
486 fw_dnld_over(priv
, -EHOSTDOWN
);
489 int nfcmrvl_fw_dnld_start(struct nci_dev
*ndev
, const char *firmware_name
)
491 struct nfcmrvl_private
*priv
= nci_get_drvdata(ndev
);
492 struct nfcmrvl_fw_dnld
*fw_dnld
= &priv
->fw_dnld
;
494 if (!priv
->support_fw_dnld
)
497 if (!firmware_name
|| !firmware_name
[0])
500 strcpy(fw_dnld
->name
, firmware_name
);
503 * Retrieve FW binary file and parse it to initialize FW download
507 /* Retrieve FW binary */
508 if (request_firmware(&fw_dnld
->fw
, firmware_name
, priv
->dev
) < 0) {
509 nfc_err(priv
->dev
, "failed to retrieve FW %s", firmware_name
);
513 fw_dnld
->header
= (const struct nfcmrvl_fw
*) priv
->fw_dnld
.fw
->data
;
515 if (fw_dnld
->header
->magic
!= NFCMRVL_FW_MAGIC
||
516 fw_dnld
->header
->phy
!= priv
->phy
) {
517 nfc_err(priv
->dev
, "bad firmware binary %s magic=0x%x phy=%d",
518 firmware_name
, fw_dnld
->header
->magic
,
519 fw_dnld
->header
->phy
);
520 release_firmware(fw_dnld
->fw
);
521 fw_dnld
->header
= NULL
;
525 if (fw_dnld
->header
->helper
.offset
!= 0) {
526 nfc_info(priv
->dev
, "loading helper");
527 fw_dnld
->binary_config
= &fw_dnld
->header
->helper
;
529 nfc_info(priv
->dev
, "loading firmware");
530 fw_dnld
->binary_config
= &fw_dnld
->header
->firmware
;
533 /* Configure a timer for timeout */
534 setup_timer(&priv
->fw_dnld
.timer
, fw_dnld_timeout
,
535 (unsigned long) priv
);
536 mod_timer(&priv
->fw_dnld
.timer
,
537 jiffies
+ msecs_to_jiffies(FW_DNLD_TIMEOUT
));
539 /* Ronfigure HI to be sure that it is the bootrom values */
540 priv
->if_ops
->nci_update_config(priv
,
541 &fw_dnld
->header
->bootrom
.config
);
543 /* Allow first command */
544 atomic_set(&priv
->ndev
->cmd_cnt
, 1);
546 /* First, reset the chip */
547 priv
->fw_dnld
.state
= STATE_RESET
;
548 nfcmrvl_chip_reset(priv
);
550 /* Now wait for CORE_RESET_NTF or timeout */