diff options
author | Jorge Ramirez-Ortiz <jorge@foundries.io> | 2021-10-04 16:13:44 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2021-11-08 10:13:23 +0100 |
commit | 777da538ab49f4b6acd8df4b5dae6e84e4938d6b (patch) | |
tree | 0d9ab61a00846d9cf3d9095dba7e8d83999c4074 /core | |
parent | e4a0a8526b0a3a07792ea21af60cf740e246439a (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.mk | 4 | ||||
-rw-r--r-- | core/drivers/sub.mk | 1 | ||||
-rw-r--r-- | core/drivers/zynqmp_csudma.c | 146 | ||||
-rw-r--r-- | core/include/drivers/zynqmp_csudma.h | 31 |
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 |