aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJorge Ramirez-Ortiz <jorge@foundries.io>2021-10-04 16:13:44 +0200
committerJérôme Forissier <jerome@forissier.org>2021-11-08 10:13:23 +0100
commit777da538ab49f4b6acd8df4b5dae6e84e4938d6b (patch)
tree0d9ab61a00846d9cf3d9095dba7e8d83999c4074 /core
parente4a0a8526b0a3a07792ea21af60cf740e246439a (diff)
zynqmp: drivers: CSUDMA module
This module provides a mechanism to transfer data between memory and peripherals. The data path is selected in the Secure Stream Switch register in the CSU. Signed-off-by: Jorge Ramirez-Ortiz <jorge@foundries.io> Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Diffstat (limited to 'core')
-rw-r--r--core/arch/arm/plat-zynqmp/conf.mk4
-rw-r--r--core/drivers/sub.mk1
-rw-r--r--core/drivers/zynqmp_csudma.c146
-rw-r--r--core/include/drivers/zynqmp_csudma.h31
4 files changed, 180 insertions, 2 deletions
diff --git a/core/arch/arm/plat-zynqmp/conf.mk b/core/arch/arm/plat-zynqmp/conf.mk
index 5ff1e3e1..cfc0b57a 100644
--- a/core/arch/arm/plat-zynqmp/conf.mk
+++ b/core/arch/arm/plat-zynqmp/conf.mk
@@ -28,6 +28,6 @@ CFG_SHMEM_SIZE ?= 0x10000000
CFG_WITH_STATS ?= y
CFG_CRYPTO_WITH_CE ?= y
-ifneq (,$(filter y, $(CFG_ZYNQMP_CSU_PUF)))
-$(call force,CFG_ZYNQMP_CSU,y,Mandated by CFG_ZYNQMP_CSU_PUF)
+ifneq (,$(filter y, $(CFG_ZYNQMP_CSU_PUF) $(CFG_ZYNQMP_CSUDMA)))
+$(call force,CFG_ZYNQMP_CSU,y,Mandated by CFG_ZYNQMP_CSU* clients)
endif
diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk
index 004cf910..8ea61dc3 100644
--- a/core/drivers/sub.mk
+++ b/core/drivers/sub.mk
@@ -39,6 +39,7 @@ srcs-$(CFG_IMX_RNGB) += imx_rngb.c
srcs-$(CFG_IMX_OCOTP) += imx_ocotp.c
srcs-$(CFG_IMX_SC) += imx_mu.c
srcs-$(CFG_ZYNQMP_CSU_PUF) += zynqmp_csu_puf.c
+srcs-$(CFG_ZYNQMP_CSUDMA) += zynqmp_csudma.c
subdirs-y += crypto
subdirs-$(CFG_BNXT_FW) += bnxt
diff --git a/core/drivers/zynqmp_csudma.c b/core/drivers/zynqmp_csudma.c
new file mode 100644
index 00000000..8809635b
--- /dev/null
+++ b/core/drivers/zynqmp_csudma.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright 2021 Foundries.io Ltd.
+ * Jorge Ramirez-Ortiz <jorge@foundries.io>
+ */
+
+#include <config.h>
+#include <drivers/zynqmp_csudma.h>
+#include <io.h>
+#include <kernel/cache_helpers.h>
+#include <kernel/delay.h>
+#include <mm/core_memprot.h>
+#include <util.h>
+
+#define CSUDMA_ADDR_OFFSET 0x00
+#define CSUDMA_SIZE_OFFSET 0x04
+#define CSUDMA_STS_OFFSET 0x08
+#define CSUDMA_CTRL_OFFSET 0x0C
+#define CSUDMA_CRC_OFFSET 0x10
+#define CSUDMA_I_STS_OFFSET 0x14
+#define CSUDMA_I_EN_OFFSET 0x18
+#define CSUDMA_I_DIS_OFFSET 0x1C
+#define CSUDMA_I_MASK_OFFSET 0x20
+#define CSUDMA_CTRL2_OFFSET 0x24
+#define CSUDMA_ADDR_MSB_OFFSET 0x28
+
+#define CSUDMA_OFFSET_DIFF 0x0800
+
+#define CSUDMA_ADDR_MASK GENMASK_32(31, 2)
+#define CSUDMA_ADDR_LSB_MASK (BIT(0) | BIT(1))
+#define CSUDMA_ADDR_MSB_MASK GENMASK_32(16, 0)
+#define CSUDMA_ADDR_MSB_SHIFT 32
+#define CSUDMA_SIZE_SHIFT 2
+#define CSUDMA_STS_BUSY_MASK BIT(0)
+#define CSUDMA_CTRL_ENDIAN_MASK BIT(23)
+#define CSUDMA_LAST_WORD_MASK BIT(0)
+#define CSUDMA_IXR_DONE_MASK BIT(1)
+#define CSUDMA_IXR_SRC_MASK GENMASK_32(6, 0)
+#define CSUDMA_IXR_DST_MASK GENMASK_32(7, 1)
+
+#define CSUDMA_DONE_TIMEOUT_USEC 3000000
+
+register_phys_mem_pgdir(MEM_AREA_IO_SEC, CSUDMA_BASE, CSUDMA_SIZE);
+
+static void csudma_clear_intr(enum zynqmp_csudma_channel channel, uint32_t mask)
+{
+ vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
+ CSUDMA_SIZE);
+ uint32_t val = CSUDMA_IXR_SRC_MASK;
+
+ if (channel == ZYNQMP_CSUDMA_DST_CHANNEL) {
+ dma += CSUDMA_OFFSET_DIFF;
+ val = CSUDMA_IXR_DST_MASK;
+ }
+
+ io_write32(dma + CSUDMA_I_STS_OFFSET, val & mask);
+}
+
+TEE_Result zynqmp_csudma_sync(enum zynqmp_csudma_channel channel)
+{
+ vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
+ CSUDMA_SIZE);
+ uint64_t tref = timeout_init_us(CSUDMA_DONE_TIMEOUT_USEC);
+ uint32_t status = 0;
+
+ if (!dma)
+ return TEE_ERROR_GENERIC;
+
+ if (channel == ZYNQMP_CSUDMA_DST_CHANNEL)
+ dma = dma + CSUDMA_OFFSET_DIFF;
+
+ while (!timeout_elapsed(tref)) {
+ status = io_read32(dma + CSUDMA_I_STS_OFFSET);
+ if ((status & CSUDMA_IXR_DONE_MASK) == CSUDMA_IXR_DONE_MASK) {
+ csudma_clear_intr(channel, CSUDMA_IXR_DONE_MASK);
+ return TEE_SUCCESS;
+ }
+ }
+
+ return TEE_ERROR_GENERIC;
+}
+
+TEE_Result zynqmp_csudma_prepare(void)
+{
+ vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
+ CSUDMA_SIZE);
+
+ if (!dma)
+ return TEE_ERROR_GENERIC;
+
+ io_setbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
+ dma = dma + CSUDMA_OFFSET_DIFF;
+ io_setbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
+
+ return TEE_SUCCESS;
+}
+
+void zynqmp_csudma_unprepare(void)
+{
+ vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
+ CSUDMA_SIZE);
+
+ io_clrbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
+ dma = dma + CSUDMA_OFFSET_DIFF;
+ io_clrbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
+}
+
+TEE_Result zynqmp_csudma_transfer(enum zynqmp_csudma_channel channel,
+ void *addr, size_t len, uint8_t notify)
+{
+ vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
+ CSUDMA_SIZE);
+ paddr_t phys = virt_to_phys(addr);
+ uint32_t addr_offset = 0;
+
+ if (!dma)
+ return TEE_ERROR_GENERIC;
+
+ if (len % sizeof(uint32_t))
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ if (!IS_ALIGNED(phys, ZYNQMP_CSUDMA_ALIGN)) {
+ EMSG("Invalid alignment");
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ /* convert to 32 bit word transfers */
+ len = len / sizeof(uint32_t);
+
+ if (channel == ZYNQMP_CSUDMA_DST_CHANNEL) {
+ dma = dma + CSUDMA_OFFSET_DIFF;
+ dcache_inv_range(addr, SHIFT_U64(len, CSUDMA_SIZE_SHIFT));
+ } else {
+ dcache_clean_range(addr, SHIFT_U64(len, CSUDMA_SIZE_SHIFT));
+ }
+
+ addr_offset = phys & CSUDMA_ADDR_MASK;
+ io_write32(dma + CSUDMA_ADDR_OFFSET, addr_offset);
+
+ addr_offset = phys >> CSUDMA_ADDR_MSB_SHIFT;
+ io_write32(dma + CSUDMA_ADDR_MSB_OFFSET, addr_offset);
+ io_write32(dma + CSUDMA_SIZE_OFFSET,
+ SHIFT_U32(len, CSUDMA_SIZE_SHIFT) | notify);
+
+ return TEE_SUCCESS;
+}
diff --git a/core/include/drivers/zynqmp_csudma.h b/core/include/drivers/zynqmp_csudma.h
new file mode 100644
index 00000000..afbf51ce
--- /dev/null
+++ b/core/include/drivers/zynqmp_csudma.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) Foundries Ltd. 2021
+ * Author: Jorge Ramirez <jorge@foundries.io>
+ */
+
+#ifndef __DRIVERS_ZYNQMP_CSUDMA_H_
+#define __DRIVERS_ZYNQMP_CSUDMA_H_
+
+#include <drivers/zynqmp_csu.h>
+#include <tee_api_types.h>
+#include <types_ext.h>
+
+#define ZYNQMP_CSUDMA_ALIGN 64
+#define __aligned_csudma __aligned(ZYNQMP_CSUDMA_ALIGN)
+
+#define ZYNQMP_CSUDMA_MIN_SIZE 16
+#define ZYNQMP_CSUDMA_DONE BIT(0)
+
+enum zynqmp_csudma_channel {
+ ZYNQMP_CSUDMA_SRC_CHANNEL = 0,
+ ZYNQMP_CSUDMA_DST_CHANNEL
+};
+
+TEE_Result zynqmp_csudma_transfer(enum zynqmp_csudma_channel channel,
+ void *address, size_t len, uint8_t notify);
+TEE_Result zynqmp_csudma_sync(enum zynqmp_csudma_channel channel);
+TEE_Result zynqmp_csudma_prepare(void);
+void zynqmp_csudma_unprepare(void);
+
+#endif