/* * Copyright 2017-2021 NXP * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef _SEC_HW_SPECIFIC_H_ #define _SEC_HW_SPECIFIC_H_ #include "caam.h" #include "sec_jr_driver.h" /* DEFINES AND MACROS */ /* Used to retry resetting a job ring in SEC hardware. */ #define SEC_TIMEOUT 100000 /* * Offset to the registers of a job ring. *Is different for each job ring. */ #define CHAN_BASE(jr) ((phys_addr_t)(jr)->register_base_addr) #define unlikely(x) __builtin_expect(!!(x), 0) #define SEC_JOB_RING_IS_FULL(pi, ci, ring_max_size, ring_threshold) \ ((((pi) + 1 + ((ring_max_size) - (ring_threshold))) & \ (ring_max_size - 1)) == ((ci))) #define SEC_CIRCULAR_COUNTER(x, max) (((x) + 1) & (max - 1)) /* Struct representing various job ring registers */ struct jobring_regs { #ifdef NXP_SEC_BE unsigned int irba_h; unsigned int irba_l; #else unsigned int irba_l; unsigned int irba_h; #endif unsigned int rsvd1; unsigned int irs; unsigned int rsvd2; unsigned int irsa; unsigned int rsvd3; unsigned int irja; #ifdef NXP_SEC_BE unsigned int orba_h; unsigned int orba_l; #else unsigned int orba_l; unsigned int orba_h; #endif unsigned int rsvd4; unsigned int ors; unsigned int rsvd5; unsigned int orjr; unsigned int rsvd6; unsigned int orsf; unsigned int rsvd7; unsigned int jrsta; unsigned int rsvd8; unsigned int jrint; unsigned int jrcfg0; unsigned int jrcfg1; unsigned int rsvd9; unsigned int irri; unsigned int rsvd10; unsigned int orwi; unsigned int rsvd11; unsigned int jrcr; }; /* Offsets representing common SEC Registers */ #define SEC_REG_MCFGR_OFFSET 0x0004 #define SEC_REG_SCFGR_OFFSET 0x000C #define SEC_REG_JR0ICIDR_MS_OFFSET 0x0010 #define SEC_REG_JR0ICIDR_LS_OFFSET 0x0014 #define SEC_REG_JR1ICIDR_MS_OFFSET 0x0018 #define SEC_REG_JR1ICIDR_LS_OFFSET 0x001C #define SEC_REG_JR2ICIDR_MS_OFFSET 0x0020 #define SEC_REG_JR2ICIDR_LS_OFFSET 0x0024 #define SEC_REG_JR3ICIDR_MS_OFFSET 0x0028 #define SEC_REG_JR3ICIDR_LS_OFFSET 0x002C #define SEC_REG_JRSTARTR_OFFSET 0x005C #define SEC_REG_CTPR_MS_OFFSET 0x0FA8 /* Offsets representing various RNG registers */ #define RNG_REG_RTMCTL_OFFSET 0x0600 #define RNG_REG_RTSDCTL_OFFSET 0x0610 #define RNG_REG_RTFRQMIN_OFFSET 0x0618 #define RNG_REG_RTFRQMAX_OFFSET 0x061C #define RNG_REG_RDSTA_OFFSET 0x06C0 #define ALG_AAI_SH_SHIFT 4 /* SEC Registers Bitmasks */ #define MCFGR_PS_SHIFT 16 #define MCFGR_AWCACHE_SHIFT 8 #define MCFGR_AWCACHE_MASK (0xF << MCFGR_AWCACHE_SHIFT) #define MCFGR_ARCACHE_SHIFT 12 #define MCFGR_ARCACHE_MASK (0xF << MCFGR_ARCACHE_SHIFT) #define SCFGR_RNGSH0 0x00000200 #define SCFGR_VIRT_EN 0x00008000 #define JRICID_MS_LICID 0x80000000 #define JRICID_MS_LAMTD 0x00020000 #define JRICID_MS_AMTDT 0x00010000 #define JRICID_MS_TZ 0x00008000 #define JRICID_LS_SDID_MASK 0x00000FFF #define JRICID_LS_NSEQID_MASK 0x0FFF0000 #define JRICID_LS_NSEQID_SHIFT 16 #define JRICID_LS_SEQID_MASK 0x00000FFF #define JRSTARTR_STARTJR0 0x00000001 #define JRSTARTR_STARTJR1 0x00000002 #define JRSTARTR_STARTJR2 0x00000004 #define JRSTARTR_STARTJR3 0x00000008 #define CTPR_VIRT_EN_POR 0x00000002 #define CTPR_VIRT_EN_INC 0x00000001 /* RNG RDSTA bitmask */ #define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001 #define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ /* use von Neumann data in both entropy shifter and statistical checker */ #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0 /* use raw data in both entropy shifter and statistical checker */ #define RTMCTL_SAMP_MODE_RAW_ES_SC 1 /* use von Neumann data in entropy shifter, raw data in statistical checker */ #define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2 /* invalid combination */ #define RTMCTL_SAMP_MODE_INVALID 3 #define RTSDCTL_ENT_DLY_MIN 3200 #define RTSDCTL_ENT_DLY_MAX 12800 #define RTSDCTL_ENT_DLY_SHIFT 16 #define RTSDCTL_ENT_DLY_MASK (U(0xffff) << RTSDCTL_ENT_DLY_SHIFT) #define RTFRQMAX_DISABLE (1 << 20) /* Constants for error handling on job ring */ #define JR_REG_JRINT_ERR_TYPE_SHIFT 8 #define JR_REG_JRINT_ERR_ORWI_SHIFT 16 #define JR_REG_JRINIT_JRE_SHIFT 1 #define JRINT_JRE (1 << JR_REG_JRINIT_JRE_SHIFT) #define JRINT_ERR_WRITE_STATUS (1 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_BAD_INPUT_BASE (3 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_BAD_OUTPUT_BASE (4 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_WRITE_2_IRBA (5 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_WRITE_2_ORBA (6 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_RES_B4_HALT (7 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_REM_TOO_MANY (8 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_ADD_TOO_MANY (9 << JR_REG_JRINT_ERR_TYPE_SHIFT) #define JRINT_ERR_HALT_MASK 0x0C #define JRINT_ERR_HALT_INPROGRESS 0x04 #define JRINT_ERR_HALT_COMPLETE 0x08 #define JR_REG_JRCR_VAL_RESET 0x00000001 #define JR_REG_JRCFG_LO_ICTT_SHIFT 0x10 #define JR_REG_JRCFG_LO_ICDCT_SHIFT 0x08 #define JR_REG_JRCFG_LO_ICEN_EN 0x02 #define JR_REG_JRCFG_LO_IMSK_EN 0x01 /* Constants for Descriptor Processing errors */ #define SEC_HW_ERR_SSRC_NO_SRC 0x00 #define SEC_HW_ERR_SSRC_CCB_ERR 0x02 #define SEC_HW_ERR_SSRC_JMP_HALT_U 0x03 #define SEC_HW_ERR_SSRC_DECO 0x04 #define SEC_HW_ERR_SSRC_JR 0x06 #define SEC_HW_ERR_SSRC_JMP_HALT_COND 0x07 #define SEC_HW_ERR_DECO_HFN_THRESHOLD 0xF1 #define SEC_HW_ERR_CCB_ICV_CHECK_FAIL 0x0A /* Macros for extracting error codes for the job ring */ #define JR_REG_JRINT_ERR_TYPE_EXTRACT(value) \ ((value) & 0x00000F00) #define JR_REG_JRINT_ERR_ORWI_EXTRACT(value) \ (((value) & 0x3FFF0000) >> \ JR_REG_JRINT_ERR_ORWI_SHIFT) #define JR_REG_JRINT_JRE_EXTRACT(value) \ ((value) & JRINT_JRE) /* Macros for manipulating JR registers */ typedef struct { #ifdef NXP_SEC_BE uint32_t high; uint32_t low; #else uint32_t low; uint32_t high; #endif } ptr_addr_t; #if defined(CONFIG_PHYS_64BIT) #define sec_read_addr(a) sec_in64((a)) #define sec_write_addr(a, v) sec_out64((a), (v)) #else #define sec_read_addr(a) sec_in32((a)) #define sec_write_addr(a, v) sec_out32((a), (v)) #endif #define JR_REG(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET) #define JR_REG_LO(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET_LO) #define GET_JR_REG(name, jr) (sec_in32(JR_REG(name, (jr)))) #define GET_JR_REG_LO(name, jr) (sec_in32(JR_REG_LO(name, (jr)))) #define SET_JR_REG(name, jr, val) \ (sec_out32(JR_REG(name, (jr)), (val))) #define SET_JR_REG_LO(name, jr, val) \ (sec_out32(JR_REG_LO(name, (jr)), (val))) /* STRUCTURES AND OTHER TYPEDEFS */ /* Lists the possible states for a job ring. */ typedef enum sec_job_ring_state_e { SEC_JOB_RING_STATE_STARTED, /* Job ring is initialized */ SEC_JOB_RING_STATE_RESET, /* Job ring reset is in progres */ } sec_job_ring_state_t; struct sec_job_ring_t { /* * Consumer index for job ring (jobs array). * @note: cidx and pidx are accessed from * different threads. * Place the cidx and pidx inside the structure * so that they lay on different cachelines, to * avoid false sharing between threads when the * threads run on different cores! */ uint32_t cidx; /* Producer index for job ring (jobs array) */ uint32_t pidx; /* Ring of input descriptors. Size of array is power of 2 to allow * fast update of producer/consumer indexes with bitwise operations. */ phys_addr_t *input_ring; /* Ring of output descriptors. */ struct sec_outring_entry *output_ring; /* The file descriptor used for polling for interrupts notifications */ uint32_t irq_fd; /* Model used by SEC Driver to receive notifications from SEC. * Can be either of the three: * #SEC_NOTIFICATION_TYPE_IRQ or * #SEC_NOTIFICATION_TYPE_POLL */ uint32_t jr_mode; /* Base address for SEC's register memory for this job ring. */ void *register_base_addr; /* notifies if coelescing is enabled for the job ring */ uint8_t coalescing_en; /* The state of this job ring */ sec_job_ring_state_t jr_state; }; /* Forward structure declaration */ typedef struct sec_job_ring_t sec_job_ring_t; struct sec_outring_entry { phys_addr_t desc; /* Pointer to completed descriptor */ uint32_t status; /* Status for completed descriptor */ } __packed; /* Lists the states possible for the SEC user space driver. */ typedef enum sec_driver_state_e { SEC_DRIVER_STATE_IDLE, /*< Driver not initialized */ SEC_DRIVER_STATE_STARTED, /*< Driver initialized and */ SEC_DRIVER_STATE_RELEASE, /*< Driver release is in progress */ } sec_driver_state_t; /* Union describing the possible error codes that */ /* can be set in the descriptor status word */ union hw_error_code { uint32_t error; union { struct { uint32_t ssrc:4; uint32_t ssed_val:28; } __packed value; struct { uint32_t ssrc:4; uint32_t res:28; } __packed no_status_src; struct { uint32_t ssrc:4; uint32_t jmp:1; uint32_t res:11; uint32_t desc_idx:8; uint32_t cha_id:4; uint32_t err_id:4; } __packed ccb_status_src; struct { uint32_t ssrc:4; uint32_t jmp:1; uint32_t res:11; uint32_t desc_idx:8; uint32_t offset:8; } __packed jmp_halt_user_src; struct { uint32_t ssrc:4; uint32_t jmp:1; uint32_t res:11; uint32_t desc_idx:8; uint32_t desc_err:8; } __packed deco_src; struct { uint32_t ssrc:4; uint32_t res:17; uint32_t naddr:3; uint32_t desc_err:8; } __packed jr_src; struct { uint32_t ssrc:4; uint32_t jmp:1; uint32_t res:11; uint32_t desc_idx:8; uint32_t cond:8; } __packed jmp_halt_cond_src; } __packed error_desc; } __packed; /* FUNCTION PROTOTYPES */ /* * @brief Initialize a job ring/channel in SEC device. * Write configuration register/s to properly initialize a job ring. * * @param [in] job_ring The job ring * * @retval 0 for success * @retval other for error */ int hw_reset_job_ring(sec_job_ring_t *job_ring); /* * @brief Reset a job ring/channel in SEC device. * Write configuration register/s to reset a job ring. * * @param [in] job_ring The job ring * * @retval 0 for success * @retval -1 in case job ring reset failed */ int hw_shutdown_job_ring(sec_job_ring_t *job_ring); /* * @brief Handle a job ring/channel error in SEC device. * Identify the error type and clear error bits if required. * * @param [in] job_ring The job ring * @param [in] sec_error_code error code as first read from SEC engine */ void hw_handle_job_ring_error(sec_job_ring_t *job_ring, uint32_t sec_error_code); /* * @brief Handle a job ring error in the device. * Identify the error type and printout a explanatory * messages. * * @param [in] job_ring The job ring * */ int hw_job_ring_error(sec_job_ring_t *job_ring); /* @brief Set interrupt coalescing parameters on the Job Ring. * @param [in] job_ring The job ring * @param [in] irq_coalesing_timer * Interrupt coalescing timer threshold. * This value determines the maximum * amount of time after processing a descriptor * before raising an interrupt. * @param [in] irq_coalescing_count * Interrupt coalescing count threshold. * This value determines how many descriptors * are completed before raising an interrupt. */ int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring, uint16_t irq_coalescing_timer, uint8_t irq_coalescing_count); /* @brief Enable interrupt coalescing on a job ring * @param [in] job_ring The job ring */ int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring); /* * @brief Disable interrupt coalescing on a job ring * @param [in] job_ring The job ring */ int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring); /* * @brief Poll the HW for already processed jobs in the JR * and notify the available jobs to UA. * * @param [in] job_ring The job ring to poll. * @param [in] limit The maximum number of jobs to notify. * If set to negative value, all available * jobs are notified. * * @retval >=0 for No of jobs notified to UA. * @retval -1 for error */ int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit); /* @brief Poll the HW for already processed jobs in the JR * and silently discard the available jobs or notify them to UA * with indicated error code. * @param [in,out] job_ring The job ring to poll. * @param [in] do_notify Can be #TRUE or #FALSE. * Indicates if descriptors to be discarded * or notified to UA with given error_code. * @param [in] error_code The detailed SEC error code. * @param [out] notified_descs Number of notified descriptors. * Can be NULL if do_notify is #FALSE */ void hw_flush_job_ring(struct sec_job_ring_t *job_ring, uint32_t do_notify, uint32_t error_code, uint32_t *notified_descs); /* * @brief Flush job rings of any processed descs. * The processed descs are silently dropped, * WITHOUT being notified to UA. */ void flush_job_rings(void); /* * @brief Handle desc that generated error in SEC engine. * Identify the exact type of error and handle the error. * Depending on the error type, the job ring could be reset. * All descs that are submitted for processing on this job ring * are notified to User Application with error status and detailed error code. * @param [in] job_ring Job ring * @param [in] sec_error_code Error code read from job ring's Channel * Status Register * @param [out] notified_descs Number of notified descs. Can be NULL if * do_notify is #FALSE * @param [out] do_driver_shutdown If set to #TRUE, then UA is returned code * #SEC_PROCESSING_ERROR * which is indication that UA must call * sec_release() after this. */ void sec_handle_desc_error(struct sec_job_ring_t *job_ring, uint32_t sec_error_code, uint32_t *notified_descs, uint32_t *do_driver_shutdown); /* * @brief Release the software and hardware resources tied to a job ring. * @param [in] job_ring The job ring * @retval 0 for success * @retval -1 for error */ int shutdown_job_ring(struct sec_job_ring_t *job_ring); /* * @brief Enable irqs on associated job ring. * @param [in] job_ring The job ring * @retval 0 for success * @retval -1 for error */ int jr_enable_irqs(struct sec_job_ring_t *job_ring); /* * @brief Disable irqs on associated job ring. * @param [in] job_ring The job ring * @retval 0 for success * @retval -1 for error */ int jr_disable_irqs(struct sec_job_ring_t *job_ring); /* * IRJA - Input Ring Jobs Added Register shows * how many new jobs were added to the Input Ring. */ static inline void hw_enqueue_desc_on_job_ring(struct jobring_regs *regs, int num) { sec_out32(®s->irja, num); } #endif /* _SEC_HW_SPECIFIC_H_ */