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