1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a06347c0SRobert Dolca /* ------------------------------------------------------------------------- 3a06347c0SRobert Dolca * Copyright (C) 2014-2016, Intel Corporation 4a06347c0SRobert Dolca * 5a06347c0SRobert Dolca * ------------------------------------------------------------------------- 6a06347c0SRobert Dolca */ 7a06347c0SRobert Dolca 8a06347c0SRobert Dolca #include <linux/module.h> 9a06347c0SRobert Dolca #include <linux/nfc.h> 10a06347c0SRobert Dolca #include <linux/i2c.h> 11a06347c0SRobert Dolca #include <linux/delay.h> 12a06347c0SRobert Dolca #include <linux/firmware.h> 13a06347c0SRobert Dolca #include <net/nfc/nci_core.h> 14a06347c0SRobert Dolca 15a06347c0SRobert Dolca #include "fdp.h" 16a06347c0SRobert Dolca 17a06347c0SRobert Dolca #define FDP_OTP_PATCH_NAME "otp.bin" 18a06347c0SRobert Dolca #define FDP_RAM_PATCH_NAME "ram.bin" 19a06347c0SRobert Dolca #define FDP_FW_HEADER_SIZE 576 20a06347c0SRobert Dolca #define FDP_FW_UPDATE_SLEEP 1000 21a06347c0SRobert Dolca 22a06347c0SRobert Dolca #define NCI_GET_VERSION_TIMEOUT 8000 23a06347c0SRobert Dolca #define NCI_PATCH_REQUEST_TIMEOUT 8000 24a06347c0SRobert Dolca #define FDP_PATCH_CONN_DEST 0xC2 25a06347c0SRobert Dolca #define FDP_PATCH_CONN_PARAM_TYPE 0xA0 26a06347c0SRobert Dolca 27a06347c0SRobert Dolca #define NCI_PATCH_TYPE_RAM 0x00 28a06347c0SRobert Dolca #define NCI_PATCH_TYPE_OTP 0x01 29a06347c0SRobert Dolca #define NCI_PATCH_TYPE_EOT 0xFF 30a06347c0SRobert Dolca 31a06347c0SRobert Dolca #define NCI_PARAM_ID_FW_RAM_VERSION 0xA0 32a06347c0SRobert Dolca #define NCI_PARAM_ID_FW_OTP_VERSION 0xA1 33a06347c0SRobert Dolca #define NCI_PARAM_ID_OTP_LIMITED_VERSION 0xC5 34a06347c0SRobert Dolca #define NCI_PARAM_ID_KEY_INDEX_ID 0xC6 35a06347c0SRobert Dolca 36a06347c0SRobert Dolca #define NCI_GID_PROP 0x0F 37a06347c0SRobert Dolca #define NCI_OP_PROP_PATCH_OID 0x08 38a06347c0SRobert Dolca #define NCI_OP_PROP_SET_PDATA_OID 0x23 39a06347c0SRobert Dolca 40a06347c0SRobert Dolca struct fdp_nci_info { 41a06347c0SRobert Dolca struct nfc_phy_ops *phy_ops; 42a06347c0SRobert Dolca struct fdp_i2c_phy *phy; 43a06347c0SRobert Dolca struct nci_dev *ndev; 44a06347c0SRobert Dolca 45a06347c0SRobert Dolca const struct firmware *otp_patch; 46a06347c0SRobert Dolca const struct firmware *ram_patch; 47a06347c0SRobert Dolca u32 otp_patch_version; 48a06347c0SRobert Dolca u32 ram_patch_version; 49a06347c0SRobert Dolca 50a06347c0SRobert Dolca u32 otp_version; 51a06347c0SRobert Dolca u32 ram_version; 52a06347c0SRobert Dolca u32 limited_otp_version; 53a06347c0SRobert Dolca u8 key_index; 54a06347c0SRobert Dolca 55a06347c0SRobert Dolca u8 *fw_vsc_cfg; 56a06347c0SRobert Dolca u8 clock_type; 57a06347c0SRobert Dolca u32 clock_freq; 58a06347c0SRobert Dolca 59a06347c0SRobert Dolca atomic_t data_pkt_counter; 60a06347c0SRobert Dolca void (*data_pkt_counter_cb)(struct nci_dev *ndev); 61a06347c0SRobert Dolca u8 setup_patch_sent; 62a06347c0SRobert Dolca u8 setup_patch_ntf; 63a06347c0SRobert Dolca u8 setup_patch_status; 64a06347c0SRobert Dolca u8 setup_reset_ntf; 65a06347c0SRobert Dolca wait_queue_head_t setup_wq; 66a06347c0SRobert Dolca }; 67a06347c0SRobert Dolca 68a06347c0SRobert Dolca static u8 nci_core_get_config_otp_ram_version[5] = { 69a06347c0SRobert Dolca 0x04, 70a06347c0SRobert Dolca NCI_PARAM_ID_FW_RAM_VERSION, 71a06347c0SRobert Dolca NCI_PARAM_ID_FW_OTP_VERSION, 72a06347c0SRobert Dolca NCI_PARAM_ID_OTP_LIMITED_VERSION, 73a06347c0SRobert Dolca NCI_PARAM_ID_KEY_INDEX_ID 74a06347c0SRobert Dolca }; 75a06347c0SRobert Dolca 76a06347c0SRobert Dolca struct nci_core_get_config_rsp { 77a06347c0SRobert Dolca u8 status; 78a06347c0SRobert Dolca u8 count; 79da60fbe7SGustavo A. R. Silva u8 data[]; 80a06347c0SRobert Dolca }; 81a06347c0SRobert Dolca 82a06347c0SRobert Dolca static int fdp_nci_create_conn(struct nci_dev *ndev) 83a06347c0SRobert Dolca { 84a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 85a06347c0SRobert Dolca struct core_conn_create_dest_spec_params param; 86a06347c0SRobert Dolca int r; 87a06347c0SRobert Dolca 88a06347c0SRobert Dolca /* proprietary destination specific paramerer without value */ 89a06347c0SRobert Dolca param.type = FDP_PATCH_CONN_PARAM_TYPE; 90a06347c0SRobert Dolca param.length = 0x00; 91a06347c0SRobert Dolca 92a06347c0SRobert Dolca r = nci_core_conn_create(info->ndev, FDP_PATCH_CONN_DEST, 1, 93a06347c0SRobert Dolca sizeof(param), ¶m); 94a06347c0SRobert Dolca if (r) 95a06347c0SRobert Dolca return r; 96a06347c0SRobert Dolca 979b8d1a4cSChristophe Ricard return nci_get_conn_info_by_dest_type_params(ndev, 989b8d1a4cSChristophe Ricard FDP_PATCH_CONN_DEST, NULL); 99a06347c0SRobert Dolca } 100a06347c0SRobert Dolca 101a06347c0SRobert Dolca static inline int fdp_nci_get_versions(struct nci_dev *ndev) 102a06347c0SRobert Dolca { 103a06347c0SRobert Dolca return nci_core_cmd(ndev, NCI_OP_CORE_GET_CONFIG_CMD, 104a06347c0SRobert Dolca sizeof(nci_core_get_config_otp_ram_version), 105a06347c0SRobert Dolca (__u8 *) &nci_core_get_config_otp_ram_version); 106a06347c0SRobert Dolca } 107a06347c0SRobert Dolca 108a06347c0SRobert Dolca static inline int fdp_nci_patch_cmd(struct nci_dev *ndev, u8 type) 109a06347c0SRobert Dolca { 110a06347c0SRobert Dolca return nci_prop_cmd(ndev, NCI_OP_PROP_PATCH_OID, sizeof(type), &type); 111a06347c0SRobert Dolca } 112a06347c0SRobert Dolca 113a06347c0SRobert Dolca static inline int fdp_nci_set_production_data(struct nci_dev *ndev, u8 len, 114a06347c0SRobert Dolca char *data) 115a06347c0SRobert Dolca { 116a06347c0SRobert Dolca return nci_prop_cmd(ndev, NCI_OP_PROP_SET_PDATA_OID, len, data); 117a06347c0SRobert Dolca } 118a06347c0SRobert Dolca 119a06347c0SRobert Dolca static int fdp_nci_set_clock(struct nci_dev *ndev, u8 clock_type, 120a06347c0SRobert Dolca u32 clock_freq) 121a06347c0SRobert Dolca { 122a06347c0SRobert Dolca u32 fc = 13560; 123a06347c0SRobert Dolca u32 nd, num, delta; 124a06347c0SRobert Dolca char data[9]; 125a06347c0SRobert Dolca 126a06347c0SRobert Dolca nd = (24 * fc) / clock_freq; 127a06347c0SRobert Dolca delta = 24 * fc - nd * clock_freq; 128a06347c0SRobert Dolca num = (32768 * delta) / clock_freq; 129a06347c0SRobert Dolca 130a06347c0SRobert Dolca data[0] = 0x00; 131a06347c0SRobert Dolca data[1] = 0x00; 132a06347c0SRobert Dolca data[2] = 0x00; 133a06347c0SRobert Dolca 134a06347c0SRobert Dolca data[3] = 0x10; 135a06347c0SRobert Dolca data[4] = 0x04; 136a06347c0SRobert Dolca data[5] = num & 0xFF; 137a06347c0SRobert Dolca data[6] = (num >> 8) & 0xff; 138a06347c0SRobert Dolca data[7] = nd; 139a06347c0SRobert Dolca data[8] = clock_type; 140a06347c0SRobert Dolca 141a06347c0SRobert Dolca return fdp_nci_set_production_data(ndev, 9, data); 142a06347c0SRobert Dolca } 143a06347c0SRobert Dolca 144a06347c0SRobert Dolca static void fdp_nci_send_patch_cb(struct nci_dev *ndev) 145a06347c0SRobert Dolca { 146a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 147a06347c0SRobert Dolca 148a06347c0SRobert Dolca info->setup_patch_sent = 1; 149a06347c0SRobert Dolca wake_up(&info->setup_wq); 150a06347c0SRobert Dolca } 151a06347c0SRobert Dolca 152cd4375d6SKrzysztof Kozlowski /* 153a06347c0SRobert Dolca * Register a packet sent counter and a callback 154a06347c0SRobert Dolca * 155a06347c0SRobert Dolca * We have no other way of knowing when all firmware packets were sent out 156a06347c0SRobert Dolca * on the i2c bus. We need to know that in order to close the connection and 157a06347c0SRobert Dolca * send the patch end message. 158a06347c0SRobert Dolca */ 159a06347c0SRobert Dolca static void fdp_nci_set_data_pkt_counter(struct nci_dev *ndev, 160a06347c0SRobert Dolca void (*cb)(struct nci_dev *ndev), int count) 161a06347c0SRobert Dolca { 162a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 163a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 164a06347c0SRobert Dolca 165a06347c0SRobert Dolca dev_dbg(dev, "NCI data pkt counter %d\n", count); 166a06347c0SRobert Dolca atomic_set(&info->data_pkt_counter, count); 167a06347c0SRobert Dolca info->data_pkt_counter_cb = cb; 168a06347c0SRobert Dolca } 169a06347c0SRobert Dolca 170cd4375d6SKrzysztof Kozlowski /* 171a06347c0SRobert Dolca * The device is expecting a stream of packets. All packets need to 172a06347c0SRobert Dolca * have the PBF flag set to 0x0 (last packet) even if the firmware 173a06347c0SRobert Dolca * file is segmented and there are multiple packets. If we give the 174a06347c0SRobert Dolca * whole firmware to nci_send_data it will segment it and it will set 175a06347c0SRobert Dolca * the PBF flag to 0x01 so we need to do the segmentation here. 176a06347c0SRobert Dolca * 177a06347c0SRobert Dolca * The firmware will be analyzed and applied when we send NCI_OP_PROP_PATCH_CMD 178a06347c0SRobert Dolca * command with NCI_PATCH_TYPE_EOT parameter. The device will send a 1790853f5abSBhaskar Chowdhury * NFCC_PATCH_NTF packet and a NCI_OP_CORE_RESET_NTF packet. 180a06347c0SRobert Dolca */ 181a06347c0SRobert Dolca static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type) 182a06347c0SRobert Dolca { 183a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 184a06347c0SRobert Dolca const struct firmware *fw; 185a06347c0SRobert Dolca struct sk_buff *skb; 186a06347c0SRobert Dolca unsigned long len; 1870dcdf9f6SDan Carpenter int max_size, payload_size; 188a06347c0SRobert Dolca int rc = 0; 189a06347c0SRobert Dolca 190a06347c0SRobert Dolca if ((type == NCI_PATCH_TYPE_OTP && !info->otp_patch) || 191a06347c0SRobert Dolca (type == NCI_PATCH_TYPE_RAM && !info->ram_patch)) 192a06347c0SRobert Dolca return -EINVAL; 193a06347c0SRobert Dolca 194a06347c0SRobert Dolca if (type == NCI_PATCH_TYPE_OTP) 195a06347c0SRobert Dolca fw = info->otp_patch; 196a06347c0SRobert Dolca else 197a06347c0SRobert Dolca fw = info->ram_patch; 198a06347c0SRobert Dolca 199a06347c0SRobert Dolca max_size = nci_conn_max_data_pkt_payload_size(ndev, conn_id); 200a06347c0SRobert Dolca if (max_size <= 0) 201a06347c0SRobert Dolca return -EINVAL; 202a06347c0SRobert Dolca 203a06347c0SRobert Dolca len = fw->size; 204a06347c0SRobert Dolca 205a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, fdp_nci_send_patch_cb, 206a06347c0SRobert Dolca DIV_ROUND_UP(fw->size, max_size)); 207a06347c0SRobert Dolca 208a06347c0SRobert Dolca while (len) { 209a06347c0SRobert Dolca 2100dcdf9f6SDan Carpenter payload_size = min_t(unsigned long, max_size, len); 211a06347c0SRobert Dolca 212a06347c0SRobert Dolca skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + payload_size), 213a06347c0SRobert Dolca GFP_KERNEL); 214a06347c0SRobert Dolca if (!skb) { 215a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, NULL, 0); 216a06347c0SRobert Dolca return -ENOMEM; 217a06347c0SRobert Dolca } 218a06347c0SRobert Dolca 219a06347c0SRobert Dolca 220a06347c0SRobert Dolca skb_reserve(skb, NCI_CTRL_HDR_SIZE); 221a06347c0SRobert Dolca 22259ae1d12SJohannes Berg skb_put_data(skb, fw->data + (fw->size - len), payload_size); 223a06347c0SRobert Dolca 224a06347c0SRobert Dolca rc = nci_send_data(ndev, conn_id, skb); 225a06347c0SRobert Dolca 226a06347c0SRobert Dolca if (rc) { 227a06347c0SRobert Dolca fdp_nci_set_data_pkt_counter(ndev, NULL, 0); 228a06347c0SRobert Dolca return rc; 229a06347c0SRobert Dolca } 230a06347c0SRobert Dolca 231a06347c0SRobert Dolca len -= payload_size; 232a06347c0SRobert Dolca } 233a06347c0SRobert Dolca 234a06347c0SRobert Dolca return rc; 235a06347c0SRobert Dolca } 236a06347c0SRobert Dolca 237a06347c0SRobert Dolca static int fdp_nci_open(struct nci_dev *ndev) 238a06347c0SRobert Dolca { 239a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 240a06347c0SRobert Dolca 24192a310cdSzuoqilin return info->phy_ops->enable(info->phy); 242a06347c0SRobert Dolca } 243a06347c0SRobert Dolca 244a06347c0SRobert Dolca static int fdp_nci_close(struct nci_dev *ndev) 245a06347c0SRobert Dolca { 246a06347c0SRobert Dolca return 0; 247a06347c0SRobert Dolca } 248a06347c0SRobert Dolca 249a06347c0SRobert Dolca static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 250a06347c0SRobert Dolca { 251a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 252a06347c0SRobert Dolca 253a06347c0SRobert Dolca if (atomic_dec_and_test(&info->data_pkt_counter)) 254a06347c0SRobert Dolca info->data_pkt_counter_cb(ndev); 255a06347c0SRobert Dolca 256a06347c0SRobert Dolca return info->phy_ops->write(info->phy, skb); 257a06347c0SRobert Dolca } 258a06347c0SRobert Dolca 259a06347c0SRobert Dolca static int fdp_nci_request_firmware(struct nci_dev *ndev) 260a06347c0SRobert Dolca { 261a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 262a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 263a06347c0SRobert Dolca u8 *data; 264a06347c0SRobert Dolca int r; 265a06347c0SRobert Dolca 266a06347c0SRobert Dolca r = request_firmware(&info->ram_patch, FDP_RAM_PATCH_NAME, dev); 267a06347c0SRobert Dolca if (r < 0) { 268a06347c0SRobert Dolca nfc_err(dev, "RAM patch request error\n"); 269*43fa32d1Swengjianfeng return r; 270a06347c0SRobert Dolca } 271a06347c0SRobert Dolca 272a06347c0SRobert Dolca data = (u8 *) info->ram_patch->data; 273a06347c0SRobert Dolca info->ram_patch_version = 274a06347c0SRobert Dolca data[FDP_FW_HEADER_SIZE] | 275a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 1] << 8) | 276a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 2] << 16) | 277a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 3] << 24); 278a06347c0SRobert Dolca 279a06347c0SRobert Dolca dev_dbg(dev, "RAM patch version: %d, size: %d\n", 280a06347c0SRobert Dolca info->ram_patch_version, (int) info->ram_patch->size); 281a06347c0SRobert Dolca 282a06347c0SRobert Dolca 283a06347c0SRobert Dolca r = request_firmware(&info->otp_patch, FDP_OTP_PATCH_NAME, dev); 284a06347c0SRobert Dolca if (r < 0) { 285a06347c0SRobert Dolca nfc_err(dev, "OTP patch request error\n"); 286*43fa32d1Swengjianfeng return 0; 287a06347c0SRobert Dolca } 288a06347c0SRobert Dolca 289a06347c0SRobert Dolca data = (u8 *) info->otp_patch->data; 290a06347c0SRobert Dolca info->otp_patch_version = 291a06347c0SRobert Dolca data[FDP_FW_HEADER_SIZE] | 292a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE + 1] << 8) | 293a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE+2] << 16) | 294a06347c0SRobert Dolca (data[FDP_FW_HEADER_SIZE+3] << 24); 295a06347c0SRobert Dolca 296a06347c0SRobert Dolca dev_dbg(dev, "OTP patch version: %d, size: %d\n", 297a06347c0SRobert Dolca info->otp_patch_version, (int) info->otp_patch->size); 298a06347c0SRobert Dolca return 0; 299a06347c0SRobert Dolca } 300a06347c0SRobert Dolca 301a06347c0SRobert Dolca static void fdp_nci_release_firmware(struct nci_dev *ndev) 302a06347c0SRobert Dolca { 303a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 304a06347c0SRobert Dolca 305a06347c0SRobert Dolca if (info->otp_patch) { 306a06347c0SRobert Dolca release_firmware(info->otp_patch); 307a06347c0SRobert Dolca info->otp_patch = NULL; 308a06347c0SRobert Dolca } 309a06347c0SRobert Dolca 310a06347c0SRobert Dolca if (info->ram_patch) { 311a06347c0SRobert Dolca release_firmware(info->ram_patch); 312f36acc33SColin Ian King info->ram_patch = NULL; 313a06347c0SRobert Dolca } 314a06347c0SRobert Dolca } 315a06347c0SRobert Dolca 316a06347c0SRobert Dolca static int fdp_nci_patch_otp(struct nci_dev *ndev) 317a06347c0SRobert Dolca { 318a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 319a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 320fa1ce54eSGeert Uytterhoeven int conn_id; 321a06347c0SRobert Dolca int r = 0; 322a06347c0SRobert Dolca 323a06347c0SRobert Dolca if (info->otp_version >= info->otp_patch_version) 324872fff33Swengjianfeng return r; 325a06347c0SRobert Dolca 326a06347c0SRobert Dolca info->setup_patch_sent = 0; 327a06347c0SRobert Dolca info->setup_reset_ntf = 0; 328a06347c0SRobert Dolca info->setup_patch_ntf = 0; 329a06347c0SRobert Dolca 330a06347c0SRobert Dolca /* Patch init request */ 331a06347c0SRobert Dolca r = fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_OTP); 332a06347c0SRobert Dolca if (r) 333872fff33Swengjianfeng return r; 334a06347c0SRobert Dolca 335a06347c0SRobert Dolca /* Patch data connection creation */ 336a06347c0SRobert Dolca conn_id = fdp_nci_create_conn(ndev); 337872fff33Swengjianfeng if (conn_id < 0) 338872fff33Swengjianfeng return conn_id; 339a06347c0SRobert Dolca 340a06347c0SRobert Dolca /* Send the patch over the data connection */ 341a06347c0SRobert Dolca r = fdp_nci_send_patch(ndev, conn_id, NCI_PATCH_TYPE_OTP); 342a06347c0SRobert Dolca if (r) 343872fff33Swengjianfeng return r; 344a06347c0SRobert Dolca 345a06347c0SRobert Dolca /* Wait for all the packets to be send over i2c */ 346a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, 347a06347c0SRobert Dolca info->setup_patch_sent == 1); 348a06347c0SRobert Dolca 349a06347c0SRobert Dolca /* make sure that the NFCC processed the last data packet */ 350a06347c0SRobert Dolca msleep(FDP_FW_UPDATE_SLEEP); 351a06347c0SRobert Dolca 352a06347c0SRobert Dolca /* Close the data connection */ 353a06347c0SRobert Dolca r = nci_core_conn_close(info->ndev, conn_id); 354a06347c0SRobert Dolca if (r) 355872fff33Swengjianfeng return r; 356a06347c0SRobert Dolca 357a06347c0SRobert Dolca /* Patch finish message */ 358a06347c0SRobert Dolca if (fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_EOT)) { 359a06347c0SRobert Dolca nfc_err(dev, "OTP patch error 0x%x\n", r); 360872fff33Swengjianfeng return -EINVAL; 361a06347c0SRobert Dolca } 362a06347c0SRobert Dolca 363a06347c0SRobert Dolca /* If the patch notification didn't arrive yet, wait for it */ 364a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_patch_ntf); 365a06347c0SRobert Dolca 366a06347c0SRobert Dolca /* Check if the patching was successful */ 367a06347c0SRobert Dolca r = info->setup_patch_status; 368a06347c0SRobert Dolca if (r) { 369a06347c0SRobert Dolca nfc_err(dev, "OTP patch error 0x%x\n", r); 370872fff33Swengjianfeng return -EINVAL; 371a06347c0SRobert Dolca } 372a06347c0SRobert Dolca 373a06347c0SRobert Dolca /* 374a06347c0SRobert Dolca * We need to wait for the reset notification before we 375a06347c0SRobert Dolca * can continue 376a06347c0SRobert Dolca */ 377a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_reset_ntf); 378a06347c0SRobert Dolca 379a06347c0SRobert Dolca return r; 380a06347c0SRobert Dolca } 381a06347c0SRobert Dolca 382a06347c0SRobert Dolca static int fdp_nci_patch_ram(struct nci_dev *ndev) 383a06347c0SRobert Dolca { 384a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 385a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 386fa1ce54eSGeert Uytterhoeven int conn_id; 387a06347c0SRobert Dolca int r = 0; 388a06347c0SRobert Dolca 389a06347c0SRobert Dolca if (info->ram_version >= info->ram_patch_version) 390872fff33Swengjianfeng return r; 391a06347c0SRobert Dolca 392a06347c0SRobert Dolca info->setup_patch_sent = 0; 393a06347c0SRobert Dolca info->setup_reset_ntf = 0; 394a06347c0SRobert Dolca info->setup_patch_ntf = 0; 395a06347c0SRobert Dolca 396a06347c0SRobert Dolca /* Patch init request */ 397a06347c0SRobert Dolca r = fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_RAM); 398a06347c0SRobert Dolca if (r) 399872fff33Swengjianfeng return r; 400a06347c0SRobert Dolca 401a06347c0SRobert Dolca /* Patch data connection creation */ 402a06347c0SRobert Dolca conn_id = fdp_nci_create_conn(ndev); 403872fff33Swengjianfeng if (conn_id < 0) 404872fff33Swengjianfeng return conn_id; 405a06347c0SRobert Dolca 406a06347c0SRobert Dolca /* Send the patch over the data connection */ 407a06347c0SRobert Dolca r = fdp_nci_send_patch(ndev, conn_id, NCI_PATCH_TYPE_RAM); 408a06347c0SRobert Dolca if (r) 409872fff33Swengjianfeng return r; 410a06347c0SRobert Dolca 411a06347c0SRobert Dolca /* Wait for all the packets to be send over i2c */ 412a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, 413a06347c0SRobert Dolca info->setup_patch_sent == 1); 414a06347c0SRobert Dolca 415a06347c0SRobert Dolca /* make sure that the NFCC processed the last data packet */ 416a06347c0SRobert Dolca msleep(FDP_FW_UPDATE_SLEEP); 417a06347c0SRobert Dolca 418a06347c0SRobert Dolca /* Close the data connection */ 419a06347c0SRobert Dolca r = nci_core_conn_close(info->ndev, conn_id); 420a06347c0SRobert Dolca if (r) 421872fff33Swengjianfeng return r; 422a06347c0SRobert Dolca 423a06347c0SRobert Dolca /* Patch finish message */ 424a06347c0SRobert Dolca if (fdp_nci_patch_cmd(ndev, NCI_PATCH_TYPE_EOT)) { 425a06347c0SRobert Dolca nfc_err(dev, "RAM patch error 0x%x\n", r); 426872fff33Swengjianfeng return -EINVAL; 427a06347c0SRobert Dolca } 428a06347c0SRobert Dolca 429a06347c0SRobert Dolca /* If the patch notification didn't arrive yet, wait for it */ 430a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_patch_ntf); 431a06347c0SRobert Dolca 432a06347c0SRobert Dolca /* Check if the patching was successful */ 433a06347c0SRobert Dolca r = info->setup_patch_status; 434a06347c0SRobert Dolca if (r) { 435a06347c0SRobert Dolca nfc_err(dev, "RAM patch error 0x%x\n", r); 436872fff33Swengjianfeng return -EINVAL; 437a06347c0SRobert Dolca } 438a06347c0SRobert Dolca 439a06347c0SRobert Dolca /* 440a06347c0SRobert Dolca * We need to wait for the reset notification before we 441a06347c0SRobert Dolca * can continue 442a06347c0SRobert Dolca */ 443a06347c0SRobert Dolca wait_event_interruptible(info->setup_wq, info->setup_reset_ntf); 444a06347c0SRobert Dolca 445a06347c0SRobert Dolca return r; 446a06347c0SRobert Dolca } 447a06347c0SRobert Dolca 448a06347c0SRobert Dolca static int fdp_nci_setup(struct nci_dev *ndev) 449a06347c0SRobert Dolca { 450a06347c0SRobert Dolca /* Format: total length followed by an NCI packet */ 451a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 452a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 453a06347c0SRobert Dolca int r; 454a06347c0SRobert Dolca u8 patched = 0; 455a06347c0SRobert Dolca 456a06347c0SRobert Dolca r = nci_core_init(ndev); 457a06347c0SRobert Dolca if (r) 458a06347c0SRobert Dolca goto error; 459a06347c0SRobert Dolca 460a06347c0SRobert Dolca /* Get RAM and OTP version */ 461a06347c0SRobert Dolca r = fdp_nci_get_versions(ndev); 462a06347c0SRobert Dolca if (r) 463a06347c0SRobert Dolca goto error; 464a06347c0SRobert Dolca 465a06347c0SRobert Dolca /* Load firmware from disk */ 466a06347c0SRobert Dolca r = fdp_nci_request_firmware(ndev); 467a06347c0SRobert Dolca if (r) 468a06347c0SRobert Dolca goto error; 469a06347c0SRobert Dolca 470a06347c0SRobert Dolca /* Update OTP */ 471a06347c0SRobert Dolca if (info->otp_version < info->otp_patch_version) { 472a06347c0SRobert Dolca r = fdp_nci_patch_otp(ndev); 473a06347c0SRobert Dolca if (r) 474a06347c0SRobert Dolca goto error; 475a06347c0SRobert Dolca patched = 1; 476a06347c0SRobert Dolca } 477a06347c0SRobert Dolca 478a06347c0SRobert Dolca /* Update RAM */ 479a06347c0SRobert Dolca if (info->ram_version < info->ram_patch_version) { 480a06347c0SRobert Dolca r = fdp_nci_patch_ram(ndev); 481a06347c0SRobert Dolca if (r) 482a06347c0SRobert Dolca goto error; 483a06347c0SRobert Dolca patched = 1; 484a06347c0SRobert Dolca } 485a06347c0SRobert Dolca 486a06347c0SRobert Dolca /* Release the firmware buffers */ 487a06347c0SRobert Dolca fdp_nci_release_firmware(ndev); 488a06347c0SRobert Dolca 489a06347c0SRobert Dolca /* If a patch was applied the new version is checked */ 490a06347c0SRobert Dolca if (patched) { 491a06347c0SRobert Dolca r = nci_core_init(ndev); 492a06347c0SRobert Dolca if (r) 493a06347c0SRobert Dolca goto error; 494a06347c0SRobert Dolca 495a06347c0SRobert Dolca r = fdp_nci_get_versions(ndev); 496a06347c0SRobert Dolca if (r) 497a06347c0SRobert Dolca goto error; 498a06347c0SRobert Dolca 499a06347c0SRobert Dolca if (info->otp_version != info->otp_patch_version || 500a06347c0SRobert Dolca info->ram_version != info->ram_patch_version) { 501a06347c0SRobert Dolca nfc_err(dev, "Firmware update failed"); 502a06347c0SRobert Dolca r = -EINVAL; 503a06347c0SRobert Dolca goto error; 504a06347c0SRobert Dolca } 505a06347c0SRobert Dolca } 506a06347c0SRobert Dolca 507a06347c0SRobert Dolca /* 508a06347c0SRobert Dolca * We initialized the devices but the NFC subsystem expects 509a06347c0SRobert Dolca * it to not be initialized. 510a06347c0SRobert Dolca */ 511a06347c0SRobert Dolca return nci_core_reset(ndev); 512a06347c0SRobert Dolca 513a06347c0SRobert Dolca error: 514a06347c0SRobert Dolca fdp_nci_release_firmware(ndev); 515a06347c0SRobert Dolca nfc_err(dev, "Setup error %d\n", r); 516a06347c0SRobert Dolca return r; 517a06347c0SRobert Dolca } 518a06347c0SRobert Dolca 519a06347c0SRobert Dolca static int fdp_nci_post_setup(struct nci_dev *ndev) 520a06347c0SRobert Dolca { 521a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 522a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 523a06347c0SRobert Dolca int r; 524a06347c0SRobert Dolca 525a06347c0SRobert Dolca /* Check if the device has VSC */ 526a06347c0SRobert Dolca if (info->fw_vsc_cfg && info->fw_vsc_cfg[0]) { 527a06347c0SRobert Dolca 528a06347c0SRobert Dolca /* Set the vendor specific configuration */ 529a06347c0SRobert Dolca r = fdp_nci_set_production_data(ndev, info->fw_vsc_cfg[3], 530a06347c0SRobert Dolca &info->fw_vsc_cfg[4]); 531a06347c0SRobert Dolca if (r) { 532a06347c0SRobert Dolca nfc_err(dev, "Vendor specific config set error %d\n", 533a06347c0SRobert Dolca r); 534a06347c0SRobert Dolca return r; 535a06347c0SRobert Dolca } 536a06347c0SRobert Dolca } 537a06347c0SRobert Dolca 538a06347c0SRobert Dolca /* Set clock type and frequency */ 539a06347c0SRobert Dolca r = fdp_nci_set_clock(ndev, info->clock_type, info->clock_freq); 540a06347c0SRobert Dolca if (r) { 541a06347c0SRobert Dolca nfc_err(dev, "Clock set error %d\n", r); 542a06347c0SRobert Dolca return r; 543a06347c0SRobert Dolca } 544a06347c0SRobert Dolca 545a06347c0SRobert Dolca /* 546a06347c0SRobert Dolca * In order to apply the VSC FDP needs a reset 547a06347c0SRobert Dolca */ 548a06347c0SRobert Dolca r = nci_core_reset(ndev); 549a06347c0SRobert Dolca if (r) 550a06347c0SRobert Dolca return r; 551a06347c0SRobert Dolca 552a06347c0SRobert Dolca /** 553a06347c0SRobert Dolca * The nci core was initialized when post setup was called 554a06347c0SRobert Dolca * so we leave it like that 555a06347c0SRobert Dolca */ 556a06347c0SRobert Dolca return nci_core_init(ndev); 557a06347c0SRobert Dolca } 558a06347c0SRobert Dolca 559a06347c0SRobert Dolca static int fdp_nci_core_reset_ntf_packet(struct nci_dev *ndev, 560a06347c0SRobert Dolca struct sk_buff *skb) 561a06347c0SRobert Dolca { 562a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 563a06347c0SRobert Dolca 564a06347c0SRobert Dolca info->setup_reset_ntf = 1; 565a06347c0SRobert Dolca wake_up(&info->setup_wq); 566a06347c0SRobert Dolca 567a06347c0SRobert Dolca return 0; 568a06347c0SRobert Dolca } 569a06347c0SRobert Dolca 570a06347c0SRobert Dolca static int fdp_nci_prop_patch_ntf_packet(struct nci_dev *ndev, 571a06347c0SRobert Dolca struct sk_buff *skb) 572a06347c0SRobert Dolca { 573a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 574a06347c0SRobert Dolca 575a06347c0SRobert Dolca info->setup_patch_ntf = 1; 576a06347c0SRobert Dolca info->setup_patch_status = skb->data[0]; 577a06347c0SRobert Dolca wake_up(&info->setup_wq); 578a06347c0SRobert Dolca 579a06347c0SRobert Dolca return 0; 580a06347c0SRobert Dolca } 581a06347c0SRobert Dolca 582a06347c0SRobert Dolca static int fdp_nci_prop_patch_rsp_packet(struct nci_dev *ndev, 583a06347c0SRobert Dolca struct sk_buff *skb) 584a06347c0SRobert Dolca { 585a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 586a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 587a06347c0SRobert Dolca u8 status = skb->data[0]; 588a06347c0SRobert Dolca 589a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, status); 590a06347c0SRobert Dolca nci_req_complete(ndev, status); 591a06347c0SRobert Dolca 592a06347c0SRobert Dolca return 0; 593a06347c0SRobert Dolca } 594a06347c0SRobert Dolca 595a06347c0SRobert Dolca static int fdp_nci_prop_set_production_data_rsp_packet(struct nci_dev *ndev, 596a06347c0SRobert Dolca struct sk_buff *skb) 597a06347c0SRobert Dolca { 598a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 599a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 600a06347c0SRobert Dolca u8 status = skb->data[0]; 601a06347c0SRobert Dolca 602a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, status); 603a06347c0SRobert Dolca nci_req_complete(ndev, status); 604a06347c0SRobert Dolca 605a06347c0SRobert Dolca return 0; 606a06347c0SRobert Dolca } 607a06347c0SRobert Dolca 608a06347c0SRobert Dolca static int fdp_nci_core_get_config_rsp_packet(struct nci_dev *ndev, 609a06347c0SRobert Dolca struct sk_buff *skb) 610a06347c0SRobert Dolca { 611a06347c0SRobert Dolca struct fdp_nci_info *info = nci_get_drvdata(ndev); 612a06347c0SRobert Dolca struct device *dev = &info->phy->i2c_dev->dev; 613a06347c0SRobert Dolca struct nci_core_get_config_rsp *rsp = (void *) skb->data; 614a06347c0SRobert Dolca u8 i, *p; 615a06347c0SRobert Dolca 616a06347c0SRobert Dolca if (rsp->status == NCI_STATUS_OK) { 617a06347c0SRobert Dolca 618a06347c0SRobert Dolca p = rsp->data; 619a06347c0SRobert Dolca for (i = 0; i < 4; i++) { 620a06347c0SRobert Dolca 621a06347c0SRobert Dolca switch (*p++) { 622a06347c0SRobert Dolca case NCI_PARAM_ID_FW_RAM_VERSION: 623a06347c0SRobert Dolca p++; 624a06347c0SRobert Dolca info->ram_version = le32_to_cpup((__le32 *) p); 625a06347c0SRobert Dolca p += 4; 626a06347c0SRobert Dolca break; 627a06347c0SRobert Dolca case NCI_PARAM_ID_FW_OTP_VERSION: 628a06347c0SRobert Dolca p++; 629a06347c0SRobert Dolca info->otp_version = le32_to_cpup((__le32 *) p); 630a06347c0SRobert Dolca p += 4; 631a06347c0SRobert Dolca break; 632a06347c0SRobert Dolca case NCI_PARAM_ID_OTP_LIMITED_VERSION: 633a06347c0SRobert Dolca p++; 634a06347c0SRobert Dolca info->otp_version = le32_to_cpup((__le32 *) p); 635a06347c0SRobert Dolca p += 4; 636a06347c0SRobert Dolca break; 637a06347c0SRobert Dolca case NCI_PARAM_ID_KEY_INDEX_ID: 638a06347c0SRobert Dolca p++; 639a06347c0SRobert Dolca info->key_index = *p++; 640a06347c0SRobert Dolca } 641a06347c0SRobert Dolca } 642a06347c0SRobert Dolca } 643a06347c0SRobert Dolca 644a06347c0SRobert Dolca dev_dbg(dev, "OTP version %d\n", info->otp_version); 645a06347c0SRobert Dolca dev_dbg(dev, "RAM version %d\n", info->ram_version); 646a06347c0SRobert Dolca dev_dbg(dev, "key index %d\n", info->key_index); 647a06347c0SRobert Dolca dev_dbg(dev, "%s: status 0x%x\n", __func__, rsp->status); 648a06347c0SRobert Dolca 649a06347c0SRobert Dolca nci_req_complete(ndev, rsp->status); 650a06347c0SRobert Dolca 651a06347c0SRobert Dolca return 0; 652a06347c0SRobert Dolca } 653a06347c0SRobert Dolca 654a06347c0SRobert Dolca static struct nci_driver_ops fdp_core_ops[] = { 655a06347c0SRobert Dolca { 656a06347c0SRobert Dolca .opcode = NCI_OP_CORE_GET_CONFIG_RSP, 657a06347c0SRobert Dolca .rsp = fdp_nci_core_get_config_rsp_packet, 658a06347c0SRobert Dolca }, 659a06347c0SRobert Dolca { 660a06347c0SRobert Dolca .opcode = NCI_OP_CORE_RESET_NTF, 661a06347c0SRobert Dolca .ntf = fdp_nci_core_reset_ntf_packet, 662a06347c0SRobert Dolca }, 663a06347c0SRobert Dolca }; 664a06347c0SRobert Dolca 665a06347c0SRobert Dolca static struct nci_driver_ops fdp_prop_ops[] = { 666a06347c0SRobert Dolca { 667a06347c0SRobert Dolca .opcode = nci_opcode_pack(NCI_GID_PROP, NCI_OP_PROP_PATCH_OID), 668a06347c0SRobert Dolca .rsp = fdp_nci_prop_patch_rsp_packet, 669a06347c0SRobert Dolca .ntf = fdp_nci_prop_patch_ntf_packet, 670a06347c0SRobert Dolca }, 671a06347c0SRobert Dolca { 672a06347c0SRobert Dolca .opcode = nci_opcode_pack(NCI_GID_PROP, 673a06347c0SRobert Dolca NCI_OP_PROP_SET_PDATA_OID), 674a06347c0SRobert Dolca .rsp = fdp_nci_prop_set_production_data_rsp_packet, 675a06347c0SRobert Dolca }, 676a06347c0SRobert Dolca }; 677a06347c0SRobert Dolca 67881ade1cdSColin Ian King static struct nci_ops nci_ops = { 679a06347c0SRobert Dolca .open = fdp_nci_open, 680a06347c0SRobert Dolca .close = fdp_nci_close, 681a06347c0SRobert Dolca .send = fdp_nci_send, 682a06347c0SRobert Dolca .setup = fdp_nci_setup, 683a06347c0SRobert Dolca .post_setup = fdp_nci_post_setup, 684a06347c0SRobert Dolca .prop_ops = fdp_prop_ops, 685a06347c0SRobert Dolca .n_prop_ops = ARRAY_SIZE(fdp_prop_ops), 686a06347c0SRobert Dolca .core_ops = fdp_core_ops, 687a06347c0SRobert Dolca .n_core_ops = ARRAY_SIZE(fdp_core_ops), 688a06347c0SRobert Dolca }; 689a06347c0SRobert Dolca 690a06347c0SRobert Dolca int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops, 691a06347c0SRobert Dolca struct nci_dev **ndevp, int tx_headroom, 692a06347c0SRobert Dolca int tx_tailroom, u8 clock_type, u32 clock_freq, 693a06347c0SRobert Dolca u8 *fw_vsc_cfg) 694a06347c0SRobert Dolca { 695a06347c0SRobert Dolca struct device *dev = &phy->i2c_dev->dev; 696a06347c0SRobert Dolca struct fdp_nci_info *info; 697a06347c0SRobert Dolca struct nci_dev *ndev; 698a06347c0SRobert Dolca u32 protocols; 699a06347c0SRobert Dolca int r; 700a06347c0SRobert Dolca 7017b9fcda9SAndy Shevchenko info = devm_kzalloc(dev, sizeof(struct fdp_nci_info), GFP_KERNEL); 7027b9fcda9SAndy Shevchenko if (!info) 7037b9fcda9SAndy Shevchenko return -ENOMEM; 704a06347c0SRobert Dolca 705a06347c0SRobert Dolca info->phy = phy; 706a06347c0SRobert Dolca info->phy_ops = phy_ops; 707a06347c0SRobert Dolca info->clock_type = clock_type; 708a06347c0SRobert Dolca info->clock_freq = clock_freq; 709a06347c0SRobert Dolca info->fw_vsc_cfg = fw_vsc_cfg; 710a06347c0SRobert Dolca 711a06347c0SRobert Dolca init_waitqueue_head(&info->setup_wq); 712a06347c0SRobert Dolca 713a06347c0SRobert Dolca protocols = NFC_PROTO_JEWEL_MASK | 714a06347c0SRobert Dolca NFC_PROTO_MIFARE_MASK | 715a06347c0SRobert Dolca NFC_PROTO_FELICA_MASK | 716a06347c0SRobert Dolca NFC_PROTO_ISO14443_MASK | 717a06347c0SRobert Dolca NFC_PROTO_ISO14443_B_MASK | 718a06347c0SRobert Dolca NFC_PROTO_NFC_DEP_MASK | 719a06347c0SRobert Dolca NFC_PROTO_ISO15693_MASK; 720a06347c0SRobert Dolca 721a06347c0SRobert Dolca ndev = nci_allocate_device(&nci_ops, protocols, tx_headroom, 722a06347c0SRobert Dolca tx_tailroom); 723a06347c0SRobert Dolca if (!ndev) { 724a06347c0SRobert Dolca nfc_err(dev, "Cannot allocate nfc ndev\n"); 7257b9fcda9SAndy Shevchenko return -ENOMEM; 726a06347c0SRobert Dolca } 727a06347c0SRobert Dolca 728a06347c0SRobert Dolca r = nci_register_device(ndev); 729a06347c0SRobert Dolca if (r) 730a06347c0SRobert Dolca goto err_regdev; 731a06347c0SRobert Dolca 732a06347c0SRobert Dolca *ndevp = ndev; 733a06347c0SRobert Dolca info->ndev = ndev; 734a06347c0SRobert Dolca 735a06347c0SRobert Dolca nci_set_drvdata(ndev, info); 736a06347c0SRobert Dolca 737a06347c0SRobert Dolca return 0; 738a06347c0SRobert Dolca 739a06347c0SRobert Dolca err_regdev: 740a06347c0SRobert Dolca nci_free_device(ndev); 741a06347c0SRobert Dolca return r; 742a06347c0SRobert Dolca } 743a06347c0SRobert Dolca EXPORT_SYMBOL(fdp_nci_probe); 744a06347c0SRobert Dolca 745a06347c0SRobert Dolca void fdp_nci_remove(struct nci_dev *ndev) 746a06347c0SRobert Dolca { 747a06347c0SRobert Dolca nci_unregister_device(ndev); 748a06347c0SRobert Dolca nci_free_device(ndev); 749a06347c0SRobert Dolca } 750a06347c0SRobert Dolca EXPORT_SYMBOL(fdp_nci_remove); 751a06347c0SRobert Dolca 752a06347c0SRobert Dolca MODULE_LICENSE("GPL"); 753a06347c0SRobert Dolca MODULE_DESCRIPTION("NFC NCI driver for Intel Fields Peak NFC controller"); 754a06347c0SRobert Dolca MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>"); 755