xref: /arm-trusted-firmware/drivers/nxp/crypto/caam/src/sec_hw_specific.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 <assert.h>
9*91f16700Schasinglulu #include <errno.h>
10*91f16700Schasinglulu #include <stdbool.h>
11*91f16700Schasinglulu #include <stdint.h>
12*91f16700Schasinglulu #include <stdio.h>
13*91f16700Schasinglulu #include <stdlib.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 "sec_hw_specific.h"
20*91f16700Schasinglulu 
21*91f16700Schasinglulu 
22*91f16700Schasinglulu /* Job rings used for communication with SEC HW */
23*91f16700Schasinglulu extern struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
24*91f16700Schasinglulu 
25*91f16700Schasinglulu /* The current state of SEC user space driver */
26*91f16700Schasinglulu extern volatile sec_driver_state_t g_driver_state;
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /* The number of job rings used by SEC user space driver */
29*91f16700Schasinglulu extern int g_job_rings_no;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu /* LOCAL FUNCTIONS */
32*91f16700Schasinglulu static inline void hw_set_input_ring_start_addr(struct jobring_regs *regs,
33*91f16700Schasinglulu 						phys_addr_t *start_addr)
34*91f16700Schasinglulu {
35*91f16700Schasinglulu #if defined(CONFIG_PHYS_64BIT)
36*91f16700Schasinglulu 	sec_out32(&regs->irba_h, PHYS_ADDR_HI(start_addr));
37*91f16700Schasinglulu #else
38*91f16700Schasinglulu 	sec_out32(&regs->irba_h, 0);
39*91f16700Schasinglulu #endif
40*91f16700Schasinglulu 	sec_out32(&regs->irba_l, PHYS_ADDR_LO(start_addr));
41*91f16700Schasinglulu }
42*91f16700Schasinglulu 
43*91f16700Schasinglulu static inline void hw_set_output_ring_start_addr(struct jobring_regs *regs,
44*91f16700Schasinglulu 						 phys_addr_t *start_addr)
45*91f16700Schasinglulu {
46*91f16700Schasinglulu #if defined(CONFIG_PHYS_64BIT)
47*91f16700Schasinglulu 	sec_out32(&regs->orba_h, PHYS_ADDR_HI(start_addr));
48*91f16700Schasinglulu #else
49*91f16700Schasinglulu 	sec_out32(&regs->orba_h, 0);
50*91f16700Schasinglulu #endif
51*91f16700Schasinglulu 	sec_out32(&regs->orba_l, PHYS_ADDR_LO(start_addr));
52*91f16700Schasinglulu }
53*91f16700Schasinglulu 
54*91f16700Schasinglulu /* ORJR - Output Ring Jobs Removed Register shows how many jobs were
55*91f16700Schasinglulu  * removed from the Output Ring for processing by software. This is done after
56*91f16700Schasinglulu  * the software has processed the entries.
57*91f16700Schasinglulu  */
58*91f16700Schasinglulu static inline void hw_remove_entries(sec_job_ring_t *jr, int num)
59*91f16700Schasinglulu {
60*91f16700Schasinglulu 	struct jobring_regs *regs =
61*91f16700Schasinglulu 	    (struct jobring_regs *)jr->register_base_addr;
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	sec_out32(&regs->orjr, num);
64*91f16700Schasinglulu }
65*91f16700Schasinglulu 
66*91f16700Schasinglulu /* IRSA - Input Ring Slots Available register holds the number of entries in
67*91f16700Schasinglulu  * the Job Ring's input ring. Once a job is enqueued, the value returned is
68*91f16700Schasinglulu  * decremented by the hardware by the number of jobs enqueued.
69*91f16700Schasinglulu  */
70*91f16700Schasinglulu static inline int hw_get_available_slots(sec_job_ring_t *jr)
71*91f16700Schasinglulu {
72*91f16700Schasinglulu 	struct jobring_regs *regs =
73*91f16700Schasinglulu 	    (struct jobring_regs *)jr->register_base_addr;
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	return sec_in32(&regs->irsa);
76*91f16700Schasinglulu }
77*91f16700Schasinglulu 
78*91f16700Schasinglulu /* ORSFR - Output Ring Slots Full register holds the number of jobs which were
79*91f16700Schasinglulu  * processed by the SEC and can be retrieved by the software. Once a job has
80*91f16700Schasinglulu  * been processed by software, the user will call hw_remove_one_entry in order
81*91f16700Schasinglulu  * to notify the SEC that the entry was processed
82*91f16700Schasinglulu  */
83*91f16700Schasinglulu static inline int hw_get_no_finished_jobs(sec_job_ring_t *jr)
84*91f16700Schasinglulu {
85*91f16700Schasinglulu 	struct jobring_regs *regs =
86*91f16700Schasinglulu 	    (struct jobring_regs *)jr->register_base_addr;
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	return sec_in32(&regs->orsf);
89*91f16700Schasinglulu }
90*91f16700Schasinglulu 
91*91f16700Schasinglulu /* @brief Process Jump Halt Condition related errors
92*91f16700Schasinglulu  * @param [in]  error_code The error code in the descriptor status word
93*91f16700Schasinglulu  */
94*91f16700Schasinglulu static inline void hw_handle_jmp_halt_cond_err(union hw_error_code error_code)
95*91f16700Schasinglulu {
96*91f16700Schasinglulu 	ERROR("JMP %x\n", error_code.error_desc.jmp_halt_cond_src.jmp);
97*91f16700Schasinglulu 	ERROR("Descriptor Index: %d\n",
98*91f16700Schasinglulu 	      error_code.error_desc.jmp_halt_cond_src.desc_idx);
99*91f16700Schasinglulu 	ERROR(" Condition %x\n", error_code.error_desc.jmp_halt_cond_src.cond);
100*91f16700Schasinglulu }
101*91f16700Schasinglulu 
102*91f16700Schasinglulu /* @brief Process DECO related errors
103*91f16700Schasinglulu  * @param [in]  error_code      The error code in the descriptor status word
104*91f16700Schasinglulu  */
105*91f16700Schasinglulu static inline void hw_handle_deco_err(union hw_error_code error_code)
106*91f16700Schasinglulu {
107*91f16700Schasinglulu 	ERROR("JMP %x\n", error_code.error_desc.deco_src.jmp);
108*91f16700Schasinglulu 	ERROR("Descriptor Index: 0x%x",
109*91f16700Schasinglulu 	      error_code.error_desc.deco_src.desc_idx);
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	switch (error_code.error_desc.deco_src.desc_err) {
112*91f16700Schasinglulu 	case SEC_HW_ERR_DECO_HFN_THRESHOLD:
113*91f16700Schasinglulu 		WARN(" Descriptor completed but exceeds the Threshold");
114*91f16700Schasinglulu 		break;
115*91f16700Schasinglulu 	default:
116*91f16700Schasinglulu 		ERROR("Error 0x%04x not implemented",
117*91f16700Schasinglulu 		      error_code.error_desc.deco_src.desc_err);
118*91f16700Schasinglulu 		break;
119*91f16700Schasinglulu 	}
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu /* @brief Process  Jump Halt User Status related errors
123*91f16700Schasinglulu  * @param [in]  error_code      The error code in the descriptor status word
124*91f16700Schasinglulu  */
125*91f16700Schasinglulu static inline void hw_handle_jmp_halt_user_err(union hw_error_code error_code)
126*91f16700Schasinglulu {
127*91f16700Schasinglulu 	WARN(" Not implemented");
128*91f16700Schasinglulu }
129*91f16700Schasinglulu 
130*91f16700Schasinglulu /* @brief Process CCB related errors
131*91f16700Schasinglulu  * @param [in]  error_code      The error code in the descriptor status word
132*91f16700Schasinglulu  */
133*91f16700Schasinglulu static inline void hw_handle_ccb_err(union hw_error_code hw_error_code)
134*91f16700Schasinglulu {
135*91f16700Schasinglulu 	WARN(" Not implemented");
136*91f16700Schasinglulu }
137*91f16700Schasinglulu 
138*91f16700Schasinglulu /* @brief Process Job Ring related errors
139*91f16700Schasinglulu  * @param [in]  error_code      The error code in the descriptor status word
140*91f16700Schasinglulu  */
141*91f16700Schasinglulu static inline void hw_handle_jr_err(union hw_error_code hw_error_code)
142*91f16700Schasinglulu {
143*91f16700Schasinglulu 	WARN(" Not implemented");
144*91f16700Schasinglulu }
145*91f16700Schasinglulu 
146*91f16700Schasinglulu /* GLOBAL FUNCTIONS */
147*91f16700Schasinglulu 
148*91f16700Schasinglulu int hw_reset_job_ring(sec_job_ring_t *job_ring)
149*91f16700Schasinglulu {
150*91f16700Schasinglulu 	int ret = 0;
151*91f16700Schasinglulu 	struct jobring_regs *regs =
152*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	/* First reset the job ring in hw */
155*91f16700Schasinglulu 	ret = hw_shutdown_job_ring(job_ring);
156*91f16700Schasinglulu 	if (ret != 0) {
157*91f16700Schasinglulu 		ERROR("Failed resetting job ring in hardware");
158*91f16700Schasinglulu 		return ret;
159*91f16700Schasinglulu 	}
160*91f16700Schasinglulu 	/* In order to have the HW JR in a workable state
161*91f16700Schasinglulu 	 *after a reset, I need to re-write the input
162*91f16700Schasinglulu 	 * queue size, input start address, output queue
163*91f16700Schasinglulu 	 * size and output start address
164*91f16700Schasinglulu 	 * Write the JR input queue size to the HW register
165*91f16700Schasinglulu 	 */
166*91f16700Schasinglulu 	sec_out32(&regs->irs, SEC_JOB_RING_SIZE);
167*91f16700Schasinglulu 
168*91f16700Schasinglulu 	/* Write the JR output queue size to the HW register */
169*91f16700Schasinglulu 	sec_out32(&regs->ors, SEC_JOB_RING_SIZE);
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	/* Write the JR input queue start address */
172*91f16700Schasinglulu 	hw_set_input_ring_start_addr(regs, vtop(job_ring->input_ring));
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	/* Write the JR output queue start address */
175*91f16700Schasinglulu 	hw_set_output_ring_start_addr(regs, vtop(job_ring->output_ring));
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	return 0;
178*91f16700Schasinglulu }
179*91f16700Schasinglulu 
180*91f16700Schasinglulu int hw_shutdown_job_ring(sec_job_ring_t *job_ring)
181*91f16700Schasinglulu {
182*91f16700Schasinglulu 	struct jobring_regs *regs =
183*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
184*91f16700Schasinglulu 	unsigned int timeout = SEC_TIMEOUT;
185*91f16700Schasinglulu 	uint32_t tmp = 0U;
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	VERBOSE("Resetting Job ring\n");
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	/*
190*91f16700Schasinglulu 	 * Mask interrupts since we are going to poll
191*91f16700Schasinglulu 	 * for reset completion status
192*91f16700Schasinglulu 	 * Also, at POR, interrupts are ENABLED on a JR, thus
193*91f16700Schasinglulu 	 * this is the point where I can disable them without
194*91f16700Schasinglulu 	 * changing the code logic too much
195*91f16700Schasinglulu 	 */
196*91f16700Schasinglulu 
197*91f16700Schasinglulu 	jr_disable_irqs(job_ring);
198*91f16700Schasinglulu 
199*91f16700Schasinglulu 	/* initiate flush (required prior to reset) */
200*91f16700Schasinglulu 	sec_out32(&regs->jrcr, JR_REG_JRCR_VAL_RESET);
201*91f16700Schasinglulu 
202*91f16700Schasinglulu 	/* dummy read */
203*91f16700Schasinglulu 	tmp = sec_in32(&regs->jrcr);
204*91f16700Schasinglulu 
205*91f16700Schasinglulu 	do {
206*91f16700Schasinglulu 		tmp = sec_in32(&regs->jrint);
207*91f16700Schasinglulu 	} while (((tmp & JRINT_ERR_HALT_MASK) ==
208*91f16700Schasinglulu 		  JRINT_ERR_HALT_INPROGRESS) && ((--timeout) != 0U));
209*91f16700Schasinglulu 
210*91f16700Schasinglulu 	if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE ||
211*91f16700Schasinglulu 	    timeout == 0U) {
212*91f16700Schasinglulu 		ERROR("Failed to flush hw job ring %x\n %u", tmp, timeout);
213*91f16700Schasinglulu 		/* unmask interrupts */
214*91f16700Schasinglulu 		if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
215*91f16700Schasinglulu 			jr_enable_irqs(job_ring);
216*91f16700Schasinglulu 		}
217*91f16700Schasinglulu 		return -1;
218*91f16700Schasinglulu 	}
219*91f16700Schasinglulu 	/* Initiate reset */
220*91f16700Schasinglulu 	timeout = SEC_TIMEOUT;
221*91f16700Schasinglulu 	sec_out32(&regs->jrcr, JR_REG_JRCR_VAL_RESET);
222*91f16700Schasinglulu 
223*91f16700Schasinglulu 	do {
224*91f16700Schasinglulu 		tmp = sec_in32(&regs->jrcr);
225*91f16700Schasinglulu 	} while (((tmp & JR_REG_JRCR_VAL_RESET) != 0U) &&
226*91f16700Schasinglulu 		 ((--timeout) != 0U));
227*91f16700Schasinglulu 
228*91f16700Schasinglulu 	if (timeout == 0U) {
229*91f16700Schasinglulu 		ERROR("Failed to reset hw job ring\n");
230*91f16700Schasinglulu 		/* unmask interrupts */
231*91f16700Schasinglulu 		if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
232*91f16700Schasinglulu 			jr_enable_irqs(job_ring);
233*91f16700Schasinglulu 		}
234*91f16700Schasinglulu 		return -1;
235*91f16700Schasinglulu 	}
236*91f16700Schasinglulu 	/* unmask interrupts */
237*91f16700Schasinglulu 	if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
238*91f16700Schasinglulu 		jr_enable_irqs(job_ring);
239*91f16700Schasinglulu 	}
240*91f16700Schasinglulu 	return 0;
241*91f16700Schasinglulu 
242*91f16700Schasinglulu }
243*91f16700Schasinglulu 
244*91f16700Schasinglulu void hw_handle_job_ring_error(sec_job_ring_t *job_ring, uint32_t error_code)
245*91f16700Schasinglulu {
246*91f16700Schasinglulu 	union hw_error_code hw_err_code;
247*91f16700Schasinglulu 
248*91f16700Schasinglulu 	hw_err_code.error = error_code;
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	switch (hw_err_code.error_desc.value.ssrc) {
251*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_NO_SRC:
252*91f16700Schasinglulu 		INFO("No Status Source ");
253*91f16700Schasinglulu 		break;
254*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_CCB_ERR:
255*91f16700Schasinglulu 		INFO("CCB Status Source");
256*91f16700Schasinglulu 		hw_handle_ccb_err(hw_err_code);
257*91f16700Schasinglulu 		break;
258*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_JMP_HALT_U:
259*91f16700Schasinglulu 		INFO("Jump Halt User Status Source");
260*91f16700Schasinglulu 		hw_handle_jmp_halt_user_err(hw_err_code);
261*91f16700Schasinglulu 		break;
262*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_DECO:
263*91f16700Schasinglulu 		INFO("DECO Status Source");
264*91f16700Schasinglulu 		hw_handle_deco_err(hw_err_code);
265*91f16700Schasinglulu 		break;
266*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_JR:
267*91f16700Schasinglulu 		INFO("Job Ring Status Source");
268*91f16700Schasinglulu 		hw_handle_jr_err(hw_err_code);
269*91f16700Schasinglulu 		break;
270*91f16700Schasinglulu 	case SEC_HW_ERR_SSRC_JMP_HALT_COND:
271*91f16700Schasinglulu 		INFO("Jump Halt Condition Codes");
272*91f16700Schasinglulu 		hw_handle_jmp_halt_cond_err(hw_err_code);
273*91f16700Schasinglulu 		break;
274*91f16700Schasinglulu 	default:
275*91f16700Schasinglulu 		INFO("Unknown SSRC");
276*91f16700Schasinglulu 		break;
277*91f16700Schasinglulu 	}
278*91f16700Schasinglulu }
279*91f16700Schasinglulu 
280*91f16700Schasinglulu int hw_job_ring_error(sec_job_ring_t *job_ring)
281*91f16700Schasinglulu {
282*91f16700Schasinglulu 	uint32_t jrint_error_code;
283*91f16700Schasinglulu 	struct jobring_regs *regs =
284*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 	if (JR_REG_JRINT_JRE_EXTRACT(sec_in32(&regs->jrint)) == 0) {
287*91f16700Schasinglulu 		return 0;
288*91f16700Schasinglulu 	}
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 	jrint_error_code =
291*91f16700Schasinglulu 	    JR_REG_JRINT_ERR_TYPE_EXTRACT(sec_in32(&regs->jrint));
292*91f16700Schasinglulu 	switch (jrint_error_code) {
293*91f16700Schasinglulu 	case JRINT_ERR_WRITE_STATUS:
294*91f16700Schasinglulu 		ERROR("Error writing status to Output Ring ");
295*91f16700Schasinglulu 		break;
296*91f16700Schasinglulu 	case JRINT_ERR_BAD_INPUT_BASE:
297*91f16700Schasinglulu 		ERROR("Bad Input Ring Base (not on a 4-byte boundary)\n");
298*91f16700Schasinglulu 		break;
299*91f16700Schasinglulu 	case JRINT_ERR_BAD_OUTPUT_BASE:
300*91f16700Schasinglulu 		ERROR("Bad Output Ring Base (not on a 4-byte boundary)\n");
301*91f16700Schasinglulu 		break;
302*91f16700Schasinglulu 	case JRINT_ERR_WRITE_2_IRBA:
303*91f16700Schasinglulu 		ERROR("Invalid write to Input Ring Base Address Register\n");
304*91f16700Schasinglulu 		break;
305*91f16700Schasinglulu 	case JRINT_ERR_WRITE_2_ORBA:
306*91f16700Schasinglulu 		ERROR("Invalid write to Output Ring Base Address Register\n");
307*91f16700Schasinglulu 		break;
308*91f16700Schasinglulu 	case JRINT_ERR_RES_B4_HALT:
309*91f16700Schasinglulu 		ERROR("Job Ring released before Job Ring is halted\n");
310*91f16700Schasinglulu 		break;
311*91f16700Schasinglulu 	case JRINT_ERR_REM_TOO_MANY:
312*91f16700Schasinglulu 		ERROR("Removed too many jobs from job ring\n");
313*91f16700Schasinglulu 		break;
314*91f16700Schasinglulu 	case JRINT_ERR_ADD_TOO_MANY:
315*91f16700Schasinglulu 		ERROR("Added too many jobs on job ring\n");
316*91f16700Schasinglulu 		break;
317*91f16700Schasinglulu 	default:
318*91f16700Schasinglulu 		ERROR("Unknown SEC JR Error :%d\n", jrint_error_code);
319*91f16700Schasinglulu 		break;
320*91f16700Schasinglulu 	}
321*91f16700Schasinglulu 	return jrint_error_code;
322*91f16700Schasinglulu }
323*91f16700Schasinglulu 
324*91f16700Schasinglulu int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
325*91f16700Schasinglulu 				     uint16_t irq_coalescing_timer,
326*91f16700Schasinglulu 				     uint8_t irq_coalescing_count)
327*91f16700Schasinglulu {
328*91f16700Schasinglulu 	uint32_t reg_val = 0U;
329*91f16700Schasinglulu 	struct jobring_regs *regs =
330*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
331*91f16700Schasinglulu 
332*91f16700Schasinglulu 	/* Set descriptor count coalescing */
333*91f16700Schasinglulu 	reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT);
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	/* Set coalescing timer value */
336*91f16700Schasinglulu 	reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT);
337*91f16700Schasinglulu 
338*91f16700Schasinglulu 	/* Update parameters in HW */
339*91f16700Schasinglulu 	sec_out32(&regs->jrcfg1, reg_val);
340*91f16700Schasinglulu 
341*91f16700Schasinglulu 	VERBOSE("Set coalescing params on jr\n");
342*91f16700Schasinglulu 
343*91f16700Schasinglulu 	return 0;
344*91f16700Schasinglulu }
345*91f16700Schasinglulu 
346*91f16700Schasinglulu int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring)
347*91f16700Schasinglulu {
348*91f16700Schasinglulu 	uint32_t reg_val = 0U;
349*91f16700Schasinglulu 	struct jobring_regs *regs =
350*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
351*91f16700Schasinglulu 
352*91f16700Schasinglulu 	/* Get the current value of the register */
353*91f16700Schasinglulu 	reg_val = sec_in32(&regs->jrcfg1);
354*91f16700Schasinglulu 
355*91f16700Schasinglulu 	/* Enable coalescing */
356*91f16700Schasinglulu 	reg_val |= JR_REG_JRCFG_LO_ICEN_EN;
357*91f16700Schasinglulu 
358*91f16700Schasinglulu 	/* Write in hw */
359*91f16700Schasinglulu 	sec_out32(&regs->jrcfg1, reg_val);
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	VERBOSE("Enabled coalescing on jr\n");
362*91f16700Schasinglulu 
363*91f16700Schasinglulu 	return 0;
364*91f16700Schasinglulu }
365*91f16700Schasinglulu 
366*91f16700Schasinglulu int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring)
367*91f16700Schasinglulu {
368*91f16700Schasinglulu 	uint32_t reg_val = 0U;
369*91f16700Schasinglulu 	struct jobring_regs *regs =
370*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	/* Get the current value of the register */
373*91f16700Schasinglulu 	reg_val = sec_in32(&regs->jrcfg1);
374*91f16700Schasinglulu 
375*91f16700Schasinglulu 	/* Disable coalescing */
376*91f16700Schasinglulu 	reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN;
377*91f16700Schasinglulu 
378*91f16700Schasinglulu 	/* Write in hw */
379*91f16700Schasinglulu 	sec_out32(&regs->jrcfg1, reg_val);
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 	VERBOSE("Disabled coalescing on jr");
382*91f16700Schasinglulu 
383*91f16700Schasinglulu 	return 0;
384*91f16700Schasinglulu 
385*91f16700Schasinglulu }
386*91f16700Schasinglulu 
387*91f16700Schasinglulu void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
388*91f16700Schasinglulu 		       uint32_t do_notify,
389*91f16700Schasinglulu 		       uint32_t error_code, uint32_t *notified_descs)
390*91f16700Schasinglulu {
391*91f16700Schasinglulu 	int32_t jobs_no_to_discard = 0;
392*91f16700Schasinglulu 	int32_t discarded_descs_no = 0;
393*91f16700Schasinglulu 	int32_t number_of_jobs_available = 0;
394*91f16700Schasinglulu 
395*91f16700Schasinglulu 	VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
396*91f16700Schasinglulu 	VERBOSE("error code %x\n", error_code);
397*91f16700Schasinglulu 	VERBOSE("Notify_desc = %d\n", do_notify);
398*91f16700Schasinglulu 
399*91f16700Schasinglulu 	number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 	/* Discard all jobs */
402*91f16700Schasinglulu 	jobs_no_to_discard = number_of_jobs_available;
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 	VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
405*91f16700Schasinglulu 	VERBOSE("Discarding desc = %d\n", jobs_no_to_discard);
406*91f16700Schasinglulu 
407*91f16700Schasinglulu 	while (jobs_no_to_discard > discarded_descs_no) {
408*91f16700Schasinglulu 		discarded_descs_no++;
409*91f16700Schasinglulu 		/* Now increment the consumer index for the current job ring,
410*91f16700Schasinglulu 		 * AFTER saving job in temporary location!
411*91f16700Schasinglulu 		 * Increment the consumer index for the current job ring
412*91f16700Schasinglulu 		 */
413*91f16700Schasinglulu 
414*91f16700Schasinglulu 		job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
415*91f16700Schasinglulu 						      SEC_JOB_RING_SIZE);
416*91f16700Schasinglulu 
417*91f16700Schasinglulu 		hw_remove_entries(job_ring, 1);
418*91f16700Schasinglulu 	}
419*91f16700Schasinglulu 
420*91f16700Schasinglulu 	if (do_notify == true) {
421*91f16700Schasinglulu 		if (notified_descs == NULL) {
422*91f16700Schasinglulu 			return;
423*91f16700Schasinglulu 		}
424*91f16700Schasinglulu 		*notified_descs = discarded_descs_no;
425*91f16700Schasinglulu 	}
426*91f16700Schasinglulu }
427*91f16700Schasinglulu 
428*91f16700Schasinglulu /* return >0 in case of success
429*91f16700Schasinglulu  *  -1 in case of error from SEC block
430*91f16700Schasinglulu  *  0 in case job not yet processed by SEC
431*91f16700Schasinglulu  *   or  Descriptor returned is NULL after dequeue
432*91f16700Schasinglulu  */
433*91f16700Schasinglulu int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit)
434*91f16700Schasinglulu {
435*91f16700Schasinglulu 	int32_t jobs_no_to_notify = 0;
436*91f16700Schasinglulu 	int32_t number_of_jobs_available = 0;
437*91f16700Schasinglulu 	int32_t notified_descs_no = 0;
438*91f16700Schasinglulu 	uint32_t error_descs_no = 0U;
439*91f16700Schasinglulu 	uint32_t sec_error_code = 0U;
440*91f16700Schasinglulu 	uint32_t do_driver_shutdown = false;
441*91f16700Schasinglulu 	phys_addr_t *fnptr, *arg_addr;
442*91f16700Schasinglulu 	user_callback usercall = NULL;
443*91f16700Schasinglulu 	uint8_t *current_desc;
444*91f16700Schasinglulu 	void *arg;
445*91f16700Schasinglulu 	uintptr_t current_desc_addr;
446*91f16700Schasinglulu 	phys_addr_t current_desc_loc;
447*91f16700Schasinglulu 
448*91f16700Schasinglulu #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
449*91f16700Schasinglulu 	inv_dcache_range((uintptr_t)job_ring->register_base_addr, sizeof(struct jobring_regs));
450*91f16700Schasinglulu 	dmbsy();
451*91f16700Schasinglulu #endif
452*91f16700Schasinglulu 
453*91f16700Schasinglulu 	/* check here if any JR error that cannot be written
454*91f16700Schasinglulu 	 * in the output status word has occurred
455*91f16700Schasinglulu 	 */
456*91f16700Schasinglulu 	sec_error_code = hw_job_ring_error(job_ring);
457*91f16700Schasinglulu 	if (unlikely(sec_error_code) != 0) {
458*91f16700Schasinglulu 		ERROR("Error here itself %x\n", sec_error_code);
459*91f16700Schasinglulu 		return -1;
460*91f16700Schasinglulu 	}
461*91f16700Schasinglulu 	/* Compute the number of notifications that need to be raised to UA
462*91f16700Schasinglulu 	 * If limit < 0 -> notify all done jobs
463*91f16700Schasinglulu 	 * If limit > total number of done jobs -> notify all done jobs
464*91f16700Schasinglulu 	 * If limit = 0 -> error
465*91f16700Schasinglulu 	 * If limit > 0 && limit < total number of done jobs -> notify a number
466*91f16700Schasinglulu 	 * of done jobs equal with limit
467*91f16700Schasinglulu 	 */
468*91f16700Schasinglulu 
469*91f16700Schasinglulu 	/*compute the number of jobs available in the job ring based on the
470*91f16700Schasinglulu 	 * producer and consumer index values.
471*91f16700Schasinglulu 	 */
472*91f16700Schasinglulu 
473*91f16700Schasinglulu 	number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
474*91f16700Schasinglulu 	jobs_no_to_notify = (limit < 0 || limit > number_of_jobs_available) ?
475*91f16700Schasinglulu 	    number_of_jobs_available : limit;
476*91f16700Schasinglulu 	VERBOSE("JR - pi %d, ci %d, ", job_ring->pidx, job_ring->cidx);
477*91f16700Schasinglulu 	VERBOSE("Jobs submitted %d", number_of_jobs_available);
478*91f16700Schasinglulu 	VERBOSE("Jobs to notify %d\n", jobs_no_to_notify);
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	while (jobs_no_to_notify > notified_descs_no) {
481*91f16700Schasinglulu 
482*91f16700Schasinglulu #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
483*91f16700Schasinglulu 		inv_dcache_range(
484*91f16700Schasinglulu 			(uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
485*91f16700Schasinglulu 			sizeof(struct sec_outring_entry));
486*91f16700Schasinglulu 		dmbsy();
487*91f16700Schasinglulu #endif
488*91f16700Schasinglulu 
489*91f16700Schasinglulu 		/* Get job status here */
490*91f16700Schasinglulu 		sec_error_code =
491*91f16700Schasinglulu 		    sec_in32(&(job_ring->output_ring[job_ring->cidx].status));
492*91f16700Schasinglulu 
493*91f16700Schasinglulu 		/* Get completed descriptor
494*91f16700Schasinglulu 		 */
495*91f16700Schasinglulu 		current_desc_loc = (uintptr_t)
496*91f16700Schasinglulu 		    &job_ring->output_ring[job_ring->cidx].desc;
497*91f16700Schasinglulu 		current_desc_addr = sec_read_addr(current_desc_loc);
498*91f16700Schasinglulu 
499*91f16700Schasinglulu 		current_desc = ptov((phys_addr_t *) current_desc_addr);
500*91f16700Schasinglulu 		if (current_desc == 0) {
501*91f16700Schasinglulu 			ERROR("No descriptor returned from SEC");
502*91f16700Schasinglulu 			assert(current_desc);
503*91f16700Schasinglulu 			return 0;
504*91f16700Schasinglulu 		}
505*91f16700Schasinglulu 		/* now increment the consumer index for the current job ring,
506*91f16700Schasinglulu 		 * AFTER saving job in temporary location!
507*91f16700Schasinglulu 		 */
508*91f16700Schasinglulu 		job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
509*91f16700Schasinglulu 						      SEC_JOB_RING_SIZE);
510*91f16700Schasinglulu 
511*91f16700Schasinglulu 		if (sec_error_code != 0) {
512*91f16700Schasinglulu 			ERROR("desc at cidx %d\n ", job_ring->cidx);
513*91f16700Schasinglulu 			ERROR("generated error %x\n", sec_error_code);
514*91f16700Schasinglulu 
515*91f16700Schasinglulu 			sec_handle_desc_error(job_ring,
516*91f16700Schasinglulu 					      sec_error_code,
517*91f16700Schasinglulu 					      &error_descs_no,
518*91f16700Schasinglulu 					      &do_driver_shutdown);
519*91f16700Schasinglulu 			hw_remove_entries(job_ring, 1);
520*91f16700Schasinglulu 
521*91f16700Schasinglulu 			return -1;
522*91f16700Schasinglulu 		}
523*91f16700Schasinglulu 		/* Signal that the job has been processed & the slot is free */
524*91f16700Schasinglulu 		hw_remove_entries(job_ring, 1);
525*91f16700Schasinglulu 		notified_descs_no++;
526*91f16700Schasinglulu 
527*91f16700Schasinglulu 		arg_addr = (phys_addr_t *) (current_desc +
528*91f16700Schasinglulu 				(MAX_DESC_SIZE_WORDS * sizeof(uint32_t)));
529*91f16700Schasinglulu 
530*91f16700Schasinglulu 		fnptr = (phys_addr_t *) (current_desc +
531*91f16700Schasinglulu 					(MAX_DESC_SIZE_WORDS * sizeof(uint32_t)
532*91f16700Schasinglulu 					+  sizeof(void *)));
533*91f16700Schasinglulu 
534*91f16700Schasinglulu 		arg = (void *)*(arg_addr);
535*91f16700Schasinglulu 		if (*fnptr != 0) {
536*91f16700Schasinglulu 			VERBOSE("Callback Function called\n");
537*91f16700Schasinglulu 			usercall = (user_callback) *(fnptr);
538*91f16700Schasinglulu 			(*usercall) ((uint32_t *) current_desc,
539*91f16700Schasinglulu 				     sec_error_code, arg, job_ring);
540*91f16700Schasinglulu 		}
541*91f16700Schasinglulu 	}
542*91f16700Schasinglulu 
543*91f16700Schasinglulu 	return notified_descs_no;
544*91f16700Schasinglulu }
545*91f16700Schasinglulu 
546*91f16700Schasinglulu void sec_handle_desc_error(sec_job_ring_t *job_ring,
547*91f16700Schasinglulu 			   uint32_t sec_error_code,
548*91f16700Schasinglulu 			   uint32_t *notified_descs,
549*91f16700Schasinglulu 			   uint32_t *do_driver_shutdown)
550*91f16700Schasinglulu {
551*91f16700Schasinglulu 	/* Analyze the SEC error on this job ring */
552*91f16700Schasinglulu 	hw_handle_job_ring_error(job_ring, sec_error_code);
553*91f16700Schasinglulu }
554*91f16700Schasinglulu 
555*91f16700Schasinglulu void flush_job_rings(void)
556*91f16700Schasinglulu {
557*91f16700Schasinglulu 	struct sec_job_ring_t *job_ring = NULL;
558*91f16700Schasinglulu 	int i = 0;
559*91f16700Schasinglulu 
560*91f16700Schasinglulu 	for (i = 0; i < g_job_rings_no; i++) {
561*91f16700Schasinglulu 		job_ring = &g_job_rings[i];
562*91f16700Schasinglulu 		/* Producer index is frozen. If consumer index is not equal
563*91f16700Schasinglulu 		 * with producer index, then we have descs to flush.
564*91f16700Schasinglulu 		 */
565*91f16700Schasinglulu 		while (job_ring->pidx != job_ring->cidx) {
566*91f16700Schasinglulu 			hw_flush_job_ring(job_ring, false, 0,	/* no error */
567*91f16700Schasinglulu 					  NULL);
568*91f16700Schasinglulu 		}
569*91f16700Schasinglulu 	}
570*91f16700Schasinglulu }
571*91f16700Schasinglulu 
572*91f16700Schasinglulu int shutdown_job_ring(struct sec_job_ring_t *job_ring)
573*91f16700Schasinglulu {
574*91f16700Schasinglulu 	int ret = 0;
575*91f16700Schasinglulu 
576*91f16700Schasinglulu 	ret = hw_shutdown_job_ring(job_ring);
577*91f16700Schasinglulu 	if (ret != 0) {
578*91f16700Schasinglulu 		ERROR("Failed to shutdown hardware job ring\n");
579*91f16700Schasinglulu 		return ret;
580*91f16700Schasinglulu 	}
581*91f16700Schasinglulu 
582*91f16700Schasinglulu 	if (job_ring->coalescing_en != 0) {
583*91f16700Schasinglulu 		hw_job_ring_disable_coalescing(job_ring);
584*91f16700Schasinglulu 	}
585*91f16700Schasinglulu 
586*91f16700Schasinglulu 	if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
587*91f16700Schasinglulu 		ret = jr_disable_irqs(job_ring);
588*91f16700Schasinglulu 		if (ret != 0) {
589*91f16700Schasinglulu 			ERROR("Failed to disable irqs for job ring");
590*91f16700Schasinglulu 			return ret;
591*91f16700Schasinglulu 		}
592*91f16700Schasinglulu 	}
593*91f16700Schasinglulu 
594*91f16700Schasinglulu 	return 0;
595*91f16700Schasinglulu }
596*91f16700Schasinglulu 
597*91f16700Schasinglulu int jr_enable_irqs(struct sec_job_ring_t *job_ring)
598*91f16700Schasinglulu {
599*91f16700Schasinglulu 	uint32_t reg_val = 0U;
600*91f16700Schasinglulu 	struct jobring_regs *regs =
601*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
602*91f16700Schasinglulu 
603*91f16700Schasinglulu 	/* Get the current value of the register */
604*91f16700Schasinglulu 	reg_val = sec_in32(&regs->jrcfg1);
605*91f16700Schasinglulu 
606*91f16700Schasinglulu 	/* Enable interrupts by disabling interrupt masking*/
607*91f16700Schasinglulu 	reg_val &= ~JR_REG_JRCFG_LO_IMSK_EN;
608*91f16700Schasinglulu 
609*91f16700Schasinglulu 	/* Update parameters in HW */
610*91f16700Schasinglulu 	sec_out32(&regs->jrcfg1, reg_val);
611*91f16700Schasinglulu 
612*91f16700Schasinglulu 	VERBOSE("Enable interrupts on JR\n");
613*91f16700Schasinglulu 
614*91f16700Schasinglulu 	return 0;
615*91f16700Schasinglulu }
616*91f16700Schasinglulu 
617*91f16700Schasinglulu int jr_disable_irqs(struct sec_job_ring_t *job_ring)
618*91f16700Schasinglulu {
619*91f16700Schasinglulu 	uint32_t reg_val = 0U;
620*91f16700Schasinglulu 	struct jobring_regs *regs =
621*91f16700Schasinglulu 	    (struct jobring_regs *)job_ring->register_base_addr;
622*91f16700Schasinglulu 
623*91f16700Schasinglulu 	/* Get the current value of the register */
624*91f16700Schasinglulu 	reg_val = sec_in32(&regs->jrcfg1);
625*91f16700Schasinglulu 
626*91f16700Schasinglulu 	/* Disable interrupts by enabling interrupt masking*/
627*91f16700Schasinglulu 	reg_val |= JR_REG_JRCFG_LO_IMSK_EN;
628*91f16700Schasinglulu 
629*91f16700Schasinglulu 	/* Update parameters in HW */
630*91f16700Schasinglulu 	sec_out32(&regs->jrcfg1, reg_val);
631*91f16700Schasinglulu 
632*91f16700Schasinglulu 	VERBOSE("Disable interrupts on JR\n");
633*91f16700Schasinglulu 
634*91f16700Schasinglulu 	return 0;
635*91f16700Schasinglulu }
636