aboutsummaryrefslogtreecommitdiff
path: root/drivers/nxp/crypto/caam/src/sec_jr_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nxp/crypto/caam/src/sec_jr_driver.c')
-rw-r--r--drivers/nxp/crypto/caam/src/sec_jr_driver.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/drivers/nxp/crypto/caam/src/sec_jr_driver.c b/drivers/nxp/crypto/caam/src/sec_jr_driver.c
new file mode 100644
index 0000000000..1fe700718e
--- /dev/null
+++ b/drivers/nxp/crypto/caam/src/sec_jr_driver.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include "caam.h"
+#include <common/debug.h>
+#include "jobdesc.h"
+#include "nxp_timer.h"
+#include "sec_hw_specific.h"
+#include "sec_jr_driver.h"
+
+
+/* Job rings used for communication with SEC HW */
+struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
+
+/* The current state of SEC user space driver */
+volatile sec_driver_state_t g_driver_state = SEC_DRIVER_STATE_IDLE;
+
+int g_job_rings_no;
+
+uint8_t ip_ring[SEC_DMA_MEM_INPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
+uint8_t op_ring[SEC_DMA_MEM_OUTPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
+
+void *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)
+{
+ struct sec_job_ring_t *job_ring = &g_job_rings[g_job_rings_no++];
+ int ret = 0;
+
+ job_ring->register_base_addr = reg_base_addr;
+ job_ring->jr_mode = jr_mode;
+ job_ring->irq_fd = irq_id;
+
+ job_ring->input_ring = vtop(ip_ring);
+ memset(job_ring->input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE);
+
+ job_ring->output_ring = (struct sec_outring_entry *)vtop(op_ring);
+ memset(job_ring->output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE);
+
+ dsb();
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)(job_ring->input_ring),
+ SEC_DMA_MEM_INPUT_RING_SIZE),
+ flush_dcache_range((uintptr_t)(job_ring->output_ring),
+ SEC_DMA_MEM_OUTPUT_RING_SIZE),
+
+ dmbsy();
+#endif
+ /* Reset job ring in SEC hw and configure job ring registers */
+ ret = hw_reset_job_ring(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to reset hardware job ring\n");
+ return NULL;
+ }
+
+ if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
+ /* Enable IRQ if driver work sin interrupt mode */
+ ERROR("Enabling DONE IRQ generation on job ring\n");
+ ret = jr_enable_irqs(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to enable irqs for job ring\n");
+ return NULL;
+ }
+ }
+ if ((irq_coalescing_timer != 0) || (irq_coalescing_count != 0)) {
+ hw_job_ring_set_coalescing_param(job_ring,
+ irq_coalescing_timer,
+ irq_coalescing_count);
+
+ hw_job_ring_enable_coalescing(job_ring);
+ job_ring->coalescing_en = 1;
+ }
+
+ job_ring->jr_state = SEC_JOB_RING_STATE_STARTED;
+
+ return job_ring;
+}
+
+int sec_release(void)
+{
+ int i;
+
+ /* Validate driver state */
+ if (g_driver_state == SEC_DRIVER_STATE_RELEASE) {
+ ERROR("Driver release is already in progress");
+ return SEC_DRIVER_RELEASE_IN_PROGRESS;
+ }
+ /* Update driver state */
+ g_driver_state = SEC_DRIVER_STATE_RELEASE;
+
+ /* If any descriptors in flight , poll and wait
+ * until all descriptors are received and silently discarded.
+ */
+
+ flush_job_rings();
+
+ for (i = 0; i < g_job_rings_no; i++) {
+ shutdown_job_ring(&g_job_rings[i]);
+ }
+ g_job_rings_no = 0;
+ g_driver_state = SEC_DRIVER_STATE_IDLE;
+
+ return SEC_SUCCESS;
+}
+
+int sec_jr_lib_init(void)
+{
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_IDLE) {
+ ERROR("Driver already initialized\n");
+ return 0;
+ }
+
+ memset(g_job_rings, 0, sizeof(g_job_rings));
+ g_job_rings_no = 0;
+
+ /* Update driver state */
+ g_driver_state = SEC_DRIVER_STATE_STARTED;
+ return 0;
+}
+
+int dequeue_jr(void *job_ring_handle, int32_t limit)
+{
+ int ret = 0;
+ int notified_descs_no = 0;
+ struct sec_job_ring_t *job_ring = (sec_job_ring_t *) job_ring_handle;
+ uint64_t start_time;
+
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
+ ERROR("Driver release in progress or driver not initialized\n");
+ return -1;
+ }
+
+ /* Validate input arguments */
+ if (job_ring == NULL) {
+ ERROR("job_ring_handle is NULL\n");
+ return -1;
+ }
+ if (((limit == 0) || (limit > SEC_JOB_RING_SIZE))) {
+ ERROR("Invalid limit parameter configuration\n");
+ return -1;
+ }
+
+ VERBOSE("JR Polling limit[%d]\n", limit);
+
+ /* Poll job ring
+ * If limit < 0 -> poll JR until no more notifications are available.
+ * If limit > 0 -> poll JR until limit is reached.
+ */
+
+ start_time = get_timer_val(0);
+
+ while (notified_descs_no == 0) {
+ /* Run hw poll job ring */
+ notified_descs_no = hw_poll_job_ring(job_ring, limit);
+ if (notified_descs_no < 0) {
+ ERROR("Error polling SEC engine job ring ");
+ return notified_descs_no;
+ }
+ VERBOSE("Jobs notified[%d]. ", notified_descs_no);
+
+ if (get_timer_val(start_time) >= CAAM_TIMEOUT) {
+ break;
+ }
+ }
+
+ if (job_ring->jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
+
+ /* Always enable IRQ generation when in pure IRQ mode */
+ ret = jr_enable_irqs(job_ring);
+ if (ret != 0) {
+ ERROR("Failed to enable irqs for job ring");
+ return ret;
+ }
+ }
+ return notified_descs_no;
+}
+
+int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr)
+{
+ struct sec_job_ring_t *job_ring;
+
+ job_ring = (struct sec_job_ring_t *)job_ring_handle;
+
+ /* Validate driver state */
+ if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
+ ERROR("Driver release in progress or driver not initialized\n");
+ return -1;
+ }
+
+ /* Check job ring state */
+ if (job_ring->jr_state != SEC_JOB_RING_STATE_STARTED) {
+ ERROR("Job ring is currently resetting\n");
+ return -1;
+ }
+
+ if (SEC_JOB_RING_IS_FULL(job_ring->pidx, job_ring->cidx,
+ SEC_JOB_RING_SIZE, SEC_JOB_RING_SIZE)) {
+ ERROR("Job ring is full\n");
+ return -1;
+ }
+
+ /* Set ptr in input ring to current descriptor */
+ sec_write_addr(&job_ring->input_ring[job_ring->pidx],
+ (phys_addr_t) vtop(jobdescr->desc));
+
+ dsb();
+
+#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
+ flush_dcache_range((uintptr_t)(&job_ring->input_ring[job_ring->pidx]),
+ sizeof(phys_addr_t));
+
+ inv_dcache_range((uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
+ sizeof(struct sec_outring_entry));
+ dmbsy();
+#endif
+ /* Notify HW that a new job is enqueued */
+ hw_enqueue_desc_on_job_ring(
+ (struct jobring_regs *)job_ring->register_base_addr, 1);
+
+ /* increment the producer index for the current job ring */
+ job_ring->pidx = SEC_CIRCULAR_COUNTER(job_ring->pidx,
+ SEC_JOB_RING_SIZE);
+
+ return 0;
+}