diff options
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/smartcard')
5 files changed, 1953 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h new file mode 100644 index 0000000000..2c7f81609b --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard.h @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SMARTCARD_H_ +#define _FSL_SMARTCARD_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup smartcard + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief Smart card driver version 2.2.2. + */ +#define FSL_SMARTCARD_DRIVER_VERSION (MAKE_VERSION(2, 2, 2)) +/*@}*/ + +/*! @brief Smart card global define which specify number of clock cycles until initial 'TS' character has to be received + */ +#define SMARTCARD_INIT_DELAY_CLOCK_CYCLES (42000u) + +/*! @brief Smart card global define which specify number of clock cycles during which ATR string has to be received */ +#define SMARTCARD_EMV_ATR_DURATION_ETU (20150u) + +/*! @brief Smart card specification initial TS character definition of direct convention */ +#define SMARTCARD_TS_DIRECT_CONVENTION (0x3Bu) + +/*! @brief Smart card specification initial TS character definition of inverse convention */ +#define SMARTCARD_TS_INVERSE_CONVENTION (0x3Fu) + +/*! @brief Smart card Error codes. */ +enum +{ + kStatus_SMARTCARD_Success = MAKE_STATUS(kStatusGroup_SMARTCARD, 0), /*!< Transfer ends successfully */ + kStatus_SMARTCARD_TxBusy = MAKE_STATUS(kStatusGroup_SMARTCARD, 1), /*!< Transmit in progress */ + kStatus_SMARTCARD_RxBusy = MAKE_STATUS(kStatusGroup_SMARTCARD, 2), /*!< Receiving in progress */ + kStatus_SMARTCARD_NoTransferInProgress = MAKE_STATUS(kStatusGroup_SMARTCARD, 3), /*!< No transfer in progress */ + kStatus_SMARTCARD_Timeout = MAKE_STATUS(kStatusGroup_SMARTCARD, 4), /*!< Transfer ends with time-out */ + kStatus_SMARTCARD_Initialized = + MAKE_STATUS(kStatusGroup_SMARTCARD, 5), /*!< Smart card driver is already initialized */ + kStatus_SMARTCARD_PhyInitialized = + MAKE_STATUS(kStatusGroup_SMARTCARD, 6), /*!< Smart card PHY drive is already initialized */ + kStatus_SMARTCARD_CardNotActivated = MAKE_STATUS(kStatusGroup_SMARTCARD, 7), /*!< Smart card is not activated */ + kStatus_SMARTCARD_InvalidInput = + MAKE_STATUS(kStatusGroup_SMARTCARD, 8), /*!< Function called with invalid input arguments */ + kStatus_SMARTCARD_OtherError = MAKE_STATUS(kStatusGroup_SMARTCARD, 9) /*!< Some other error occur */ +}; + +/*! @brief Control codes for the Smart card protocol timers and misc. */ +typedef enum _smartcard_control +{ + kSMARTCARD_EnableADT = 0x0u, + kSMARTCARD_DisableADT = 0x1u, + kSMARTCARD_EnableGTV = 0x2u, + kSMARTCARD_DisableGTV = 0x3u, + kSMARTCARD_ResetWWT = 0x4u, + kSMARTCARD_EnableWWT = 0x5u, + kSMARTCARD_DisableWWT = 0x6u, + kSMARTCARD_ResetCWT = 0x7u, + kSMARTCARD_EnableCWT = 0x8u, + kSMARTCARD_DisableCWT = 0x9u, + kSMARTCARD_ResetBWT = 0xAu, + kSMARTCARD_EnableBWT = 0xBu, + kSMARTCARD_DisableBWT = 0xCu, + kSMARTCARD_EnableInitDetect = 0xDu, + kSMARTCARD_EnableAnack = 0xEu, + kSMARTCARD_DisableAnack = 0xFu, + kSMARTCARD_ConfigureBaudrate = 0x10u, + kSMARTCARD_SetupATRMode = 0x11u, + kSMARTCARD_SetupT0Mode = 0x12u, + kSMARTCARD_SetupT1Mode = 0x13u, + kSMARTCARD_EnableReceiverMode = 0x14u, + kSMARTCARD_DisableReceiverMode = 0x15u, + kSMARTCARD_EnableTransmitterMode = 0x16u, + kSMARTCARD_DisableTransmitterMode = 0x17u, + kSMARTCARD_ResetWaitTimeMultiplier = 0x18u, +} smartcard_control_t; + +/*! @brief Defines Smart card interface voltage class values */ +typedef enum _smartcard_card_voltage_class +{ + kSMARTCARD_VoltageClassUnknown = 0x0u, + kSMARTCARD_VoltageClassA5_0V = 0x1u, + kSMARTCARD_VoltageClassB3_3V = 0x2u, + kSMARTCARD_VoltageClassC1_8V = 0x3u +} smartcard_card_voltage_class_t; + +/*! @brief Defines Smart card I/O transfer states */ +typedef enum _smartcard_transfer_state +{ + kSMARTCARD_IdleState = 0x0u, + kSMARTCARD_WaitingForTSState = 0x1u, + kSMARTCARD_InvalidTSDetecetedState = 0x2u, + kSMARTCARD_ReceivingState = 0x3u, + kSMARTCARD_TransmittingState = 0x4u, +} smartcard_transfer_state_t; + +/*! @brief Defines Smart card reset types */ +typedef enum _smartcard_reset_type +{ + kSMARTCARD_ColdReset = 0x0u, + kSMARTCARD_WarmReset = 0x1u, + kSMARTCARD_NoColdReset = 0x2u, + kSMARTCARD_NoWarmReset = 0x3u, +} smartcard_reset_type_t; + +/*! @brief Defines Smart card transport protocol types */ +typedef enum _smartcard_transport_type +{ + kSMARTCARD_T0Transport = 0x0u, + kSMARTCARD_T1Transport = 0x1u +} smartcard_transport_type_t; + +/*! @brief Defines Smart card data parity types */ +typedef enum _smartcard_parity_type +{ + kSMARTCARD_EvenParity = 0x0u, + kSMARTCARD_OddParity = 0x1u +} smartcard_parity_type_t; + +/*! @brief Defines data Convention format */ +typedef enum _smartcard_card_convention +{ + kSMARTCARD_DirectConvention = 0x0u, + kSMARTCARD_InverseConvention = 0x1u +} smartcard_card_convention_t; + +/*! @brief Defines Smart card interface IC control types */ +typedef enum _smartcard_interface_control +{ + kSMARTCARD_InterfaceSetVcc = 0x00u, + kSMARTCARD_InterfaceSetClockToResetDelay = 0x01u, + kSMARTCARD_InterfaceReadStatus = 0x02u +} smartcard_interface_control_t; + +/*! @brief Defines transfer direction.*/ +typedef enum _smartcard_direction +{ + kSMARTCARD_Receive = 0u, + kSMARTCARD_Transmit = 1u +} smartcard_direction_t; + +/*! @brief Smart card interface interrupt callback function type */ +typedef void (*smartcard_interface_callback_t)(void *smartcardContext, void *param); +/*! @brief Smart card transfer interrupt callback function type */ +typedef void (*smartcard_transfer_callback_t)(void *smartcardContext, void *param); + +/*! @brief Time Delay function used to passive waiting using RTOS [us] */ +typedef void (*smartcard_time_delay_t)(uint32_t us); + +/*! @brief Defines card-specific parameters for Smart card driver */ +typedef struct _smartcard_card_params +{ + /* ISO7816/EMV4.3 specification variables */ + uint16_t Fi; /*!< 4 bits Fi - clock rate conversion integer */ + uint8_t fMax; /*!< Maximum Smart card frequency in MHz */ + uint8_t WI; /*!< 8 bits WI - work wait time integer */ + uint8_t Di; /*!< 4 bits DI - baud rate divisor */ + uint8_t BWI; /*!< 4 bits BWI - block wait time integer */ + uint8_t CWI; /*!< 4 bits CWI - character wait time integer */ + uint8_t BGI; /*!< 4 bits BGI - block guard time integer */ + uint8_t GTN; /*!< 8 bits GTN - extended guard time integer */ + uint8_t IFSC; /*!< Indicates IFSC value of the card */ + uint8_t modeNegotiable; /*!< Indicates if the card acts in negotiable or a specific mode. */ + uint8_t currentD; /*!< 4 bits DI - current baud rate divisor*/ + /* Driver-specific variables */ + uint8_t status; /*!< Indicates smart card status */ + bool t0Indicated; /*!< Indicates ff T=0 indicated in TD1 byte */ + bool t1Indicated; /*!< Indicates if T=1 indicated in TD2 byte */ + bool atrComplete; /*!< Indicates whether the ATR received from the card was complete or not */ + bool atrValid; /*!< Indicates whether the ATR received from the card was valid or not */ + bool present; /*!< Indicates if a smart card is present */ + bool active; /*!< Indicates if the smart card is activated */ + bool faulty; /*!< Indicates whether smart card/interface is faulty */ + smartcard_card_convention_t convention; /*!< Card convention, kSMARTCARD_DirectConvention for direct convention, + kSMARTCARD_InverseConvention for inverse convention */ +} smartcard_card_params_t; + +/*! @brief Smart card defines the state of the EMV timers in the Smart card driver */ +typedef struct _smartcard_timers_state +{ + volatile bool adtExpired; /*!< Indicates whether ADT timer expired */ + volatile bool wwtExpired; /*!< Indicates whether WWT timer expired */ + volatile bool cwtExpired; /*!< Indicates whether CWT timer expired */ + volatile bool bwtExpired; /*!< Indicates whether BWT timer expired */ + volatile bool initCharTimerExpired; /*!< Indicates whether reception timer + for initialization character (TS) after the RST has expired */ +} smartcard_timers_state_t; + +/*! @brief Defines user specified configuration of Smart card interface */ +typedef struct _smartcard_interface_config +{ + uint32_t smartCardClock; /*!< Smart card interface clock [Hz] */ + uint32_t clockToResetDelay; /*!< Indicates clock to RST apply delay [smart card clock cycles] */ + uint8_t clockModule; /*!< Smart card clock module number */ + uint8_t clockModuleChannel; /*!< Smart card clock module channel number */ + uint8_t clockModuleSourceClock; /*!< Smart card clock module source clock [e.g., BusClk] */ + smartcard_card_voltage_class_t vcc; /*!< Smart card voltage class */ + uint8_t controlPort; /*!< Smart card PHY control port instance */ + uint8_t controlPin; /*!< Smart card PHY control pin instance */ + uint8_t irqPort; /*!< Smart card PHY Interrupt port instance */ + uint8_t irqPin; /*!< Smart card PHY Interrupt pin instance */ + uint8_t resetPort; /*!< Smart card reset port instance */ + uint8_t resetPin; /*!< Smart card reset pin instance */ + uint8_t vsel0Port; /*!< Smart card PHY Vsel0 control port instance */ + uint8_t vsel0Pin; /*!< Smart card PHY Vsel0 control pin instance */ + uint8_t vsel1Port; /*!< Smart card PHY Vsel1 control port instance */ + uint8_t vsel1Pin; /*!< Smart card PHY Vsel1 control pin instance */ + uint8_t dataPort; /*!< Smart card PHY data port instance */ + uint8_t dataPin; /*!< Smart card PHY data pin instance */ + uint8_t dataPinMux; /*!< Smart card PHY data pin mux option */ + uint8_t tsTimerId; /*!< Numerical identifier of the External HW timer for Initial character detection */ +} smartcard_interface_config_t; + +/*! @brief Defines user transfer structure used to initialize transfer */ +typedef struct _smartcard_xfer +{ + smartcard_direction_t direction; /*!< Direction of communication. (RX/TX) */ + uint8_t *buff; /*!< The buffer of data. */ + size_t size; /*!< The number of transferred units. */ +} smartcard_xfer_t; + +/*! + * @brief Runtime state of the Smart card driver. + */ +typedef struct _smartcard_context +{ + /* Xfer part */ + void *base; /*!< Smart card module base address */ + smartcard_direction_t direction; /*!< Direction of communication. (RX/TX) */ + uint8_t *xBuff; /*!< The buffer of data being transferred.*/ + volatile size_t xSize; /*!< The number of bytes to be transferred. */ + volatile bool xIsBusy; /*!< True if there is an active transfer. */ + uint8_t txFifoEntryCount; /*!< Number of data word entries in transmit FIFO. */ + uint8_t rxFifoThreshold; /*!< The max value of the receiver FIFO threshold. */ + /* Smart card Interface part */ + smartcard_interface_callback_t interfaceCallback; /*!< Callback to invoke after interface IC raised interrupt.*/ + smartcard_transfer_callback_t transferCallback; /*!< Callback to invoke after transfer event occur.*/ + void *interfaceCallbackParam; /*!< Interface callback parameter pointer.*/ + void *transferCallbackParam; /*!< Transfer callback parameter pointer.*/ + smartcard_time_delay_t timeDelay; /*!< Function which handles time delay defined by user or RTOS. */ + smartcard_reset_type_t resetType; /*!< Indicates whether a Cold reset or Warm reset was requested. */ + smartcard_transport_type_t tType; /*!< Indicates current transfer protocol (T0 or T1) */ + /* Smart card State part */ + volatile smartcard_transfer_state_t transferState; /*!< Indicates the current transfer state */ + smartcard_timers_state_t timersState; /*!< Indicates the state of different protocol timers used in driver */ + smartcard_card_params_t + cardParams; /*!< Smart card parameters(ATR and current) and interface slots states(ATR and current) */ + uint8_t IFSD; /*!< Indicates the terminal IFSD */ + smartcard_parity_type_t parity; /*!< Indicates current parity even/odd */ + volatile bool rxtCrossed; /*!< Indicates whether RXT thresholds has been crossed */ + volatile bool txtCrossed; /*!< Indicates whether TXT thresholds has been crossed */ + volatile bool wtxRequested; /*!< Indicates whether WTX has been requested or not*/ + volatile bool parityError; /*!< Indicates whether a parity error has been detected */ + uint8_t statusBytes[2]; /*!< Used to store Status bytes SW1, SW2 of the last executed card command response */ + /* Configuration part */ + smartcard_interface_config_t interfaceConfig; /*!< Smart card interface configuration structure */ + bool abortTransfer; /*!< Used to abort transfer. */ +} smartcard_context_t; + +/*! @}*/ +#endif /* _FSL_SMARTCARD_H_*/ diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c new file mode 100644 index 0000000000..61bca20b49 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.c @@ -0,0 +1,1143 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_smartcard_emvsim.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.smartcard_emvsim" +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to emvsim bases for each instance. */ +static EMVSIM_Type *const s_emvsimBases[] = EMVSIM_BASE_PTRS; + +/*! @brief Pointers to emvsim IRQ number for each instance. */ +static const IRQn_Type s_emvsimIRQ[] = EMVSIM_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to emvsim clocks for each instance. */ +static const clock_ip_name_t s_emvsimClock[] = EMVSIM_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/* #define CARDSIM_EXTRADELAY_USED */ + +/******************************************************************************* + * Private Functions + ******************************************************************************/ +static void smartcard_emvsim_CompleteSendData(EMVSIM_Type *base, smartcard_context_t *context); +static void smartcard_emvsim_StartSendData(EMVSIM_Type *base, smartcard_context_t *context); +static void smartcard_emvsim_CompleteReceiveData(EMVSIM_Type *base, smartcard_context_t *context); +static void smartcard_emvsim_StartReceiveData(EMVSIM_Type *base, smartcard_context_t *context); +static void smartcard_emvsim_SetTransferType(EMVSIM_Type *base, + smartcard_context_t *context, + smartcard_control_t control); +static uint32_t smartcard_emvsim_GetInstance(EMVSIM_Type *base); + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief Get the UART instance from peripheral base address. + * + * @param base UART peripheral base address. + * @return UART instance. + */ +static uint32_t smartcard_emvsim_GetInstance(EMVSIM_Type *base) +{ + uint8_t instance = 0; + uint32_t emvsimArrayCount = (sizeof(s_emvsimBases) / sizeof(s_emvsimBases[0])); + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < emvsimArrayCount; instance++) + { + if (s_emvsimBases[instance] == base) + { + break; + } + } + + assert(instance < emvsimArrayCount); + + return instance; +} +/*! + * @brief Finish up a transmit by completing the process of sending data and disabling the interrupt. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a SMARTCARD driver context structure. + */ +static void smartcard_emvsim_CompleteSendData(EMVSIM_Type *base, smartcard_context_t *context) +{ + assert((NULL != context)); + + /* Disable ETC and TDT interrupt */ + base->INT_MASK |= (EMVSIM_INT_MASK_ETC_IM_MASK | EMVSIM_INT_MASK_TDT_IM_MASK); + + /* Disable transmitter */ + base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK; + /* Clear receive status flag */ + base->RX_STATUS = EMVSIM_RX_STATUS_RX_DATA_MASK; + /* Enable Receiver */ + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + /* Update the information of the module driver context */ + context->xIsBusy = false; + context->transferState = kSMARTCARD_IdleState; + /* Clear txSize to avoid any spurious transmit from ISR */ + context->xSize = 0u; + /* Invoke user call-back */ + if (NULL != context->transferCallback) + { + context->transferCallback(context, context->transferCallbackParam); + } +} + +/*! + * @brief Finish up a receive by completing the process of receiving data and disabling the interrupt. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a SMARTCARD driver context structure. + */ +static void smartcard_emvsim_CompleteReceiveData(EMVSIM_Type *base, smartcard_context_t *context) +{ + assert((NULL != context)); + + /* Disable RDT and RX_DATA interrupt */ + base->INT_MASK |= (EMVSIM_INT_MASK_RDT_IM_MASK | EMVSIM_INT_MASK_RX_DATA_IM_MASK); + + /* Read data from fifo */ + while (((base->RX_STATUS & EMVSIM_RX_STATUS_RX_CNT_MASK) != 0u) && ((context->xSize) > 0u)) + { + /* Get data and put into receive buffer */ + *context->xBuff = (uint8_t)(base->RX_BUF); + ++context->xBuff; + --context->xSize; + } + + /* Update the information of the module driver context */ + context->xIsBusy = false; + /* Invoke user call-back */ + if (NULL != context->transferCallback) + { + context->transferCallback(context, context->transferCallbackParam); + } +} + +/*! + * @brief Initiate (start) a transmit by beginning the process of sending data and enabling the interrupt. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a SMARTCARD driver context structure. + */ +static void smartcard_emvsim_StartSendData(EMVSIM_Type *base, smartcard_context_t *context) +{ + assert((NULL != context)); + + uint32_t delay = 0u; + uint32_t control = 0u; + + /* Block guard time */ + /* 22 etus (16 Receiver Clocks == 1 etu) */ + delay = 22u * 16u; + /* Disable all functionality like protocol timers, NACK generation */ + control = base->CTRL; + base->CTRL = 0u; + base->TX_GETU = context->cardParams.GTN; + /* Clear Global counter time-out flag */ + base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK; + /* Disable counter interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK; + /* Set counter value */ + base->GPCNT1_VAL = delay; + /* Select the clock for GPCNT */ + base->CLKCFG = + (base->CLKCFG & ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK) | EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCRxClock); + /* Trigger the counter */ + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + /* Wait until counter overflow event occur */ + while ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT1_TO_MASK) == 0u) + { + } + /* Clear status flag and disable GPCNT1 clock */ + base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK; + base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK; + /* Restore Control register */ + base->CTRL = control & ~(EMVSIM_CTRL_XMT_EN_MASK | EMVSIM_CTRL_RCV_EN_MASK); + /* Update transferState */ + context->transferState = kSMARTCARD_TransmittingState; + context->xIsBusy = true; + + /* Flush transmitter */ + base->CTRL |= EMVSIM_CTRL_FLSH_TX_MASK; + + /* Enable transmitter */ + base->CTRL |= EMVSIM_CTRL_XMT_EN_MASK; + + /* Set transmitter data threshold value to 0 - TDTF is set when the fifo is empty */ + base->TX_THD &= ~EMVSIM_TX_THD_TDT_MASK; + + /* Enable TDT interrupt */ + base->INT_MASK &= ~EMVSIM_INT_MASK_TDT_IM_MASK; +} + +/*! + * @brief Initiate (start) a receive by beginning the process of receiving data and enabling the interrupt. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a SMARTCARD driver context structure. + */ +static void smartcard_emvsim_StartReceiveData(EMVSIM_Type *base, smartcard_context_t *context) +{ + assert((NULL != context)); + + /* Initialize the module driver context structure to indicate transfer in progress */ + context->xIsBusy = true; + /* Enable BWT Timer interrupt to occur */ + base->INT_MASK &= ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK; + /* Disable transmitter */ + base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK; + /* Enable receiver and switch to receive direction */ + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + + /* Set rx threshold value - number of bytes that must exist in the Receive FIFO to trigger the receive data + * threshold interrupt flag (RDTF).*/ + if (context->xSize < context->rxFifoThreshold) + { + uint32_t rx_thd; + rx_thd = (base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK); + rx_thd |= context->xSize; + base->RX_THD = rx_thd; + } + else + { + base->RX_THD = ((base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK) | context->rxFifoThreshold); + } + + /* Enable RDT interrupt - count of bytes in rx fifo is equal or greater than threshold RX_THD[RDT] */ + base->INT_MASK &= ~EMVSIM_INT_MASK_RDT_IM_MASK; + + if (context->tType == kSMARTCARD_T1Transport) + { + /* Enable interrupt when new byte is received - in T=1 is necessary to disable BWT interrupt and enable CWT + * interrupt after receiving the first byte */ + base->INT_MASK &= ~EMVSIM_INT_MASK_RX_DATA_IM_MASK; + } +} + +/*! + * @brief Sets up the EMVSIM hardware for T=0 or T=1 protocol data exchange and initialize timer values. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a SMARTCARD driver context structure. + */ +static void smartcard_emvsim_SetTransferType(EMVSIM_Type *base, + smartcard_context_t *context, + smartcard_control_t control) +{ + assert((NULL != context)); + assert((control == kSMARTCARD_SetupATRMode) || (control == kSMARTCARD_SetupT0Mode) || + (control == kSMARTCARD_SetupT1Mode)); + + uint16_t temp16 = 0u; + uint32_t bwiVal = 0u; + uint8_t tdt = 0u; + + if (control == kSMARTCARD_SetupATRMode) + { + /* Disable all functionality at first */ + base->CTRL &= ~(EMVSIM_CTRL_RCVR_11_MASK | EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK | + EMVSIM_CTRL_ANACK_MASK | EMVSIM_CTRL_ONACK_MASK | EMVSIM_CTRL_RCV_EN_MASK); + /* Set default values as per EMV specification */ + context->cardParams.Fi = 372u; + context->cardParams.Di = 1u; + context->cardParams.currentD = 1u; + context->cardParams.WI = 0x0Au; + context->cardParams.GTN = 0x00u; + /* Set default baudrate/ETU time based on EMV parameters and card clock */ + base->DIVISOR = (((uint32_t)context->cardParams.Fi / context->cardParams.currentD) & 0x1FFu); + /* EMV expectation: WWT = (960 x D x WI) + (D x 480) + * EMVSIM formula: BWT_VAL[15:0] = CWT_VAL[15:0] */ + temp16 = (960u * context->cardParams.currentD * context->cardParams.WI) + + (context->cardParams.currentD * 480u) + SMARTCARD_WWT_ADJUSTMENT; + base->CWT_VAL = temp16; + base->BWT_VAL = temp16; + /* Set Extended Guard Timer value + * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 12 + * EMVSIM formula: same as above */ + base->TX_GETU = context->cardParams.GTN; + /* Setting Rx threshold so that an interrupt is generated when a NACK is + sent either due to parity error or wrong INIT char*/ + base->RX_THD = EMVSIM_RX_THD_RDT(1); + /* Setting up Tx NACK threshold */ + tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u); + base->TX_THD = (EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD) | EMVSIM_TX_THD_TDT(tdt)); + /* Clear all pending interrupts */ + base->RX_STATUS = 0xFFFFFFFFu; + /* Enable Tx NACK threshold interrupt to occur */ + base->INT_MASK &= ~EMVSIM_INT_MASK_TNACK_IM_MASK; + /* Set transport type to T=0 in SMARTCARD context structure */ + context->tType = kSMARTCARD_T0Transport; + } + else if (control == kSMARTCARD_SetupT0Mode) + { + /* Disable receiver at first if it's not, Disable T=0 mode counters 1st, + * Setup for single wire ISO7816 mode (setup 12 etu mode). + * Set transport protocol type to T=0, Disable initial character detection.*/ + base->CTRL &= + ~(EMVSIM_CTRL_RCV_EN_MASK | EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_RCVR_11_MASK | + EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK | EMVSIM_CTRL_ICM_MASK); + /* EMV expectation: WWT = (960 x D x WI) + (D x 480) + * EMVSIM formula: BWT_VAL[15:0] = CWT_VAL[15:0] */ + temp16 = (960u * context->cardParams.currentD * context->cardParams.WI) + + (context->cardParams.currentD * 480u) + SMARTCARD_WWT_ADJUSTMENT; + base->CWT_VAL = temp16; + base->BWT_VAL = temp16; + /* Set Extended Guard Timer value + * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 12 + * EMVSIM formula: same as above for range [0:254] + * Fix for EMV. If TX_GETU == 0 in T0 mode, 3 stop bits are inserted. */ + context->cardParams.GTN = (context->cardParams.GTN == 0xFFu) ? 0x00u : context->cardParams.GTN; + base->TX_GETU = context->cardParams.GTN; + /* Setting Rx threshold so that an interrupt is generated when a NACK is + sent either due to parity error or wrong INIT char */ + base->RX_THD = (EMVSIM_RX_THD_RNCK_THD(SMARTCARD_EMV_RX_NACK_THRESHOLD) | EMVSIM_RX_THD_RDT(1)); + /* Setting up Tx NACK threshold */ + tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u); + base->TX_THD = (EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD) | EMVSIM_TX_THD_TDT(tdt)); + /* Enable Tx NACK threshold interrupt to occur */ + base->INT_MASK &= ~EMVSIM_INT_MASK_TNACK_IM_MASK; + /* Enable T=0 mode counters, Enable NACK on error interrupt and NACK on overflow interrupt */ + base->CTRL |= + (EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_ANACK_MASK | EMVSIM_CTRL_ONACK_MASK); + /* Set transport type to T=0 in SMARTCARD context structure */ + context->tType = kSMARTCARD_T0Transport; + } + else + { /* Disable T=1 mode counters 1st, Disable NACK on error interrupt, Disable NACK on overflow interrupt */ + base->CTRL &= ~(EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK | EMVSIM_CTRL_ANACK_MASK | + EMVSIM_CTRL_ONACK_MASK | EMVSIM_CTRL_XMT_CRC_LRC_MASK | EMVSIM_CTRL_LRC_EN_MASK); + /* Calculate and set Block Wait Timer (BWT) value + * EMV expectation: BWT = 11 + (2^BWI x 960 x D) + (D x 960) = 11 + (2^BWI + 1) x 960 x D + * EMVSIM formula: BWT = Same */ + bwiVal = 11u + ((((uint32_t)1u << context->cardParams.BWI) + 1u) * 960u * context->cardParams.currentD); +#ifdef CARDSIM_EXTRADELAY_USED + base->BWT_VAL = bwiVal + 100u; +#else + base->BWT_VAL = bwiVal; +#endif + /* Calculate and set Character Wait Timer (CWT) value + * EMV expectation: CWT = ((2^CWI + 11) + 4) + * EMVSIM formula: CWT = Same */ + if (context->cardParams.currentD == 1u) + { +#ifdef CARDSIM_EXTRADELAY_USED + temp16 = ((uint16_t)1u << context->cardParams.CWI) + 16u; +#else + temp16 = ((uint16_t)1u << context->cardParams.CWI) + 15u; +#endif + } + else + { +#ifdef CARDSIM_EXTRADELAY_USED + temp16 = ((uint16_t)1u << context->cardParams.CWI) + 20u + SMARTCARD_CWT_ADJUSTMENT; +#else + temp16 = ((uint16_t)1u << context->cardParams.CWI) + 15u + SMARTCARD_CWT_ADJUSTMENT; +#endif + } + /* EMV = 15, ISO = 11, + * EMV expectation: BGT = 22 + * EMVSIM formula: BGT = Same */ + base->CWT_VAL = temp16; + context->cardParams.BGI = 22u; + base->BGT_VAL = context->cardParams.BGI; + /* Set Extended Guard Timer value + * EMV expectation: GT = GTN not equal to 255 -> 12 + GTN = GTN equal to 255 -> 11 + * EMVSIM formula: same as above */ + base->TX_GETU = context->cardParams.GTN; + /* Setup for single wire ISO7816 mode, + * Set transport protocol type to T=1, Enable T=0 mode counters */ + base->CTRL |= (EMVSIM_CTRL_RCVR_11_MASK | EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK); + /* Setting Rx threshold */ + base->RX_THD = (EMVSIM_RX_THD_RNCK_THD(SMARTCARD_EMV_RX_NACK_THRESHOLD) | EMVSIM_RX_THD_RDT(1)); + /* Setting up Tx threshold */ + tdt = (uint8_t)(((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT) - 1u); + base->TX_THD = (EMVSIM_TX_THD_TDT(tdt) | EMVSIM_TX_THD_TNCK_THD(SMARTCARD_EMV_TX_NACK_THRESHOLD)); + /* Set transport type to T=1 in SMARTCARD context structure */ + context->tType = kSMARTCARD_T1Transport; + } +} + +/*! + * brief Fills in the smartcard_card_params structure with default values according to the EMV 4.3 specification. + * + * param cardParams The configuration structure of type smartcard_interface_config_t. + * Function fill in members: + * Fi = 372; + * Di = 1; + * currentD = 1; + * WI = 0x0A; + * GTN = 0x00; + * with default values. + */ +void SMARTCARD_EMVSIM_GetDefaultConfig(smartcard_card_params_t *cardParams) +{ + /* Initializes the configure structure to zero. */ + (void)memset(cardParams, 0, sizeof(*cardParams)); + + /* EMV default values */ + cardParams->Fi = 372u; + cardParams->Di = 1u; + cardParams->currentD = 1u; + cardParams->WI = 0x0Au; + cardParams->GTN = 0x00u; +} + +/*! + * brief Initializes an EMVSIM peripheral for the Smart card/ISO-7816 operation. + * + * This function un-gates the EMVSIM clock, initializes the module to EMV default settings, + * configures the IRQ, enables the module-level interrupt to the core and, initializes the driver context. + * + * param base The EMVSIM peripheral base address. + * param context A pointer to the smart card driver context structure. + * param srcClock_Hz Smart card clock generation module source clock. + * + * return An error code or kStatus_SMARTCARD_Success. + */ +status_t SMARTCARD_EMVSIM_Init(EMVSIM_Type *base, smartcard_context_t *context, uint32_t srcClock_Hz) +{ + assert((NULL != base)); + + if ((NULL == context) || (srcClock_Hz == 0u)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + uint32_t instance = smartcard_emvsim_GetInstance(base); +/* Set source clock for EMVSIM MCGPLLCLK */ +#if (defined(FSL_FEATURE_SOC_MCG_COUNT) && FSL_FEATURE_SOC_MCG_COUNT) + CLOCK_SetEmvsimClock(1u); +#endif +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable emvsim clock */ + CLOCK_EnableClock(s_emvsimClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + context->base = base; + /* Initialize EMVSIM to a known context. */ + base->CLKCFG = 0u; + base->DIVISOR = 372u; + base->CTRL = 0x300u; + base->INT_MASK = 0x7FFFu; + base->RX_THD = 1u; + base->TX_THD = 0u; + base->PCSR = 0x1000000u; + base->TX_GETU = 0u; + base->CWT_VAL = 0xFFFFu; + base->BWT_VAL = 0xFFFFFFFFu; + base->BGT_VAL = 0u; + base->GPCNT0_VAL = 0xFFFFu; + base->GPCNT1_VAL = 0xFFFFu; + /* Initialize EMVSIM module for SMARTCARD mode of default operation */ + smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupATRMode); + /* Store information about tx fifo depth */ + context->txFifoEntryCount = + (uint8_t)((base->PARAM & EMVSIM_PARAM_TX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_TX_FIFO_DEPTH_SHIFT); + /* Compute max value of rx fifo threshold */ + context->rxFifoThreshold = + (uint8_t)((base->PARAM & EMVSIM_PARAM_RX_FIFO_DEPTH_MASK) >> EMVSIM_PARAM_RX_FIFO_DEPTH_SHIFT); + if ((EMVSIM_RX_THD_RDT_MASK >> EMVSIM_RX_THD_RDT_SHIFT) < context->rxFifoThreshold) + { + context->rxFifoThreshold = (EMVSIM_RX_THD_RDT_MASK >> EMVSIM_RX_THD_RDT_SHIFT); + } +/* Enable EMVSIM interrupt on NVIC level. */ +#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && FSL_FEATURE_SOC_INTMUX_COUNT + if ((uint32_t)s_emvsimIRQ[instance] < (uint32_t)FSL_FEATURE_INTMUX_IRQ_START_INDEX) + { + NVIC_EnableIRQ(s_emvsimIRQ[instance]); + } +#else + NVIC_EnableIRQ(s_emvsimIRQ[instance]); +#endif + /* Finally, disable the EMVSIM receiver and transmitter */ + base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK & ~EMVSIM_CTRL_RCV_EN_MASK; + + return kStatus_SMARTCARD_Success; +} + +/*! + * brief This function disables the EMVSIM interrupts, disables the transmitter and receiver, + * flushes the FIFOs, and gates EMVSIM clock in SIM. + * + * param base The EMVSIM module base address. + */ +void SMARTCARD_EMVSIM_Deinit(EMVSIM_Type *base) +{ + uint32_t instance = 0u; + /* In case there is still data in the TX FIFO or shift register that is + * being transmitted wait till transmit is complete. + * Wait until the data is completely shifted out of shift register */ + if ((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) != 0u) + { + while ((base->TX_STATUS & EMVSIM_TX_STATUS_ETCF_MASK) == 0u) + { + } + } + instance = smartcard_emvsim_GetInstance(base); + /* Disable TX and RX */ + base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK & ~EMVSIM_CTRL_RCV_EN_MASK; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Gate EMVSIM module clock */ + CLOCK_DisableClock(s_emvsimClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +/* Disable emvsim interrupt in NVIC */ +#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && FSL_FEATURE_SOC_INTMUX_COUNT + if ((uint32_t)s_emvsimIRQ[instance] < (uint32_t)FSL_FEATURE_INTMUX_IRQ_START_INDEX) + { + NVIC_DisableIRQ(s_emvsimIRQ[instance]); + } +#else + NVIC_DisableIRQ(s_emvsimIRQ[instance]); +#endif +} + +/*! + * brief Transfer data using interrupts. + * + * A non-blocking (also known as asynchronous) function means that the function returns + * immediately after initiating the transfer function. The application has to get the + * transfer status to see when the transfer is complete. In other words, after calling the non-blocking + * (asynchronous) transfer function, the application must get the transfer status to check if the transmit + * is completed or not. + * + * param base The EMVSIM peripheral base address. + * param context A pointer to a smart card driver context structure. + * param xfer A pointer to the smart card transfer structure where the linked buffers and sizes are stored. + * + * return An error code or kStatus_SMARTCARD_Success. + */ +status_t SMARTCARD_EMVSIM_TransferNonBlocking(EMVSIM_Type *base, smartcard_context_t *context, smartcard_xfer_t *xfer) +{ + if ((NULL == context) || (NULL == xfer) || (xfer->buff == NULL)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + /* Check input parameters */ + if ((0u == xfer->size)) + { + return kStatus_SMARTCARD_Success; + } + /* Check if some transfer is in progress */ + if (0 != SMARTCARD_EMVSIM_GetTransferRemainingBytes(base, context)) + { + if (kSMARTCARD_Receive == context->direction) + { + return kStatus_SMARTCARD_RxBusy; + } + else + { + return kStatus_SMARTCARD_TxBusy; + } + } + /* Initialize error check flags */ + context->rxtCrossed = false; + context->txtCrossed = false; + context->parityError = false; + /* Initialize SMARTCARD context structure to start transfer */ + context->xBuff = xfer->buff; + context->xSize = xfer->size; + + if (kSMARTCARD_Receive == xfer->direction) + { + context->direction = xfer->direction; + context->transferState = kSMARTCARD_ReceivingState; + /* Start transfer */ + smartcard_emvsim_StartReceiveData(base, context); + } + else if (kSMARTCARD_Transmit == xfer->direction) + { + context->direction = xfer->direction; + context->transferState = kSMARTCARD_TransmittingState; + /* Start transfer */ + smartcard_emvsim_StartSendData(base, context); + } + else + { + return kStatus_SMARTCARD_InvalidInput; + } + + return kStatus_SMARTCARD_Success; +} + +/*! + * brief Returns whether the previous EMVSIM transfer has finished. + * + * When performing an async transfer, call this function to ascertain the context of the + * current transfer: in progress (or busy) or complete (success). If the + * transfer is still in progress, the user can obtain the number of words that have not been + * transferred. + * + * param base The EMVSIM module base address. + * param context A pointer to a smart card driver context structure. + * + * return The number of bytes not transferred. + */ +int32_t SMARTCARD_EMVSIM_GetTransferRemainingBytes(EMVSIM_Type *base, smartcard_context_t *context) +{ + if ((NULL == context)) + { + return -1; + } + if (context->xIsBusy) + { + if (context->direction == kSMARTCARD_Transmit) + { + /* Count of bytes in buffer + data in fifo */ + uint32_t count; + count = context->xSize; + count += ((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) >> EMVSIM_TX_STATUS_TX_CNT_SHIFT); + return (int32_t)count; + } + return (int32_t)context->xSize; + } + + return 0; +} + +/*! + * brief Terminates an asynchronous EMVSIM transfer early. + * + * During an async EMVSIM transfer, the user can terminate the transfer early + * if the transfer is still in progress. + * + * param base The EMVSIM peripheral address. + * param context A pointer to a smart card driver context structure. + * retval kStatus_SMARTCARD_Success The transmit abort was successful. + * retval kStatus_SMARTCARD_NoTransmitInProgress No transmission is currently in progress. + */ +status_t SMARTCARD_EMVSIM_AbortTransfer(EMVSIM_Type *base, smartcard_context_t *context) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + context->abortTransfer = true; + + /* Check if a transfer is running. */ + if ((!context->xIsBusy)) + { + return kStatus_SMARTCARD_NoTransferInProgress; + } + /* Call transfer complete to abort transfer */ + if (kSMARTCARD_Receive == context->direction) + { /* Stop the running transfer. */ + smartcard_emvsim_CompleteReceiveData(base, context); + } + else if (kSMARTCARD_Transmit == context->direction) + { /* Stop the running transfer. */ + smartcard_emvsim_CompleteSendData(base, context); + } + else + { + return kStatus_SMARTCARD_InvalidInput; + } + + return kStatus_SMARTCARD_Success; +} + +/*! + * brief Handles EMVSIM module interrupts. + * + * param base The EMVSIM peripheral base address. + * param context A pointer to a smart card driver context structure. + */ +void SMARTCARD_EMVSIM_IRQHandler(EMVSIM_Type *base, smartcard_context_t *context) +{ + if (NULL == context) + { + return; + } + + /* Check card insertion/removal interrupt occurs, only EMVSIM DIRECT interface driver using enables this interrupt + * to occur */ + if (((base->PCSR & EMVSIM_PCSR_SPDIM_MASK) == 0u) && ((base->PCSR & EMVSIM_PCSR_SPDIF_MASK) != 0u)) + { + /* Clear card presence interrupt status */ + base->PCSR |= EMVSIM_PCSR_SPDIF_MASK; + /* Set PD signal edge behaviour */ + if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >> + EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnFallingEdge) && + ((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >> + EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow)) + { /* Set rising edge interrupt */ + base->PCSR |= EMVSIM_PCSR_SPDES_MASK; + } + if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >> + EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnRisingEdge) && + ((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >> + EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsHigh)) + { /* Set falling edge interrupt */ + base->PCSR &= ~EMVSIM_PCSR_SPDES_MASK; + } + /* Card presence(insertion)/removal detected */ + /* Invoke callback if there is one */ + if (NULL != context->interfaceCallback) + { + context->interfaceCallback(context, context->interfaceCallbackParam); + } + return; + } + /* Check if timer for initial character (TS) detection has expired */ + if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT0_IM_MASK) >> EMVSIM_INT_MASK_GPCNT0_IM_SHIFT == 0u) && + ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT0_TO_MASK) != 0u)) + { + /* Disable TS and ADT timers by clearing source clock to 0 */ + base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK); + context->timersState.initCharTimerExpired = true; + /* Disable and clear GPCNT interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK; + base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT0_TO_MASK; + /* Down counter trigger, and clear any pending counter status flag */ + base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + context->transferState = kSMARTCARD_IdleState; + /* Unblock the caller */ + smartcard_emvsim_CompleteReceiveData(base, context); + return; + } + /* Check if timer for ATR duration timer has expired */ + if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT1_IM_MASK) == 0u) && + ((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT1_TO_MASK) != 0u)) + { /* Disable clock counter by clearing source clock to 0 */ + base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK; + /* Disable and clear GPCNT interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK; + base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK; + context->timersState.adtExpired = true; + /* Unblock the caller */ + smartcard_emvsim_CompleteReceiveData(base, context); + return; + } + /* + * Check if a parity error was indicated. + * A parity error will cause transmission of NACK if ANACK bit is set in + * CTRL register and PEF bit will not be asserted. When ANACK is not set, + * PEF will be asserted. + */ + if ((base->RX_STATUS & EMVSIM_RX_STATUS_PEF_MASK) != 0u) + { + context->parityError = true; + /* Clear parity error indication */ + base->RX_STATUS = EMVSIM_RX_STATUS_PEF_MASK; + } + /* Check if transmit NACK generation threshold was reached */ + if ((base->TX_STATUS & EMVSIM_TX_STATUS_TNTE_MASK) != 0u) + { + context->txtCrossed = true; + /* Disable transmit NACK threshold interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_TNACK_IM_MASK; + /* Clear transmit NACK threshold error flag */ + base->TX_STATUS = EMVSIM_TX_STATUS_TNTE_MASK; + /* Unblock the caller */ + smartcard_emvsim_CompleteSendData(base, context); + return; + } + /* Check if receive NACK generation threshold was reached */ + if ((base->RX_STATUS & EMVSIM_RX_STATUS_RTE_MASK) != 0u) + { + context->rxtCrossed = true; + /* Clear receiver NACK threshold interrupt status */ + base->RX_STATUS = EMVSIM_RX_STATUS_RTE_MASK; + if (context->xIsBusy) + { /* Unblock the caller */ + smartcard_emvsim_CompleteReceiveData(base, context); + } + } + /* Check if a Character Wait Timer expired */ + if (((base->INT_MASK & EMVSIM_INT_MASK_CWT_ERR_IM_MASK) == 0u) && + ((base->RX_STATUS & EMVSIM_RX_STATUS_CWT_ERR_MASK) != 0u)) + { /* Disable Character Wait Timer interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK; + /* Reset the counter */ + base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK; + /* Clear interrupt status */ + base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK; + /* Enable CWT timer */ + base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; + context->transferState = kSMARTCARD_IdleState; + + if (kSMARTCARD_T0Transport == context->tType) + { /* Indicate WWT expired */ + context->timersState.wwtExpired = true; + } + else + { /* Indicate CWT expired */ + context->timersState.cwtExpired = true; + } + if (context->xIsBusy) + { /* Terminate and unblock any caller */ + smartcard_emvsim_CompleteReceiveData(base, context); + } + } + /* Check if a Block Wait Timer expired */ + if (((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u) && + ((base->RX_STATUS & EMVSIM_RX_STATUS_BWT_ERR_MASK) != 0u)) + { /* Disable Block Wait Timer interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK; + /* Clear interrupt status flag */ + base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK; + /* Clear error */ + base->RX_STATUS = EMVSIM_RX_STATUS_BWT_ERR_MASK; + /* Enable BWT timer */ + base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; + + if (kSMARTCARD_T0Transport == context->tType) + { /* Indicate WWT expired */ + context->timersState.wwtExpired = true; + } + else + { /* Indicate BWT expired */ + context->timersState.bwtExpired = true; + } + /* Check if Wait Time Extension(WTX) was requested */ + if (context->wtxRequested) + { /* Reset WTX to default */ + (void)SMARTCARD_EMVSIM_Control(base, context, kSMARTCARD_ResetWaitTimeMultiplier, 1u); + } + if (context->xIsBusy) + { /* Terminate and unblock any caller */ + smartcard_emvsim_CompleteReceiveData(base, context); + } + } + + /* RX_DATA IRQ */ + /* Used in T=1 after receive 1st byte - disable BWT and enable CWT interrupt */ + if (((base->INT_MASK & EMVSIM_INT_MASK_RX_DATA_IM_MASK) == 0u) && + ((base->RX_STATUS & EMVSIM_RX_STATUS_RX_DATA_MASK) != 0u)) + { + if ((context->tType == kSMARTCARD_T1Transport) && (context->xSize > 0u) && + ((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u)) + { + context->timersState.cwtExpired = false; + /* Clear CWT error flag */ + base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK; + /* Enable CWT */ + base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; + /* Only the 1st byte has been received, now time to disable BWT interrupt and enable CWT interrupt */ + base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK) | EMVSIM_INT_MASK_BWT_ERR_IM_MASK; + } + /* Disable interrupt when is received new byte */ + base->INT_MASK |= EMVSIM_INT_MASK_RX_DATA_IM_MASK; + } + + /* RDT IRQ - count of bytes in rx fifo reached the rx threshold value RX_THD[RDT] */ + if (((base->INT_MASK & EMVSIM_INT_MASK_RDT_IM_MASK) == 0u) && + ((base->RX_STATUS & EMVSIM_RX_STATUS_RDTF_MASK) != 0u)) + { + if (kSMARTCARD_WaitingForTSState == context->transferState) + { + /* Read byte */ + (void)(base->RX_BUF); + + if ((base->CTRL & EMVSIM_CTRL_ICM_MASK) != 0u) + { /* ICM mode still enabled, this is due to parity error */ + context->transferState = kSMARTCARD_InvalidTSDetecetedState; + } + else + { /* Received valid TS */ + context->transferState = kSMARTCARD_ReceivingState; + /* Get Data Convention form by reading IC bit of EMVSIM_CTRL register */ + context->cardParams.convention = + (smartcard_card_convention_t)(uint32_t)((base->CTRL & EMVSIM_CTRL_IC_MASK) >> EMVSIM_CTRL_IC_SHIFT); + } + if (kSMARTCARD_InvalidTSDetecetedState == context->transferState) + { /* Stop initial character (TS) detection timer, ADT timer and it's interrupt to occur */ + base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK); + base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK; + smartcard_emvsim_CompleteReceiveData(base, context); + } + if (kSMARTCARD_ReceivingState == context->transferState) + { /* Stop initial character (TS) detection timer and disable ATR duration timer to reset it */ + base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK); + /* Start ATR duration counter (restart GPCNT) */ + base->CLKCFG |= EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock); + /* Start ATR duration counter, Disable counter 0 interrupt and Enable counter 1 interrupt */ + base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_GPCNT1_IM_MASK) | EMVSIM_INT_MASK_GPCNT0_IM_MASK; + /* Complete receive transfer */ + smartcard_emvsim_CompleteReceiveData(base, context); + } + /* Return anyway */ + return; + } + + while (((base->RX_STATUS & EMVSIM_RX_STATUS_RX_CNT_MASK) != 0u) && ((context->xSize) > 0u)) + { + /* Get data and put into receive buffer */ + *context->xBuff = (uint8_t)(base->RX_BUF); + ++context->xBuff; + --context->xSize; + } + + /* Check if the last byte was received */ + if (context->xSize == 0u) + { + smartcard_emvsim_CompleteReceiveData(base, context); + } + else + { + /* If the count of remaining bytes to receive is less than depth of fifo, update the value of the receiver + * data threshold */ + if (context->xSize < context->rxFifoThreshold) + { + /* Set receiver data threshold value to count of remaining bytes */ + uint32_t rx_thd; + rx_thd = (base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK); + rx_thd |= context->xSize; + base->RX_THD = rx_thd; + } + } + } + + /* ETC IRQ - all data from fifo is transmitted */ + if (((base->INT_MASK & EMVSIM_INT_MASK_ETC_IM_MASK) == 0u) && + ((base->TX_STATUS & EMVSIM_TX_STATUS_ETCF_MASK) != 0u)) + { + smartcard_emvsim_CompleteSendData(base, context); + } + + /* TDT IRQ - tx fifo is empty */ + if (((base->INT_MASK & EMVSIM_INT_MASK_TDT_IM_MASK) == 0u) && + ((base->TX_STATUS & EMVSIM_TX_STATUS_TDTF_MASK) != 0u)) + { + if (context->xSize == 0u) + { + smartcard_emvsim_CompleteSendData(base, context); + } + + if (context->xSize == 1u) + { + /* Disable TDT interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK; + /* When the TX_GETU is not zero while sending last byte, the transmitter sends one byte more */ + base->TX_GETU = 0; + + /* Write data to fifo */ + base->TX_BUF = *(context->xBuff); + ++context->xBuff; + --context->xSize; + + /* Last byte was written to fifo - wait for ETC interrupt */ + /* Clear ETC flag and enable ETC interrupt */ + base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK; + base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK; + } + else + { + /* To fifo will be written 2 or more bytes */ + size_t getu_tail = (size_t)(base->TX_GETU > 0u); + while (((context->txFifoEntryCount - (uint8_t)((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) >> + EMVSIM_TX_STATUS_TX_CNT_SHIFT)) > 0u) && + (context->xSize > getu_tail)) + { + /* Write data to fifo */ + base->TX_BUF = *(context->xBuff); + ++context->xBuff; + --context->xSize; + } + + if (context->xSize == 0u) + { + /* Disable TDT interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK; + + /* Clear ETC flag and enable ETC interrupt */ + base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK; + base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK; + } + } + } + SDK_ISR_EXIT_BARRIER; +} + +/*! + * brief Controls the EMVSIM module per different user request. + * + * param base The EMVSIM peripheral base address. + * param context A pointer to a smart card driver context structure. + * param control Control type. + * param param Integer value of specific to control command. + * + * return kStatus_SMARTCARD_Success in success. + * return kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_EMVSIM_Control(EMVSIM_Type *base, + smartcard_context_t *context, + smartcard_control_t control, + uint32_t param) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + status_t status = kStatus_SMARTCARD_Success; + uint32_t temp32 = 0u; + + switch (control) + { + case kSMARTCARD_EnableADT: + /* Do nothing, ADT counter has been loaded and started after reset + * and during starting TS delay counter only. This is because, once + * TS counter has been triggered with RCV_EN down-up, we should not + * trigger again after TS is received(to avoid missing next character to + * TS. Rather, after TS is received, the ATR duration counter should just + * be restarted w/o re-triggering the counter. */ + break; + case kSMARTCARD_DisableADT: + base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; + /* Stop ADT specific counter and it's interrupt to occur */ + base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK; + base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK; + base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK; + break; + case kSMARTCARD_EnableGTV: + /* Enable GTV specific interrupt */ + base->INT_MASK &= ~EMVSIM_INT_MASK_BGT_ERR_IM_MASK; + break; + case kSMARTCARD_DisableGTV: + /* Disable GTV specific interrupt */ + base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK; + break; + case kSMARTCARD_ResetWWT: + /* Reset WWT Timer */ + base->CTRL &= ~(EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK); + base->CTRL |= (EMVSIM_CTRL_CWT_EN_MASK | EMVSIM_CTRL_BWT_EN_MASK); + break; + case kSMARTCARD_EnableWWT: + /* BGT must be masked */ + base->INT_MASK |= EMVSIM_INT_MASK_BGT_ERR_IM_MASK; + /* Enable WWT Timer interrupt to occur */ + base->INT_MASK &= (~EMVSIM_INT_MASK_CWT_ERR_IM_MASK & ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK); + break; + case kSMARTCARD_DisableWWT: + /* Disable WWT Timer interrupt to occur */ + base->INT_MASK |= (EMVSIM_INT_MASK_CWT_ERR_IM_MASK | EMVSIM_INT_MASK_BWT_ERR_IM_MASK); + break; + case kSMARTCARD_ResetCWT: + /* Reset CWT Timer */ + base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK; + base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; + break; + case kSMARTCARD_EnableCWT: + base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK; + /* Enable CWT Timer interrupt to occur */ + base->INT_MASK &= ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK; + break; + case kSMARTCARD_DisableCWT: + /* CWT counter is for receive mode only */ + base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK; + /* Disable CWT Timer interrupt to occur */ + base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK; + break; + case kSMARTCARD_ResetBWT: + /* Reset BWT Timer */ + base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK; + base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; + break; + case kSMARTCARD_EnableBWT: + base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; + /* Enable BWT Timer interrupt to occur */ + base->INT_MASK &= ~EMVSIM_INT_MASK_BWT_ERR_IM_MASK; + break; + case kSMARTCARD_DisableBWT: + /* Disable BWT Timer interrupt to occur */ + base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK; + break; + case kSMARTCARD_EnableInitDetect: + /* Clear all ISO7816 interrupt flags */ + base->RX_STATUS = 0xFFFFFFFFu; + /* Enable initial character detection : hardware method */ + context->transferState = kSMARTCARD_WaitingForTSState; + /* Enable initial character detection */ + base->CTRL |= EMVSIM_CTRL_ICM_MASK; + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + break; + case kSMARTCARD_EnableAnack: + /* Enable NACK-on-error interrupt to occur */ + base->CTRL |= EMVSIM_CTRL_ANACK_MASK; + break; + case kSMARTCARD_DisableAnack: + /* Disable NACK-on-error interrupt to occur */ + base->CTRL &= ~EMVSIM_CTRL_ANACK_MASK; + break; + case kSMARTCARD_ConfigureBaudrate: + /* Set default baudrate/ETU time based on EMV parameters and card clock */ + base->DIVISOR = (((uint32_t)context->cardParams.Fi / context->cardParams.currentD) & 0x1FFu); + break; + case kSMARTCARD_SetupATRMode: + /* Set in default ATR mode */ + smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupATRMode); + break; + case kSMARTCARD_SetupT0Mode: + /* Set transport protocol type to T=0 */ + smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupT0Mode); + break; + case kSMARTCARD_SetupT1Mode: + /* Set transport protocol type to T=1 */ + smartcard_emvsim_SetTransferType(base, context, kSMARTCARD_SetupT1Mode); + break; + case kSMARTCARD_EnableReceiverMode: + /* Enable receiver mode and switch to receive direction */ + base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + /* Set receiver threshold value to 1 */ + base->RX_THD = ((base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK) | 1u); + /* Enable RDT interrupt */ + base->INT_MASK &= ~EMVSIM_INT_MASK_RDT_IM_MASK; + break; + case kSMARTCARD_DisableReceiverMode: + /* Disable receiver */ + base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; + break; + case kSMARTCARD_EnableTransmitterMode: + /* Enable transmitter mode and switch to transmit direction */ + base->CTRL |= EMVSIM_CTRL_XMT_EN_MASK; + break; + case kSMARTCARD_DisableTransmitterMode: + /* Disable transmitter */ + base->CTRL &= ~EMVSIM_CTRL_XMT_EN_MASK; + break; + case kSMARTCARD_ResetWaitTimeMultiplier: + base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK; + /* Reset Wait Timer Multiplier + * EMV Formula : WTX x (11 + ((2^BWI + 1) x 960 x D)) */ + temp32 = ((uint8_t)param) * + (11u + ((((uint32_t)1u << context->cardParams.BWI) + 1u) * 960u * context->cardParams.currentD)); +#ifdef CARDSIM_EXTRADELAY_USED + temp32 += context->cardParams.currentD * 50; +#endif + base->BWT_VAL = temp32; + /* Set flag to SMARTCARD context accordingly */ + if (param > 1u) + { + context->wtxRequested = true; + } + else + { + context->wtxRequested = false; + } + base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK; + break; + default: + status = kStatus_SMARTCARD_InvalidInput; + break; + } + return status; +} diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h new file mode 100644 index 0000000000..397966bc02 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_emvsim.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SMARTCARD_EMVSIM_H_ +#define _FSL_SMARTCARD_EMVSIM_H_ + +#include "fsl_smartcard.h" + +/*! + * @addtogroup smartcard_emvsim_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief EMV RX NACK interrupt generation threshold */ +#define SMARTCARD_EMV_RX_NACK_THRESHOLD (5u) + +/*! @brief EMV TX NACK interrupt generation threshold */ +#define SMARTCARD_EMV_TX_NACK_THRESHOLD (5u) + +/*! @brief Smart card Word Wait Timer adjustment value */ +#define SMARTCARD_WWT_ADJUSTMENT (160u) + +/*! @brief Smart card Character Wait Timer adjustment value */ +#define SMARTCARD_CWT_ADJUSTMENT (3u) + +/*! @brief General Purpose Counter clock selections */ +typedef enum _emvsim_gpc_clock_select +{ + kEMVSIM_GPCClockDisable = 0u, /*!< Disabled */ + kEMVSIM_GPCCardClock = 1u, /*!< Card clock */ + kEMVSIM_GPCRxClock = 2u, /*!< Receive clock */ + kEMVSIM_GPCTxClock = 3u, /*!< Transmit ETU clock */ +} emvsim_gpc_clock_select_t; + +/*! @brief EMVSIM card presence detection edge control */ +typedef enum _presence_detect_edge +{ + kEMVSIM_DetectOnFallingEdge = 0u, /*!< Presence detected on the falling edge */ + kEMVSIM_DetectOnRisingEdge = 1u, /*!< Presence detected on the rising edge */ +} emvsim_presence_detect_edge_t; + +/*! @brief EMVSIM card presence detection status */ +typedef enum _presence_detect_status +{ + kEMVSIM_DetectPinIsLow = 0u, /*!< Presence detected pin is logic low */ + kEMVSIM_DetectPinIsHigh = 1u, /*!< Presence detected pin is logic high */ +} emvsim_presence_detect_status_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Smart card EMVSIM Driver + * @{ + */ + +/*! + * @brief Fills in the smartcard_card_params structure with default values according to the EMV 4.3 specification. + * + * @param cardParams The configuration structure of type smartcard_interface_config_t. + * Function fill in members: + * Fi = 372; + * Di = 1; + * currentD = 1; + * WI = 0x0A; + * GTN = 0x00; + * with default values. + */ +void SMARTCARD_EMVSIM_GetDefaultConfig(smartcard_card_params_t *cardParams); + +/*! + * @brief Initializes an EMVSIM peripheral for the Smart card/ISO-7816 operation. + * + * This function un-gates the EMVSIM clock, initializes the module to EMV default settings, + * configures the IRQ, enables the module-level interrupt to the core and, initializes the driver context. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to the smart card driver context structure. + * @param srcClock_Hz Smart card clock generation module source clock. + * + * @return An error code or kStatus_SMARTCARD_Success. + */ +status_t SMARTCARD_EMVSIM_Init(EMVSIM_Type *base, smartcard_context_t *context, uint32_t srcClock_Hz); + +/*! + * @brief This function disables the EMVSIM interrupts, disables the transmitter and receiver, + * flushes the FIFOs, and gates EMVSIM clock in SIM. + * + * @param base The EMVSIM module base address. + */ +void SMARTCARD_EMVSIM_Deinit(EMVSIM_Type *base); + +/*! + * @brief Returns whether the previous EMVSIM transfer has finished. + * + * When performing an async transfer, call this function to ascertain the context of the + * current transfer: in progress (or busy) or complete (success). If the + * transfer is still in progress, the user can obtain the number of words that have not been + * transferred. + * + * @param base The EMVSIM module base address. + * @param context A pointer to a smart card driver context structure. + * + * @return The number of bytes not transferred. + */ +int32_t SMARTCARD_EMVSIM_GetTransferRemainingBytes(EMVSIM_Type *base, smartcard_context_t *context); + +/*! + * @brief Terminates an asynchronous EMVSIM transfer early. + * + * During an async EMVSIM transfer, the user can terminate the transfer early + * if the transfer is still in progress. + * + * @param base The EMVSIM peripheral address. + * @param context A pointer to a smart card driver context structure. + * @retval kStatus_SMARTCARD_Success The transmit abort was successful. + * @retval kStatus_SMARTCARD_NoTransmitInProgress No transmission is currently in progress. + */ +status_t SMARTCARD_EMVSIM_AbortTransfer(EMVSIM_Type *base, smartcard_context_t *context); + +/*! + * @brief Transfer data using interrupts. + * + * A non-blocking (also known as asynchronous) function means that the function returns + * immediately after initiating the transfer function. The application has to get the + * transfer status to see when the transfer is complete. In other words, after calling the non-blocking + * (asynchronous) transfer function, the application must get the transfer status to check if the transmit + * is completed or not. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a smart card driver context structure. + * @param xfer A pointer to the smart card transfer structure where the linked buffers and sizes are stored. + * + * @return An error code or kStatus_SMARTCARD_Success. + */ +status_t SMARTCARD_EMVSIM_TransferNonBlocking(EMVSIM_Type *base, smartcard_context_t *context, smartcard_xfer_t *xfer); + +/*! + * @brief Controls the EMVSIM module per different user request. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a smart card driver context structure. + * @param control Control type. + * @param param Integer value of specific to control command. + * + * return kStatus_SMARTCARD_Success in success. + * return kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_EMVSIM_Control(EMVSIM_Type *base, + smartcard_context_t *context, + smartcard_control_t control, + uint32_t param); + +/*! + * @brief Handles EMVSIM module interrupts. + * + * @param base The EMVSIM peripheral base address. + * @param context A pointer to a smart card driver context structure. + */ +void SMARTCARD_EMVSIM_IRQHandler(EMVSIM_Type *base, smartcard_context_t *context); +/*@}*/ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_SMARTCARD_EMVSIM_H_*/ diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h new file mode 100644 index 0000000000..21408bef76 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_SMARTCARD_PHY_H_ +#define _FSL_SMARTCARD_PHY_H_ + +#include "fsl_smartcard.h" + +/*! + * @addtogroup smartcard_phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Smart card definition which specifies the adjustment number of clock cycles during which an ATR string has to + * be received. + */ +#define SMARTCARD_ATR_DURATION_ADJUSTMENT (360u) + +/*! @brief Smart card definition which specifies the adjustment number of clock cycles until an initial 'TS' character + * has to be + * received. */ +#define SMARTCARD_INIT_DELAY_CLOCK_CYCLES_ADJUSTMENT (4200u) + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Fills in the configuration structure with default values. + * + * @param config The Smart card user configuration structure which contains configuration structure of type + * smartcard_interface_config_t. + * Function fill in members: + * clockToResetDelay = 42000, + * vcc = kSmartcardVoltageClassB3_3V, + * with default values. + */ +void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config); + +/*! + * @brief Initializes a Smart card interface instance. + * + * @param base The Smart card peripheral base address. + * @param config The user configuration structure of type smartcard_interface_config_t. Call the + * function SMARTCARD_PHY_GetDefaultConfig() to fill the configuration structure. + * @param srcClock_Hz Smart card clock generation module source clock. + * + * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_PHY_Init(void *base, smartcard_interface_config_t const *config, uint32_t srcClock_Hz); + +/*! + * @brief De-initializes a Smart card interface, stops the Smart card clock, and disables the VCC. + * + * @param base The Smart card peripheral module base address. + * @param config The user configuration structure of type smartcard_interface_config_t. + */ +void SMARTCARD_PHY_Deinit(void *base, smartcard_interface_config_t const *config); + +/*! + * @brief Activates the Smart card IC. + * + * @param base The Smart card peripheral module base address. + * @param context A pointer to a Smart card driver context structure. + * @param resetType type of reset to be performed, possible values + * = kSmartcardColdReset, kSmartcardWarmReset + * + * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_PHY_Activate(void *base, smartcard_context_t *context, smartcard_reset_type_t resetType); + +/*! + * @brief De-activates the Smart card IC. + * + * @param base The Smart card peripheral module base address. + * @param context A pointer to a Smart card driver context structure. + * + * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_PHY_Deactivate(void *base, smartcard_context_t *context); + +/*! + * @brief Controls the Smart card interface IC. + * + * @param base The Smart card peripheral module base address. + * @param context A pointer to a Smart card driver context structure. + * @param control A interface command type. + * @param param Integer value specific to control type + * + * @retval kStatus_SMARTCARD_Success or kStatus_SMARTCARD_OtherError in case of error. + */ +status_t SMARTCARD_PHY_Control(void *base, + smartcard_context_t *context, + smartcard_interface_control_t control, + uint32_t param); + +/*! + * @brief Smart card interface IC IRQ ISR. + * + * @param base The Smart card peripheral module base address. + * @param context The Smart card context pointer. + */ +#if defined(USING_PHY_TDA8035) +void SMARTCARD_PHY_IRQHandler(void *base, smartcard_context_t *context); +#endif +/*@}*/ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_SMARTCARD_PHY_H_*/ diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c new file mode 100644 index 0000000000..1be83f8101 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/smartcard/fsl_smartcard_phy_emvsim.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_smartcard_emvsim.h" +#include "fsl_smartcard_phy.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.smartcard_phy_emvsim" +#endif + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Private Functions + ******************************************************************************/ +static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base, + const smartcard_interface_config_t *config, + uint32_t srcClock_Hz); + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief This function initializes clock module used for card clock generation + */ +static uint32_t smartcard_phy_emvsim_InterfaceClockInit(EMVSIM_Type *base, + const smartcard_interface_config_t *config, + uint32_t srcClock_Hz) +{ + assert((NULL != config) && (0u != srcClock_Hz)); + + uint32_t emvsimClkMhz = 0u; + uint8_t emvsimPRSCValue; + + /* Retrieve EMV SIM clock */ + emvsimClkMhz = srcClock_Hz / 1000000u; + /* Calculate MOD value */ + emvsimPRSCValue = (uint8_t)((emvsimClkMhz * 1000u) / (config->smartCardClock / 1000u)); + /* Set clock prescaler */ + base->CLKCFG = (base->CLKCFG & ~EMVSIM_CLKCFG_CLK_PRSC_MASK) | EMVSIM_CLKCFG_CLK_PRSC(emvsimPRSCValue); + + return config->smartCardClock; +} + +void SMARTCARD_PHY_GetDefaultConfig(smartcard_interface_config_t *config) +{ + assert((NULL != config)); + + /* Initializes the configure structure to zero. */ + (void)memset(config, 0, sizeof(*config)); + + config->clockToResetDelay = SMARTCARD_INIT_DELAY_CLOCK_CYCLES; + config->vcc = kSMARTCARD_VoltageClassB3_3V; +} + +status_t SMARTCARD_PHY_Init(void *base, smartcard_interface_config_t const *config, uint32_t srcClock_Hz) +{ + if ((NULL == config) || (0u == srcClock_Hz)) + { + return kStatus_SMARTCARD_InvalidInput; + } + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + /* SMARTCARD clock initialization. Clock is still not active after this call */ + (void)smartcard_phy_emvsim_InterfaceClockInit(emvsimBase, config, srcClock_Hz); + + /* Configure EMVSIM direct interface driver interrupt occur according card presence */ + if ((emvsimBase->PCSR & EMVSIM_PCSR_SPDP_MASK) != 0u) + { + emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDES_MASK; + } + else + { + emvsimBase->PCSR |= EMVSIM_PCSR_SPDES_MASK; + } + /* Un-mask presence detect interrupt flag */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SPDIM_MASK; + + return kStatus_SMARTCARD_Success; +} + +void SMARTCARD_PHY_Deinit(void *base, smartcard_interface_config_t const *config) +{ + assert((NULL != config)); + /* Deactivate VCC, CLOCK */ + ((EMVSIM_Type *)base)->PCSR &= ~(EMVSIM_PCSR_SCEN_MASK | EMVSIM_PCSR_SVCC_EN_MASK); +} + +status_t SMARTCARD_PHY_Activate(void *base, smartcard_context_t *context, smartcard_reset_type_t resetType) +{ + if ((NULL == context) || (NULL == context->timeDelay)) + { + return kStatus_SMARTCARD_InvalidInput; + } + assert(context->interfaceConfig.vcc == kSMARTCARD_VoltageClassB3_3V); + + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + context->timersState.initCharTimerExpired = false; + context->resetType = resetType; + + /* Disable receiver to deactivate GPC timers trigger */ + emvsimBase->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK; + if (resetType == kSMARTCARD_ColdReset) + { /* Set polarity of VCC to active high, Enable VCC for SMARTCARD, Enable smart card clock */ + emvsimBase->PCSR = + (emvsimBase->PCSR & ~EMVSIM_PCSR_VCCENP_MASK) | (EMVSIM_PCSR_SVCC_EN_MASK | EMVSIM_PCSR_SCEN_MASK); + /* Set transfer inversion to default(direct) value */ + emvsimBase->CTRL &= ~EMVSIM_CTRL_IC_MASK; + } + else if (resetType == kSMARTCARD_WarmReset) + { /* Ensure that card is already active */ + if (!context->cardParams.active) + { /* Card is not active;hence return */ + return kStatus_SMARTCARD_CardNotActivated; + } + } + else + { + return kStatus_SMARTCARD_InvalidInput; + } + /* Set Reset low */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK; + /* Calculate time delay needed for reset */ + uint32_t temp = + ((((uint32_t)10000u * context->interfaceConfig.clockToResetDelay) / context->interfaceConfig.smartCardClock) * + 100u) + + 1u; + context->timeDelay(temp); + /* Pull reset HIGH Now to mark the end of Activation sequence */ + emvsimBase->PCSR |= EMVSIM_PCSR_SRST_MASK; + /* Disable GPC timers input clock */ + emvsimBase->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK); + /* Down counter trigger, and clear any pending counter status flag */ + emvsimBase->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK | EMVSIM_TX_STATUS_GPCNT0_TO_MASK; + /* Set counter value for TS detection delay */ + emvsimBase->GPCNT0_VAL = (SMARTCARD_INIT_DELAY_CLOCK_CYCLES + SMARTCARD_INIT_DELAY_CLOCK_CYCLES_ADJUSTMENT); + /* Pre-load counter value for ATR duration delay */ + emvsimBase->GPCNT1_VAL = (SMARTCARD_EMV_ATR_DURATION_ETU + SMARTCARD_ATR_DURATION_ADJUSTMENT); + /* Select the clock for GPCNT for both TS detection and early start of ATR duration counter */ + emvsimBase->CLKCFG |= + (EMVSIM_CLKCFG_GPCNT0_CLK_SEL(kEMVSIM_GPCCardClock) | EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock)); + /* Set receiver to ICM mode, Flush RX FIFO */ + emvsimBase->CTRL |= (EMVSIM_CTRL_ICM_MASK | EMVSIM_CTRL_FLSH_RX_MASK); + /* Enable counter interrupt for TS detection */ + emvsimBase->INT_MASK &= ~EMVSIM_INT_MASK_GPCNT0_IM_MASK; + /* Clear any pending status flags */ + emvsimBase->RX_STATUS = 0xFFFFFFFFu; + /* Enable receiver */ + emvsimBase->CTRL |= EMVSIM_CTRL_RCV_EN_MASK; + /* Here the card was activated */ + context->cardParams.active = true; + + return kStatus_SMARTCARD_Success; +} + +status_t SMARTCARD_PHY_Deactivate(void *base, smartcard_context_t *context) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + EMVSIM_Type *emvsimBase = (EMVSIM_Type *)base; + + /* Assert Reset */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SRST_MASK; + /* Stop SMARTCARD clock generation */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SCEN_MASK; + /* Deactivate card by disabling VCC */ + emvsimBase->PCSR &= ~EMVSIM_PCSR_SVCC_EN_MASK; + /* According EMV 4.3 specification deactivation sequence should be done within 100ms. + * The period is measured from the time that RST is set to state L to the time that Vcc + * reaches 0.4 V or less. + */ + context->timeDelay(100 * 1000); + /* Here the card was deactivated */ + context->cardParams.active = false; + + return kStatus_SMARTCARD_Success; +} + +status_t SMARTCARD_PHY_Control(void *base, + smartcard_context_t *context, + smartcard_interface_control_t control, + uint32_t param) +{ + if ((NULL == context)) + { + return kStatus_SMARTCARD_InvalidInput; + } + + status_t status = kStatus_SMARTCARD_Success; + + switch (control) + { + case kSMARTCARD_InterfaceSetVcc: + /* Only 3.3V interface supported by the direct interface */ + assert((smartcard_card_voltage_class_t)param == kSMARTCARD_VoltageClassB3_3V); + context->interfaceConfig.vcc = (smartcard_card_voltage_class_t)param; + break; + case kSMARTCARD_InterfaceSetClockToResetDelay: + /* Set interface clock to Reset delay set by caller */ + context->interfaceConfig.clockToResetDelay = param; + break; + case kSMARTCARD_InterfaceReadStatus: + /* Expecting active low present detect */ + context->cardParams.present = (bool)((emvsim_presence_detect_status_t)(uint32_t)( + (((EMVSIM_Type *)base)->PCSR & EMVSIM_PCSR_SPDP_MASK) >> + EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow); + break; + default: + status = kStatus_SMARTCARD_InvalidInput; + break; + } + + return status; +} |