1*777da538SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
2*777da538SJorge Ramirez-Ortiz /*
3*777da538SJorge Ramirez-Ortiz * Copyright 2021 Foundries.io Ltd.
4*777da538SJorge Ramirez-Ortiz * Jorge Ramirez-Ortiz <jorge@foundries.io>
5*777da538SJorge Ramirez-Ortiz */
6*777da538SJorge Ramirez-Ortiz
7*777da538SJorge Ramirez-Ortiz #include <config.h>
8*777da538SJorge Ramirez-Ortiz #include <drivers/zynqmp_csudma.h>
9*777da538SJorge Ramirez-Ortiz #include <io.h>
10*777da538SJorge Ramirez-Ortiz #include <kernel/cache_helpers.h>
11*777da538SJorge Ramirez-Ortiz #include <kernel/delay.h>
12*777da538SJorge Ramirez-Ortiz #include <mm/core_memprot.h>
13*777da538SJorge Ramirez-Ortiz #include <util.h>
14*777da538SJorge Ramirez-Ortiz
15*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_OFFSET 0x00
16*777da538SJorge Ramirez-Ortiz #define CSUDMA_SIZE_OFFSET 0x04
17*777da538SJorge Ramirez-Ortiz #define CSUDMA_STS_OFFSET 0x08
18*777da538SJorge Ramirez-Ortiz #define CSUDMA_CTRL_OFFSET 0x0C
19*777da538SJorge Ramirez-Ortiz #define CSUDMA_CRC_OFFSET 0x10
20*777da538SJorge Ramirez-Ortiz #define CSUDMA_I_STS_OFFSET 0x14
21*777da538SJorge Ramirez-Ortiz #define CSUDMA_I_EN_OFFSET 0x18
22*777da538SJorge Ramirez-Ortiz #define CSUDMA_I_DIS_OFFSET 0x1C
23*777da538SJorge Ramirez-Ortiz #define CSUDMA_I_MASK_OFFSET 0x20
24*777da538SJorge Ramirez-Ortiz #define CSUDMA_CTRL2_OFFSET 0x24
25*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_MSB_OFFSET 0x28
26*777da538SJorge Ramirez-Ortiz
27*777da538SJorge Ramirez-Ortiz #define CSUDMA_OFFSET_DIFF 0x0800
28*777da538SJorge Ramirez-Ortiz
29*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_MASK GENMASK_32(31, 2)
30*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_LSB_MASK (BIT(0) | BIT(1))
31*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_MSB_MASK GENMASK_32(16, 0)
32*777da538SJorge Ramirez-Ortiz #define CSUDMA_ADDR_MSB_SHIFT 32
33*777da538SJorge Ramirez-Ortiz #define CSUDMA_SIZE_SHIFT 2
34*777da538SJorge Ramirez-Ortiz #define CSUDMA_STS_BUSY_MASK BIT(0)
35*777da538SJorge Ramirez-Ortiz #define CSUDMA_CTRL_ENDIAN_MASK BIT(23)
36*777da538SJorge Ramirez-Ortiz #define CSUDMA_LAST_WORD_MASK BIT(0)
37*777da538SJorge Ramirez-Ortiz #define CSUDMA_IXR_DONE_MASK BIT(1)
38*777da538SJorge Ramirez-Ortiz #define CSUDMA_IXR_SRC_MASK GENMASK_32(6, 0)
39*777da538SJorge Ramirez-Ortiz #define CSUDMA_IXR_DST_MASK GENMASK_32(7, 1)
40*777da538SJorge Ramirez-Ortiz
41*777da538SJorge Ramirez-Ortiz #define CSUDMA_DONE_TIMEOUT_USEC 3000000
42*777da538SJorge Ramirez-Ortiz
43*777da538SJorge Ramirez-Ortiz register_phys_mem_pgdir(MEM_AREA_IO_SEC, CSUDMA_BASE, CSUDMA_SIZE);
44*777da538SJorge Ramirez-Ortiz
csudma_clear_intr(enum zynqmp_csudma_channel channel,uint32_t mask)45*777da538SJorge Ramirez-Ortiz static void csudma_clear_intr(enum zynqmp_csudma_channel channel, uint32_t mask)
46*777da538SJorge Ramirez-Ortiz {
47*777da538SJorge Ramirez-Ortiz vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
48*777da538SJorge Ramirez-Ortiz CSUDMA_SIZE);
49*777da538SJorge Ramirez-Ortiz uint32_t val = CSUDMA_IXR_SRC_MASK;
50*777da538SJorge Ramirez-Ortiz
51*777da538SJorge Ramirez-Ortiz if (channel == ZYNQMP_CSUDMA_DST_CHANNEL) {
52*777da538SJorge Ramirez-Ortiz dma += CSUDMA_OFFSET_DIFF;
53*777da538SJorge Ramirez-Ortiz val = CSUDMA_IXR_DST_MASK;
54*777da538SJorge Ramirez-Ortiz }
55*777da538SJorge Ramirez-Ortiz
56*777da538SJorge Ramirez-Ortiz io_write32(dma + CSUDMA_I_STS_OFFSET, val & mask);
57*777da538SJorge Ramirez-Ortiz }
58*777da538SJorge Ramirez-Ortiz
zynqmp_csudma_sync(enum zynqmp_csudma_channel channel)59*777da538SJorge Ramirez-Ortiz TEE_Result zynqmp_csudma_sync(enum zynqmp_csudma_channel channel)
60*777da538SJorge Ramirez-Ortiz {
61*777da538SJorge Ramirez-Ortiz vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
62*777da538SJorge Ramirez-Ortiz CSUDMA_SIZE);
63*777da538SJorge Ramirez-Ortiz uint64_t tref = timeout_init_us(CSUDMA_DONE_TIMEOUT_USEC);
64*777da538SJorge Ramirez-Ortiz uint32_t status = 0;
65*777da538SJorge Ramirez-Ortiz
66*777da538SJorge Ramirez-Ortiz if (!dma)
67*777da538SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
68*777da538SJorge Ramirez-Ortiz
69*777da538SJorge Ramirez-Ortiz if (channel == ZYNQMP_CSUDMA_DST_CHANNEL)
70*777da538SJorge Ramirez-Ortiz dma = dma + CSUDMA_OFFSET_DIFF;
71*777da538SJorge Ramirez-Ortiz
72*777da538SJorge Ramirez-Ortiz while (!timeout_elapsed(tref)) {
73*777da538SJorge Ramirez-Ortiz status = io_read32(dma + CSUDMA_I_STS_OFFSET);
74*777da538SJorge Ramirez-Ortiz if ((status & CSUDMA_IXR_DONE_MASK) == CSUDMA_IXR_DONE_MASK) {
75*777da538SJorge Ramirez-Ortiz csudma_clear_intr(channel, CSUDMA_IXR_DONE_MASK);
76*777da538SJorge Ramirez-Ortiz return TEE_SUCCESS;
77*777da538SJorge Ramirez-Ortiz }
78*777da538SJorge Ramirez-Ortiz }
79*777da538SJorge Ramirez-Ortiz
80*777da538SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
81*777da538SJorge Ramirez-Ortiz }
82*777da538SJorge Ramirez-Ortiz
zynqmp_csudma_prepare(void)83*777da538SJorge Ramirez-Ortiz TEE_Result zynqmp_csudma_prepare(void)
84*777da538SJorge Ramirez-Ortiz {
85*777da538SJorge Ramirez-Ortiz vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
86*777da538SJorge Ramirez-Ortiz CSUDMA_SIZE);
87*777da538SJorge Ramirez-Ortiz
88*777da538SJorge Ramirez-Ortiz if (!dma)
89*777da538SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
90*777da538SJorge Ramirez-Ortiz
91*777da538SJorge Ramirez-Ortiz io_setbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
92*777da538SJorge Ramirez-Ortiz dma = dma + CSUDMA_OFFSET_DIFF;
93*777da538SJorge Ramirez-Ortiz io_setbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
94*777da538SJorge Ramirez-Ortiz
95*777da538SJorge Ramirez-Ortiz return TEE_SUCCESS;
96*777da538SJorge Ramirez-Ortiz }
97*777da538SJorge Ramirez-Ortiz
zynqmp_csudma_unprepare(void)98*777da538SJorge Ramirez-Ortiz void zynqmp_csudma_unprepare(void)
99*777da538SJorge Ramirez-Ortiz {
100*777da538SJorge Ramirez-Ortiz vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
101*777da538SJorge Ramirez-Ortiz CSUDMA_SIZE);
102*777da538SJorge Ramirez-Ortiz
103*777da538SJorge Ramirez-Ortiz io_clrbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
104*777da538SJorge Ramirez-Ortiz dma = dma + CSUDMA_OFFSET_DIFF;
105*777da538SJorge Ramirez-Ortiz io_clrbits32(dma + CSUDMA_CTRL_OFFSET, CSUDMA_CTRL_ENDIAN_MASK);
106*777da538SJorge Ramirez-Ortiz }
107*777da538SJorge Ramirez-Ortiz
zynqmp_csudma_transfer(enum zynqmp_csudma_channel channel,void * addr,size_t len,uint8_t notify)108*777da538SJorge Ramirez-Ortiz TEE_Result zynqmp_csudma_transfer(enum zynqmp_csudma_channel channel,
109*777da538SJorge Ramirez-Ortiz void *addr, size_t len, uint8_t notify)
110*777da538SJorge Ramirez-Ortiz {
111*777da538SJorge Ramirez-Ortiz vaddr_t dma = core_mmu_get_va(CSUDMA_BASE, MEM_AREA_IO_SEC,
112*777da538SJorge Ramirez-Ortiz CSUDMA_SIZE);
113*777da538SJorge Ramirez-Ortiz paddr_t phys = virt_to_phys(addr);
114*777da538SJorge Ramirez-Ortiz uint32_t addr_offset = 0;
115*777da538SJorge Ramirez-Ortiz
116*777da538SJorge Ramirez-Ortiz if (!dma)
117*777da538SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
118*777da538SJorge Ramirez-Ortiz
119*777da538SJorge Ramirez-Ortiz if (len % sizeof(uint32_t))
120*777da538SJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS;
121*777da538SJorge Ramirez-Ortiz
122*777da538SJorge Ramirez-Ortiz if (!IS_ALIGNED(phys, ZYNQMP_CSUDMA_ALIGN)) {
123*777da538SJorge Ramirez-Ortiz EMSG("Invalid alignment");
124*777da538SJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS;
125*777da538SJorge Ramirez-Ortiz }
126*777da538SJorge Ramirez-Ortiz
127*777da538SJorge Ramirez-Ortiz /* convert to 32 bit word transfers */
128*777da538SJorge Ramirez-Ortiz len = len / sizeof(uint32_t);
129*777da538SJorge Ramirez-Ortiz
130*777da538SJorge Ramirez-Ortiz if (channel == ZYNQMP_CSUDMA_DST_CHANNEL) {
131*777da538SJorge Ramirez-Ortiz dma = dma + CSUDMA_OFFSET_DIFF;
132*777da538SJorge Ramirez-Ortiz dcache_inv_range(addr, SHIFT_U64(len, CSUDMA_SIZE_SHIFT));
133*777da538SJorge Ramirez-Ortiz } else {
134*777da538SJorge Ramirez-Ortiz dcache_clean_range(addr, SHIFT_U64(len, CSUDMA_SIZE_SHIFT));
135*777da538SJorge Ramirez-Ortiz }
136*777da538SJorge Ramirez-Ortiz
137*777da538SJorge Ramirez-Ortiz addr_offset = phys & CSUDMA_ADDR_MASK;
138*777da538SJorge Ramirez-Ortiz io_write32(dma + CSUDMA_ADDR_OFFSET, addr_offset);
139*777da538SJorge Ramirez-Ortiz
140*777da538SJorge Ramirez-Ortiz addr_offset = phys >> CSUDMA_ADDR_MSB_SHIFT;
141*777da538SJorge Ramirez-Ortiz io_write32(dma + CSUDMA_ADDR_MSB_OFFSET, addr_offset);
142*777da538SJorge Ramirez-Ortiz io_write32(dma + CSUDMA_SIZE_OFFSET,
143*777da538SJorge Ramirez-Ortiz SHIFT_U32(len, CSUDMA_SIZE_SHIFT) | notify);
144*777da538SJorge Ramirez-Ortiz
145*777da538SJorge Ramirez-Ortiz return TEE_SUCCESS;
146*777da538SJorge Ramirez-Ortiz }
147