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