xref: /optee_os/core/drivers/zynqmp_csudma.c (revision 777da538ab49f4b6acd8df4b5dae6e84e4938d6b)
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