xref: /arm-trusted-firmware/drivers/nxp/crypto/caam/src/sec_jr_driver.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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