1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright 2021 NXP 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <stdbool.h> 10*91f16700Schasinglulu #include <stdint.h> 11*91f16700Schasinglulu #include <stdio.h> 12*91f16700Schasinglulu #include <stdlib.h> 13*91f16700Schasinglulu #include <string.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include <arch_helpers.h> 16*91f16700Schasinglulu #include "caam.h" 17*91f16700Schasinglulu #include <common/debug.h> 18*91f16700Schasinglulu #include "jobdesc.h" 19*91f16700Schasinglulu #include "nxp_timer.h" 20*91f16700Schasinglulu #include "sec_hw_specific.h" 21*91f16700Schasinglulu #include "sec_jr_driver.h" 22*91f16700Schasinglulu 23*91f16700Schasinglulu 24*91f16700Schasinglulu /* Job rings used for communication with SEC HW */ 25*91f16700Schasinglulu struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS]; 26*91f16700Schasinglulu 27*91f16700Schasinglulu /* The current state of SEC user space driver */ 28*91f16700Schasinglulu volatile sec_driver_state_t g_driver_state = SEC_DRIVER_STATE_IDLE; 29*91f16700Schasinglulu 30*91f16700Schasinglulu int g_job_rings_no; 31*91f16700Schasinglulu 32*91f16700Schasinglulu uint8_t ip_ring[SEC_DMA_MEM_INPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE); 33*91f16700Schasinglulu uint8_t op_ring[SEC_DMA_MEM_OUTPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE); 34*91f16700Schasinglulu 35*91f16700Schasinglulu void *init_job_ring(uint8_t jr_mode, 36*91f16700Schasinglulu uint16_t irq_coalescing_timer, 37*91f16700Schasinglulu uint8_t irq_coalescing_count, 38*91f16700Schasinglulu void *reg_base_addr, uint32_t irq_id) 39*91f16700Schasinglulu { 40*91f16700Schasinglulu struct sec_job_ring_t *job_ring = &g_job_rings[g_job_rings_no++]; 41*91f16700Schasinglulu int ret = 0; 42*91f16700Schasinglulu 43*91f16700Schasinglulu job_ring->register_base_addr = reg_base_addr; 44*91f16700Schasinglulu job_ring->jr_mode = jr_mode; 45*91f16700Schasinglulu job_ring->irq_fd = irq_id; 46*91f16700Schasinglulu 47*91f16700Schasinglulu job_ring->input_ring = vtop(ip_ring); 48*91f16700Schasinglulu memset(job_ring->input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE); 49*91f16700Schasinglulu 50*91f16700Schasinglulu job_ring->output_ring = (struct sec_outring_entry *)vtop(op_ring); 51*91f16700Schasinglulu memset(job_ring->output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE); 52*91f16700Schasinglulu 53*91f16700Schasinglulu dsb(); 54*91f16700Schasinglulu 55*91f16700Schasinglulu #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) 56*91f16700Schasinglulu flush_dcache_range((uintptr_t)(job_ring->input_ring), 57*91f16700Schasinglulu SEC_DMA_MEM_INPUT_RING_SIZE), 58*91f16700Schasinglulu flush_dcache_range((uintptr_t)(job_ring->output_ring), 59*91f16700Schasinglulu SEC_DMA_MEM_OUTPUT_RING_SIZE), 60*91f16700Schasinglulu 61*91f16700Schasinglulu dmbsy(); 62*91f16700Schasinglulu #endif 63*91f16700Schasinglulu /* Reset job ring in SEC hw and configure job ring registers */ 64*91f16700Schasinglulu ret = hw_reset_job_ring(job_ring); 65*91f16700Schasinglulu if (ret != 0) { 66*91f16700Schasinglulu ERROR("Failed to reset hardware job ring\n"); 67*91f16700Schasinglulu return NULL; 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) { 71*91f16700Schasinglulu /* Enable IRQ if driver work sin interrupt mode */ 72*91f16700Schasinglulu ERROR("Enabling DONE IRQ generation on job ring\n"); 73*91f16700Schasinglulu ret = jr_enable_irqs(job_ring); 74*91f16700Schasinglulu if (ret != 0) { 75*91f16700Schasinglulu ERROR("Failed to enable irqs for job ring\n"); 76*91f16700Schasinglulu return NULL; 77*91f16700Schasinglulu } 78*91f16700Schasinglulu } 79*91f16700Schasinglulu if ((irq_coalescing_timer != 0) || (irq_coalescing_count != 0)) { 80*91f16700Schasinglulu hw_job_ring_set_coalescing_param(job_ring, 81*91f16700Schasinglulu irq_coalescing_timer, 82*91f16700Schasinglulu irq_coalescing_count); 83*91f16700Schasinglulu 84*91f16700Schasinglulu hw_job_ring_enable_coalescing(job_ring); 85*91f16700Schasinglulu job_ring->coalescing_en = 1; 86*91f16700Schasinglulu } 87*91f16700Schasinglulu 88*91f16700Schasinglulu job_ring->jr_state = SEC_JOB_RING_STATE_STARTED; 89*91f16700Schasinglulu 90*91f16700Schasinglulu return job_ring; 91*91f16700Schasinglulu } 92*91f16700Schasinglulu 93*91f16700Schasinglulu int sec_release(void) 94*91f16700Schasinglulu { 95*91f16700Schasinglulu int i; 96*91f16700Schasinglulu 97*91f16700Schasinglulu /* Validate driver state */ 98*91f16700Schasinglulu if (g_driver_state == SEC_DRIVER_STATE_RELEASE) { 99*91f16700Schasinglulu ERROR("Driver release is already in progress"); 100*91f16700Schasinglulu return SEC_DRIVER_RELEASE_IN_PROGRESS; 101*91f16700Schasinglulu } 102*91f16700Schasinglulu /* Update driver state */ 103*91f16700Schasinglulu g_driver_state = SEC_DRIVER_STATE_RELEASE; 104*91f16700Schasinglulu 105*91f16700Schasinglulu /* If any descriptors in flight , poll and wait 106*91f16700Schasinglulu * until all descriptors are received and silently discarded. 107*91f16700Schasinglulu */ 108*91f16700Schasinglulu 109*91f16700Schasinglulu flush_job_rings(); 110*91f16700Schasinglulu 111*91f16700Schasinglulu for (i = 0; i < g_job_rings_no; i++) { 112*91f16700Schasinglulu shutdown_job_ring(&g_job_rings[i]); 113*91f16700Schasinglulu } 114*91f16700Schasinglulu g_job_rings_no = 0; 115*91f16700Schasinglulu g_driver_state = SEC_DRIVER_STATE_IDLE; 116*91f16700Schasinglulu 117*91f16700Schasinglulu return SEC_SUCCESS; 118*91f16700Schasinglulu } 119*91f16700Schasinglulu 120*91f16700Schasinglulu int sec_jr_lib_init(void) 121*91f16700Schasinglulu { 122*91f16700Schasinglulu /* Validate driver state */ 123*91f16700Schasinglulu if (g_driver_state != SEC_DRIVER_STATE_IDLE) { 124*91f16700Schasinglulu ERROR("Driver already initialized\n"); 125*91f16700Schasinglulu return 0; 126*91f16700Schasinglulu } 127*91f16700Schasinglulu 128*91f16700Schasinglulu memset(g_job_rings, 0, sizeof(g_job_rings)); 129*91f16700Schasinglulu g_job_rings_no = 0; 130*91f16700Schasinglulu 131*91f16700Schasinglulu /* Update driver state */ 132*91f16700Schasinglulu g_driver_state = SEC_DRIVER_STATE_STARTED; 133*91f16700Schasinglulu return 0; 134*91f16700Schasinglulu } 135*91f16700Schasinglulu 136*91f16700Schasinglulu int dequeue_jr(void *job_ring_handle, int32_t limit) 137*91f16700Schasinglulu { 138*91f16700Schasinglulu int ret = 0; 139*91f16700Schasinglulu int notified_descs_no = 0; 140*91f16700Schasinglulu struct sec_job_ring_t *job_ring = (sec_job_ring_t *) job_ring_handle; 141*91f16700Schasinglulu uint64_t start_time; 142*91f16700Schasinglulu 143*91f16700Schasinglulu /* Validate driver state */ 144*91f16700Schasinglulu if (g_driver_state != SEC_DRIVER_STATE_STARTED) { 145*91f16700Schasinglulu ERROR("Driver release in progress or driver not initialized\n"); 146*91f16700Schasinglulu return -1; 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu /* Validate input arguments */ 150*91f16700Schasinglulu if (job_ring == NULL) { 151*91f16700Schasinglulu ERROR("job_ring_handle is NULL\n"); 152*91f16700Schasinglulu return -1; 153*91f16700Schasinglulu } 154*91f16700Schasinglulu if (((limit == 0) || (limit > SEC_JOB_RING_SIZE))) { 155*91f16700Schasinglulu ERROR("Invalid limit parameter configuration\n"); 156*91f16700Schasinglulu return -1; 157*91f16700Schasinglulu } 158*91f16700Schasinglulu 159*91f16700Schasinglulu VERBOSE("JR Polling limit[%d]\n", limit); 160*91f16700Schasinglulu 161*91f16700Schasinglulu /* Poll job ring 162*91f16700Schasinglulu * If limit < 0 -> poll JR until no more notifications are available. 163*91f16700Schasinglulu * If limit > 0 -> poll JR until limit is reached. 164*91f16700Schasinglulu */ 165*91f16700Schasinglulu 166*91f16700Schasinglulu start_time = get_timer_val(0); 167*91f16700Schasinglulu 168*91f16700Schasinglulu while (notified_descs_no == 0) { 169*91f16700Schasinglulu /* Run hw poll job ring */ 170*91f16700Schasinglulu notified_descs_no = hw_poll_job_ring(job_ring, limit); 171*91f16700Schasinglulu if (notified_descs_no < 0) { 172*91f16700Schasinglulu ERROR("Error polling SEC engine job ring "); 173*91f16700Schasinglulu return notified_descs_no; 174*91f16700Schasinglulu } 175*91f16700Schasinglulu VERBOSE("Jobs notified[%d]. ", notified_descs_no); 176*91f16700Schasinglulu 177*91f16700Schasinglulu if (get_timer_val(start_time) >= CAAM_TIMEOUT) { 178*91f16700Schasinglulu break; 179*91f16700Schasinglulu } 180*91f16700Schasinglulu } 181*91f16700Schasinglulu 182*91f16700Schasinglulu if (job_ring->jr_mode == SEC_NOTIFICATION_TYPE_IRQ) { 183*91f16700Schasinglulu 184*91f16700Schasinglulu /* Always enable IRQ generation when in pure IRQ mode */ 185*91f16700Schasinglulu ret = jr_enable_irqs(job_ring); 186*91f16700Schasinglulu if (ret != 0) { 187*91f16700Schasinglulu ERROR("Failed to enable irqs for job ring"); 188*91f16700Schasinglulu return ret; 189*91f16700Schasinglulu } 190*91f16700Schasinglulu } 191*91f16700Schasinglulu return notified_descs_no; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu 194*91f16700Schasinglulu int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr) 195*91f16700Schasinglulu { 196*91f16700Schasinglulu struct sec_job_ring_t *job_ring; 197*91f16700Schasinglulu 198*91f16700Schasinglulu job_ring = (struct sec_job_ring_t *)job_ring_handle; 199*91f16700Schasinglulu 200*91f16700Schasinglulu /* Validate driver state */ 201*91f16700Schasinglulu if (g_driver_state != SEC_DRIVER_STATE_STARTED) { 202*91f16700Schasinglulu ERROR("Driver release in progress or driver not initialized\n"); 203*91f16700Schasinglulu return -1; 204*91f16700Schasinglulu } 205*91f16700Schasinglulu 206*91f16700Schasinglulu /* Check job ring state */ 207*91f16700Schasinglulu if (job_ring->jr_state != SEC_JOB_RING_STATE_STARTED) { 208*91f16700Schasinglulu ERROR("Job ring is currently resetting\n"); 209*91f16700Schasinglulu return -1; 210*91f16700Schasinglulu } 211*91f16700Schasinglulu 212*91f16700Schasinglulu if (SEC_JOB_RING_IS_FULL(job_ring->pidx, job_ring->cidx, 213*91f16700Schasinglulu SEC_JOB_RING_SIZE, SEC_JOB_RING_SIZE)) { 214*91f16700Schasinglulu ERROR("Job ring is full\n"); 215*91f16700Schasinglulu return -1; 216*91f16700Schasinglulu } 217*91f16700Schasinglulu 218*91f16700Schasinglulu /* Set ptr in input ring to current descriptor */ 219*91f16700Schasinglulu sec_write_addr(&job_ring->input_ring[job_ring->pidx], 220*91f16700Schasinglulu (phys_addr_t) vtop(jobdescr->desc)); 221*91f16700Schasinglulu 222*91f16700Schasinglulu dsb(); 223*91f16700Schasinglulu 224*91f16700Schasinglulu #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) 225*91f16700Schasinglulu flush_dcache_range((uintptr_t)(&job_ring->input_ring[job_ring->pidx]), 226*91f16700Schasinglulu sizeof(phys_addr_t)); 227*91f16700Schasinglulu 228*91f16700Schasinglulu inv_dcache_range((uintptr_t)(&job_ring->output_ring[job_ring->cidx]), 229*91f16700Schasinglulu sizeof(struct sec_outring_entry)); 230*91f16700Schasinglulu dmbsy(); 231*91f16700Schasinglulu #endif 232*91f16700Schasinglulu /* Notify HW that a new job is enqueued */ 233*91f16700Schasinglulu hw_enqueue_desc_on_job_ring( 234*91f16700Schasinglulu (struct jobring_regs *)job_ring->register_base_addr, 1); 235*91f16700Schasinglulu 236*91f16700Schasinglulu /* increment the producer index for the current job ring */ 237*91f16700Schasinglulu job_ring->pidx = SEC_CIRCULAR_COUNTER(job_ring->pidx, 238*91f16700Schasinglulu SEC_JOB_RING_SIZE); 239*91f16700Schasinglulu 240*91f16700Schasinglulu return 0; 241*91f16700Schasinglulu } 242