^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Generic driver for NXP NCI NFC chips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014 NXP Semiconductors All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Clément Perrochaud <clement.perrochaud@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Derived from PN544 device driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2012 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/nfc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "nxp-nci.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Crypto operations can take up to 30 seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define NXP_NCI_FW_ANSWER_TIMEOUT msecs_to_jiffies(30000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define NXP_NCI_FW_CMD_RESET 0xF0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define NXP_NCI_FW_CMD_GETVERSION 0xF1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define NXP_NCI_FW_CMD_CHECKINTEGRITY 0xE0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define NXP_NCI_FW_CMD_WRITE 0xC0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define NXP_NCI_FW_CMD_READ 0xA2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define NXP_NCI_FW_CMD_GETSESSIONSTATE 0xF2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define NXP_NCI_FW_CMD_LOG 0xA7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define NXP_NCI_FW_CMD_FORCE 0xD0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define NXP_NCI_FW_CMD_GET_DIE_ID 0xF4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define NXP_NCI_FW_CHUNK_FLAG 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define NXP_NCI_FW_RESULT_OK 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define NXP_NCI_FW_RESULT_INVALID_ADDR 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define NXP_NCI_FW_RESULT_GENERIC_ERROR 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define NXP_NCI_FW_RESULT_UNKNOWN_CMD 0x0B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define NXP_NCI_FW_RESULT_ABORTED_CMD 0x0C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define NXP_NCI_FW_RESULT_PLL_ERROR 0x0D
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR 0x1E
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR 0x1F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define NXP_NCI_FW_RESULT_MEM_BSY 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define NXP_NCI_FW_RESULT_SIGNATURE_ERROR 0x21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define NXP_NCI_FW_RESULT_PROTOCOL_ERROR 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define NXP_NCI_FW_RESULT_SFWU_DEGRADED 0x2A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK 0x2D
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK 0x2E
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5 0xC5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct nxp_nci_fw_info *fw_info = &info->fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (info->phy_ops->set_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (r < 0 && result == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) result = -r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) info->mode = NXP_NCI_MODE_COLD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (fw_info->fw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) release_firmware(fw_info->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) fw_info->fw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) nfc_fw_download_done(info->ndev->nfc_dev, fw_info->name, (u32) -result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* crc_ccitt cannot be used since it is computed MSB first and not LSB first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static u16 nxp_nci_fw_crc(u8 const *buffer, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u16 crc = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) while (len--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) crc = ((crc >> 8) | (crc << 8)) ^ *buffer++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) crc ^= (crc & 0xff) >> 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) crc ^= (crc & 0xff) << 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) crc ^= (crc & 0xff) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return crc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct nxp_nci_fw_info *fw_info = &info->fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u16 header, crc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) size_t chunk_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) size_t remaining_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) skb = nci_skb_alloc(info->ndev, info->max_payload, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) r = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) goto chunk_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) chunk_len = info->max_payload - NXP_NCI_FW_HDR_LEN - NXP_NCI_FW_CRC_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) remaining_len = fw_info->frame_size - fw_info->written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (remaining_len > chunk_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) header = NXP_NCI_FW_CHUNK_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) chunk_len = remaining_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) header = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) header |= chunk_len & NXP_NCI_FW_FRAME_LEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) put_unaligned_be16(header, skb_put(skb, NXP_NCI_FW_HDR_LEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) skb_put_data(skb, fw_info->data + fw_info->written, chunk_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) crc = nxp_nci_fw_crc(skb->data, chunk_len + NXP_NCI_FW_HDR_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) put_unaligned_be16(crc, skb_put(skb, NXP_NCI_FW_CRC_LEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) r = info->phy_ops->write(info->phy_id, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (r >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) r = chunk_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) chunk_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static int nxp_nci_fw_send(struct nxp_nci_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct nxp_nci_fw_info *fw_info = &info->fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) long completion_rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) reinit_completion(&fw_info->cmd_completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (fw_info->written == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) fw_info->frame_size = get_unaligned_be16(fw_info->data) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) NXP_NCI_FW_FRAME_LEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) fw_info->data += NXP_NCI_FW_HDR_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) fw_info->size -= NXP_NCI_FW_HDR_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (fw_info->frame_size > fw_info->size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) r = nxp_nci_fw_send_chunk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) fw_info->written += r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (*fw_info->data == NXP_NCI_FW_CMD_RESET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) fw_info->cmd_result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (fw_info->fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) schedule_work(&fw_info->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) completion_rc = wait_for_completion_interruptible_timeout(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) &fw_info->cmd_completion, NXP_NCI_FW_ANSWER_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (completion_rc == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) void nxp_nci_fw_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct nxp_nci_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct nxp_nci_fw_info *fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) fw_info = container_of(work, struct nxp_nci_fw_info, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) info = container_of(fw_info, struct nxp_nci_info, fw_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) mutex_lock(&info->info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) r = fw_info->cmd_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) goto exit_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (fw_info->written == fw_info->frame_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) fw_info->data += fw_info->frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) fw_info->size -= fw_info->frame_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) fw_info->written = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (fw_info->size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) r = nxp_nci_fw_send(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) exit_work:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (r < 0 || fw_info->size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) nxp_nci_fw_work_complete(info, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) mutex_unlock(&info->info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct nxp_nci_info *info = nci_get_drvdata(ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct nxp_nci_fw_info *fw_info = &info->fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) mutex_lock(&info->info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!info->phy_ops->set_mode || !info->phy_ops->write) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) r = -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto fw_download_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!firmware_name || firmware_name[0] == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) r = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto fw_download_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) strcpy(fw_info->name, firmware_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) r = request_firmware(&fw_info->fw, firmware_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ndev->nfc_dev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) goto fw_download_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_FW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) release_firmware(fw_info->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) goto fw_download_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) info->mode = NXP_NCI_MODE_FW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) fw_info->data = fw_info->fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) fw_info->size = fw_info->fw->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) fw_info->written = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) fw_info->frame_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) fw_info->cmd_result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) schedule_work(&fw_info->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) fw_download_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) mutex_unlock(&info->info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static int nxp_nci_fw_read_status(u8 stat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) switch (stat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case NXP_NCI_FW_RESULT_OK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case NXP_NCI_FW_RESULT_INVALID_ADDR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case NXP_NCI_FW_RESULT_UNKNOWN_CMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) case NXP_NCI_FW_RESULT_ABORTED_CMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) case NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return -EADDRNOTAVAIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) case NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case NXP_NCI_FW_RESULT_MEM_BSY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return -ENOKEY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) case NXP_NCI_FW_RESULT_SIGNATURE_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return -EKEYREJECTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) case NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -EALREADY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case NXP_NCI_FW_RESULT_PROTOCOL_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return -EPROTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) case NXP_NCI_FW_RESULT_SFWU_DEGRADED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EHWPOISON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) case NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static u16 nxp_nci_fw_check_crc(struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) u16 crc, frame_crc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) size_t len = skb->len - NXP_NCI_FW_CRC_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) crc = nxp_nci_fw_crc(skb->data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) frame_crc = get_unaligned_be16(skb->data + len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return (crc ^ frame_crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct nxp_nci_info *info = nci_get_drvdata(ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct nxp_nci_fw_info *fw_info = &info->fw_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) complete(&fw_info->cmd_completion);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (nxp_nci_fw_check_crc(skb) != 0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) fw_info->cmd_result = -EBADMSG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) fw_info->cmd_result = nxp_nci_fw_read_status(*(u8 *)skb_pull(skb, NXP_NCI_FW_HDR_LEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) fw_info->cmd_result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (fw_info->fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) schedule_work(&fw_info->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) EXPORT_SYMBOL(nxp_nci_fw_recv_frame);