|
| 1 | +{ |
| 2 | + config, |
| 3 | + lib, |
| 4 | + pkgs, |
| 5 | + ... |
| 6 | +}: |
| 7 | + |
| 8 | +let |
| 9 | + cfg = config.hardware.nfc-nci; |
| 10 | + |
| 11 | + # To understand these settings in more detail, refer to the upstream configuration templates |
| 12 | + # available at https://github.com/NXPNFCLinux/linux_libnfc-nci/tree/master/conf . |
| 13 | + # Settings in curly braces are NCI commands, the "NFC Controller Interface Specification" |
| 14 | + # as well as the "NFC Digital Protocol Technical Specification" can be found online. |
| 15 | + # These default settings have been specifically engineered for the Lenovo NXP1001 (NPC300) chipset. |
| 16 | + defaultSettings = { |
| 17 | + # This block will be emitted into /etc/libnfc-nci.conf |
| 18 | + nci = { |
| 19 | + # Set up general logging |
| 20 | + APPL_TRACE_LEVEL = "0x01"; |
| 21 | + PROTOCOL_TRACE_LEVEL = "0x01"; |
| 22 | + # Set up which NFC technologies are enabled (due to e.g. local regulation or patent law) |
| 23 | + HOST_LISTEN_TECH_MASK = "0x07"; |
| 24 | + POLLING_TECH_MASK = "0xEF"; |
| 25 | + P2P_LISTEN_TECH_MASK = "0xC5"; |
| 26 | + }; |
| 27 | + # This block will be emitted into /etc/libnfc-nxp-init.conf |
| 28 | + init = { |
| 29 | + # Setup logging of the individual userland library components |
| 30 | + NXPLOG_GLOBAL_LOGLEVEL = "0x01"; |
| 31 | + NXPLOG_EXTNS_LOGLEVEL = "0x01"; |
| 32 | + NXPLOG_NCIHAL_LOGLEVEL = "0x01"; |
| 33 | + NXPLOG_NCIX_LOGLEVEL = "0x01"; |
| 34 | + NXPLOG_NCIR_LOGLEVEL = "0x01"; |
| 35 | + NXPLOG_FWDNLD_LOGLEVEL = "0x00"; |
| 36 | + NXPLOG_TML_LOGLEVEL = "0x01"; |
| 37 | + # Where to find the kernel device node |
| 38 | + NXP_NFC_DEV_NODE = ''"/dev/pn544"''; |
| 39 | + # Enable the NXP proprietary features of the chip |
| 40 | + NXP_ACT_PROP_EXTN = "{2F, 02, 00}"; |
| 41 | + # Configure the NFC Forum profile: |
| 42 | + # 0xA0 0x44: POLL_PROFILE_SEL_CFG = 0x00 (Use NFC Forum profile default configuration values. Specifically, not EMVCo.) |
| 43 | + NXP_NFC_PROFILE_EXTN = '' |
| 44 | + {20, 02, 05, 01, |
| 45 | + A0, 44, 01, 00 |
| 46 | + } |
| 47 | + ''; |
| 48 | + # Enable chip standby mode |
| 49 | + NXP_CORE_STANDBY = "{2F, 00, 01, 01}"; |
| 50 | + # Enable NCI packet fragmentation on the I2C bus |
| 51 | + NXP_I2C_FRAGMENTATION_ENABLED = "0x01"; |
| 52 | + }; |
| 53 | + # This block will be emitted into /etc/libnfc-nxp-pn547.conf as well as /etc/libnfc-nxp-pn548.conf |
| 54 | + # Which file is actually used is decided by the library at runtime depending on chip variant, both files are required. |
| 55 | + pn54x = { |
| 56 | + # Enable Mifare Classic reader functionality |
| 57 | + MIFARE_READER_ENABLE = "0x01"; |
| 58 | + # Configure clock source - use XTAL (hardware crystal) instead of PLL (synthetic clock) |
| 59 | + NXP_SYS_CLK_SRC_SEL = "0x01"; |
| 60 | + NXP_SYS_CLK_FREQ_SEL = "0x00"; |
| 61 | + NXP_SYS_CLOCK_TO_CFG = "0x01"; |
| 62 | + # Configure the non-propriety NCI settings in EEPROM: |
| 63 | + # 0x28: PN_NFC_DEP_SPEED = 0x00 (Data exchange: Highest Available Bit Rates) |
| 64 | + # 0x21: PI_BIT_RATE = 0x00 (Maximum allowed bit rate: 106 Kbit/s) |
| 65 | + # 0x30: LA_BIT_FRAME_SDD = 0x08 (Bit Frame SDD value to be sent in Byte 1 of SENS_RES) |
| 66 | + # 0x31: LA_PLATFORM_CONFIG = 0x03 (Platform Configuration value to be sent in Byte 2 of SENS_RES) |
| 67 | + # 0x33: LA_NFCID1 = [ 0x04 0x03 0x02 0x01 ] ("Unique" NFCID1 ID in SENS_RES) |
| 68 | + # 0x54: LF_CON_BITR_F = 0x06 (Bit rates to listen for: Both) |
| 69 | + # 0x50: LF_PROTOCOL_TYPE = 0x02 (Protocols supported in Listen Mode for NFC-F: NFC-DEP) |
| 70 | + # 0x5B: LI_BIT_RATE = 0x00 (Maximum supported bit rate: 106 Kbit/s) |
| 71 | + # 0x60: LN_WT = 0x0E (Waiting Time NFC-DEP WT_MAX default for Initiator) |
| 72 | + # 0x80: RF_FIELD_INFO = 0x01 (Chip is allowed to emit RF Field Information Notifications) |
| 73 | + # 0x81: RF_NFCEE_ACTION = 0x01 (Chip should send trigger notification for the default set of NFCEE actions) |
| 74 | + # 0x82: NFCDEP_OP = 0x0E (NFC-DEP protocol behavior: Default flags, but also enable RTOX requests) |
| 75 | + # 0x18: PF_BIT_RATE = 0x01 (NFC-F discovery polling initial bit rate: 106 Kbit/s) |
| 76 | + NXP_CORE_CONF = '' |
| 77 | + {20, 02, 2B, 0D, |
| 78 | + 28, 01, 00, |
| 79 | + 21, 01, 00, |
| 80 | + 30, 01, 08, |
| 81 | + 31, 01, 03, |
| 82 | + 33, 04, 04, 03, 02, 01, |
| 83 | + 54, 01, 06, |
| 84 | + 50, 01, 02, |
| 85 | + 5B, 01, 00, |
| 86 | + 60, 01, 0E, |
| 87 | + 80, 01, 01, |
| 88 | + 81, 01, 01, |
| 89 | + 82, 01, 0E, |
| 90 | + 18, 01, 01 |
| 91 | + } |
| 92 | + ''; |
| 93 | + # Configure the proprietary NXP extension to the NCI standard in EEPROM: |
| 94 | + # 0xA0 0x5E: JEWEL_RID_CFG = 0x01 (Enable sending RID to T1T on RF) |
| 95 | + # 0xA0 0x40: TAG_DETECTOR_CFG = 0x00 (Tag detector: Disable both AGC based detection and trace mode) |
| 96 | + # 0xA0 0x43: TAG_DETECTOR_FALLBACK_CNT_CFG = 0x00 (Tag detector: Disable hybrid mode, only use LPCD to initiate polling) |
| 97 | + # 0xA0 0x0F: DH_EEPROM_AREA_1 = [ 32 bytes of opaque Lenovo data ] (Custom configuration for the Lenovo customized chip firmware) |
| 98 | + # See also https://github.com/nfc-tools/libnfc/issues/455#issuecomment-2221979571 |
| 99 | + NXP_CORE_CONF_EXTN = '' |
| 100 | + {20, 02, 30, 04, |
| 101 | + A0, 5E, 01, 01, |
| 102 | + A0, 40, 01, 00, |
| 103 | + A0, 43, 01, 00, |
| 104 | + A0, 0F, 20, |
| 105 | + 00, 03, 1D, 01, 03, 00, 02, 00, |
| 106 | + 01, 00, 01, 00, 00, 00, 00, 00, |
| 107 | + 00, 00, 00, 00, 00, 00, 00, 00, |
| 108 | + 00, 00, 00, 00, 00, 00, 00, 00 |
| 109 | + } |
| 110 | + ''; |
| 111 | + # Firmware-specific protocol configuration parameters (one byte per protocol) |
| 112 | + NXP_NFC_PROPRIETARY_CFG = "{05:FF:FF:06:81:80:70:FF:FF}"; |
| 113 | + # Configure power supply of chip, use Lenovo driver configuration, which deviates a bit from the spec: |
| 114 | + # 0xA0 0x0E: PMU_CFG = [ 0x16, 0x09, 0x00 ] (VBAT1 connected to 5V, TVDD monitoring: 3.6V, TxLDO Voltage in reader and card mode: 3.3V) |
| 115 | + NXP_EXT_TVDD_CFG = "0x01"; |
| 116 | + NXP_EXT_TVDD_CFG_1 = '' |
| 117 | + {20, 02, 07, 01, |
| 118 | + A0, 0E, 03, 16, 09, 00 |
| 119 | + } |
| 120 | + ''; |
| 121 | + # Use the default for NFA_EE_MAX_EE_SUPPORTED stack size (concerns HCI) |
| 122 | + NXP_NFC_MAX_EE_SUPPORTED = "0x00"; |
| 123 | + }; |
| 124 | + }; |
| 125 | + |
| 126 | + generateSettings = |
| 127 | + cfgName: |
| 128 | + let |
| 129 | + toKeyValueLines = |
| 130 | + obj: builtins.concatStringsSep "\n" (map (key: "${key}=${obj.${key}}") (builtins.attrNames obj)); |
| 131 | + in |
| 132 | + toKeyValueLines (defaultSettings.${cfgName} // (cfg.settings.${cfgName} or { })); |
| 133 | +in |
| 134 | +{ |
| 135 | + options.hardware.nfc-nci = { |
| 136 | + enable = lib.mkEnableOption "PN5xx kernel module with udev rules, libnfc-nci userland, and optional ifdnfc-nci PC/SC driver"; |
| 137 | + |
| 138 | + settings = lib.mkOption { |
| 139 | + default = defaultSettings; |
| 140 | + description = '' |
| 141 | + Configuration to be written to the libncf-nci configuration files. |
| 142 | + To understand the configuration format, refer to https://github.com/NXPNFCLinux/linux_libnfc-nci/tree/master/conf. |
| 143 | + ''; |
| 144 | + type = lib.types.attrs; |
| 145 | + }; |
| 146 | + |
| 147 | + enableIFD = lib.mkOption { |
| 148 | + type = lib.types.bool; |
| 149 | + default = true; |
| 150 | + description = '' |
| 151 | + Register ifdnfc-nci as a serial reader with pcscd. |
| 152 | + ''; |
| 153 | + }; |
| 154 | + }; |
| 155 | + |
| 156 | + config = lib.mkIf cfg.enable { |
| 157 | + environment.systemPackages = |
| 158 | + [ |
| 159 | + pkgs.libnfc-nci |
| 160 | + ] |
| 161 | + ++ lib.optionals cfg.enableIFD [ |
| 162 | + pkgs.ifdnfc-nci |
| 163 | + ]; |
| 164 | + |
| 165 | + environment.etc = { |
| 166 | + "libnfc-nci.conf".text = generateSettings "nci"; |
| 167 | + "libnfc-nxp-init.conf".text = generateSettings "init"; |
| 168 | + "libnfc-nxp-pn547.conf".text = generateSettings "pn54x"; |
| 169 | + "libnfc-nxp-pn548.conf".text = generateSettings "pn54x"; |
| 170 | + }; |
| 171 | + |
| 172 | + services.udev.packages = [ |
| 173 | + config.boot.kernelPackages.nxp-pn5xx |
| 174 | + ]; |
| 175 | + |
| 176 | + boot.blacklistedKernelModules = [ |
| 177 | + "nxp_nci_i2c" |
| 178 | + "nxp_nci" |
| 179 | + ]; |
| 180 | + |
| 181 | + boot.extraModulePackages = [ |
| 182 | + config.boot.kernelPackages.nxp-pn5xx |
| 183 | + ]; |
| 184 | + |
| 185 | + boot.kernelModules = [ |
| 186 | + "nxp-pn5xx" |
| 187 | + ]; |
| 188 | + |
| 189 | + services.pcscd.readerConfigs = lib.mkIf cfg.enableIFD [ |
| 190 | + '' |
| 191 | + FRIENDLYNAME "NFC NCI" |
| 192 | + LIBPATH ${pkgs.ifdnfc-nci}/lib/libifdnfc-nci.so |
| 193 | + CHANNELID 0 |
| 194 | + '' |
| 195 | + ]; |
| 196 | + |
| 197 | + # NFC chip looses power when system goes to sleep / hibernate, |
| 198 | + # and needs to be re-initialized upon wakeup |
| 199 | + powerManagement.resumeCommands = lib.mkIf cfg.enableIFD '' |
| 200 | + systemctl restart pcscd.service |
| 201 | + ''; |
| 202 | + }; |
| 203 | + |
| 204 | + meta.maintainers = with lib.maintainers; [ stargate01 ]; |
| 205 | +} |
0 commit comments