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