xref: /arm-trusted-firmware/plat/nvidia/tegra/drivers/gpcdma/gpcdma.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <arch_helpers.h>
8*91f16700Schasinglulu #include <common/debug.h>
9*91f16700Schasinglulu #include <drivers/delay_timer.h>
10*91f16700Schasinglulu #include <errno.h>
11*91f16700Schasinglulu #include <gpcdma.h>
12*91f16700Schasinglulu #include <lib/mmio.h>
13*91f16700Schasinglulu #include <lib/utils_def.h>
14*91f16700Schasinglulu #include <platform_def.h>
15*91f16700Schasinglulu #include <stdbool.h>
16*91f16700Schasinglulu #include <tegra_def.h>
17*91f16700Schasinglulu 
18*91f16700Schasinglulu /* DMA channel registers */
19*91f16700Schasinglulu #define DMA_CH_CSR				U(0x0)
20*91f16700Schasinglulu #define DMA_CH_CSR_WEIGHT_SHIFT			U(10)
21*91f16700Schasinglulu #define DMA_CH_CSR_XFER_MODE_SHIFT		U(21)
22*91f16700Schasinglulu #define DMA_CH_CSR_DMA_MODE_MEM2MEM		U(4)
23*91f16700Schasinglulu #define DMA_CH_CSR_DMA_MODE_FIXEDPATTERN	U(6)
24*91f16700Schasinglulu #define DMA_CH_CSR_IRQ_MASK_ENABLE		(U(1) << 15)
25*91f16700Schasinglulu #define DMA_CH_CSR_RUN_ONCE			(U(1) << 27)
26*91f16700Schasinglulu #define DMA_CH_CSR_ENABLE			(U(1) << 31)
27*91f16700Schasinglulu 
28*91f16700Schasinglulu #define DMA_CH_STAT				U(0x4)
29*91f16700Schasinglulu #define DMA_CH_STAT_BUSY			(U(1) << 31)
30*91f16700Schasinglulu 
31*91f16700Schasinglulu #define DMA_CH_SRC_PTR				U(0xC)
32*91f16700Schasinglulu 
33*91f16700Schasinglulu #define DMA_CH_DST_PTR				U(0x10)
34*91f16700Schasinglulu 
35*91f16700Schasinglulu #define DMA_CH_HI_ADR_PTR			U(0x14)
36*91f16700Schasinglulu #define DMA_CH_HI_ADR_PTR_SRC_MASK		U(0xFF)
37*91f16700Schasinglulu #define DMA_CH_HI_ADR_PTR_DST_SHIFT		U(16)
38*91f16700Schasinglulu #define DMA_CH_HI_ADR_PTR_DST_MASK		U(0xFF)
39*91f16700Schasinglulu 
40*91f16700Schasinglulu #define DMA_CH_MC_SEQ				U(0x18)
41*91f16700Schasinglulu #define DMA_CH_MC_SEQ_REQ_CNT_SHIFT		U(25)
42*91f16700Schasinglulu #define DMA_CH_MC_SEQ_REQ_CNT_VAL		U(0x10)
43*91f16700Schasinglulu #define DMA_CH_MC_SEQ_BURST_SHIFT		U(23)
44*91f16700Schasinglulu #define DMA_CH_MC_SEQ_BURST_16_WORDS		U(0x3)
45*91f16700Schasinglulu 
46*91f16700Schasinglulu #define DMA_CH_WORD_COUNT			U(0x20)
47*91f16700Schasinglulu #define DMA_CH_FIXED_PATTERN			U(0x34)
48*91f16700Schasinglulu #define DMA_CH_TZ				U(0x38)
49*91f16700Schasinglulu #define DMA_CH_TZ_ACCESS_ENABLE			U(0)
50*91f16700Schasinglulu #define DMA_CH_TZ_ACCESS_DISABLE		U(3)
51*91f16700Schasinglulu 
52*91f16700Schasinglulu #define MAX_TRANSFER_SIZE			(1U*1024U*1024U*1024U)	/* 1GB */
53*91f16700Schasinglulu #define GPCDMA_TIMEOUT_MS			U(100)
54*91f16700Schasinglulu #define GPCDMA_RESET_BIT			(U(1) << 1)
55*91f16700Schasinglulu 
56*91f16700Schasinglulu static bool init_done;
57*91f16700Schasinglulu 
58*91f16700Schasinglulu static void tegra_gpcdma_write32(uint32_t offset, uint32_t val)
59*91f16700Schasinglulu {
60*91f16700Schasinglulu 	mmio_write_32(TEGRA_GPCDMA_BASE + offset, val);
61*91f16700Schasinglulu }
62*91f16700Schasinglulu 
63*91f16700Schasinglulu static uint32_t tegra_gpcdma_read32(uint32_t offset)
64*91f16700Schasinglulu {
65*91f16700Schasinglulu 	return mmio_read_32(TEGRA_GPCDMA_BASE + offset);
66*91f16700Schasinglulu }
67*91f16700Schasinglulu 
68*91f16700Schasinglulu static void tegra_gpcdma_init(void)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	/* assert reset for DMA engine */
71*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_SET_REG_OFFSET,
72*91f16700Schasinglulu 		      GPCDMA_RESET_BIT);
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	udelay(2);
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 	/* de-assert reset for DMA engine */
77*91f16700Schasinglulu 	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_CLR_REG_OFFSET,
78*91f16700Schasinglulu 		      GPCDMA_RESET_BIT);
79*91f16700Schasinglulu }
80*91f16700Schasinglulu 
81*91f16700Schasinglulu static void tegra_gpcdma_memcpy_priv(uint64_t dst_addr, uint64_t src_addr,
82*91f16700Schasinglulu 				     uint32_t num_bytes, uint32_t mode)
83*91f16700Schasinglulu {
84*91f16700Schasinglulu 	uint32_t val, timeout = 0;
85*91f16700Schasinglulu 	int32_t ret = 0;
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	/* sanity check byte count */
88*91f16700Schasinglulu 	if ((num_bytes > MAX_TRANSFER_SIZE) || ((num_bytes & 0x3U) != U(0))) {
89*91f16700Schasinglulu 		ret = -EINVAL;
90*91f16700Schasinglulu 	}
91*91f16700Schasinglulu 
92*91f16700Schasinglulu 	/* initialise GPCDMA block */
93*91f16700Schasinglulu 	if (!init_done) {
94*91f16700Schasinglulu 		tegra_gpcdma_init();
95*91f16700Schasinglulu 		init_done = true;
96*91f16700Schasinglulu 	}
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	/* make sure channel isn't busy */
99*91f16700Schasinglulu 	val = tegra_gpcdma_read32(DMA_CH_STAT);
100*91f16700Schasinglulu 	if ((val & DMA_CH_STAT_BUSY) == DMA_CH_STAT_BUSY) {
101*91f16700Schasinglulu 		ERROR("DMA channel is busy\n");
102*91f16700Schasinglulu 		ret = -EBUSY;
103*91f16700Schasinglulu 	}
104*91f16700Schasinglulu 
105*91f16700Schasinglulu 	if (ret == 0) {
106*91f16700Schasinglulu 
107*91f16700Schasinglulu 		/* disable any DMA transfers */
108*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_CSR, 0);
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 		/* enable DMA access to TZDRAM */
111*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_ENABLE);
112*91f16700Schasinglulu 
113*91f16700Schasinglulu 		/* configure MC sequencer */
114*91f16700Schasinglulu 		val = (DMA_CH_MC_SEQ_REQ_CNT_VAL << DMA_CH_MC_SEQ_REQ_CNT_SHIFT) |
115*91f16700Schasinglulu 		      (DMA_CH_MC_SEQ_BURST_16_WORDS << DMA_CH_MC_SEQ_BURST_SHIFT);
116*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_MC_SEQ, val);
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 		/* reset fixed pattern */
119*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_FIXED_PATTERN, 0);
120*91f16700Schasinglulu 
121*91f16700Schasinglulu 		/* populate src and dst address registers */
122*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_SRC_PTR, (uint32_t)src_addr);
123*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_DST_PTR, (uint32_t)dst_addr);
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 		val = (uint32_t)((src_addr >> 32) & DMA_CH_HI_ADR_PTR_SRC_MASK);
126*91f16700Schasinglulu 		val |= (uint32_t)(((dst_addr >> 32) & DMA_CH_HI_ADR_PTR_DST_MASK) <<
127*91f16700Schasinglulu 			DMA_CH_HI_ADR_PTR_DST_SHIFT);
128*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_HI_ADR_PTR, val);
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 		/* transfer size (in words) */
131*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_WORD_COUNT, ((num_bytes >> 2) - 1U));
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 		/* populate value for CSR */
134*91f16700Schasinglulu 		val = (mode << DMA_CH_CSR_XFER_MODE_SHIFT) |
135*91f16700Schasinglulu 		      DMA_CH_CSR_RUN_ONCE | (U(1) << DMA_CH_CSR_WEIGHT_SHIFT) |
136*91f16700Schasinglulu 		      DMA_CH_CSR_IRQ_MASK_ENABLE;
137*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_CSR, val);
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 		/* enable transfer */
140*91f16700Schasinglulu 		val = tegra_gpcdma_read32(DMA_CH_CSR);
141*91f16700Schasinglulu 		val |= DMA_CH_CSR_ENABLE;
142*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_CSR, val);
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 		/* wait till transfer completes */
145*91f16700Schasinglulu 		do {
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 			/* read the status */
148*91f16700Schasinglulu 			val = tegra_gpcdma_read32(DMA_CH_STAT);
149*91f16700Schasinglulu 			if ((val & DMA_CH_STAT_BUSY) != DMA_CH_STAT_BUSY) {
150*91f16700Schasinglulu 				break;
151*91f16700Schasinglulu 			}
152*91f16700Schasinglulu 
153*91f16700Schasinglulu 			mdelay(1);
154*91f16700Schasinglulu 			timeout++;
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 		} while (timeout < GPCDMA_TIMEOUT_MS);
157*91f16700Schasinglulu 
158*91f16700Schasinglulu 		/* flag timeout error */
159*91f16700Schasinglulu 		if (timeout == GPCDMA_TIMEOUT_MS) {
160*91f16700Schasinglulu 			ERROR("DMA transfer timed out\n");
161*91f16700Schasinglulu 		}
162*91f16700Schasinglulu 
163*91f16700Schasinglulu 		dsbsy();
164*91f16700Schasinglulu 
165*91f16700Schasinglulu 		/* disable DMA access to TZDRAM */
166*91f16700Schasinglulu 		tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_DISABLE);
167*91f16700Schasinglulu 		isb();
168*91f16700Schasinglulu 	}
169*91f16700Schasinglulu }
170*91f16700Schasinglulu 
171*91f16700Schasinglulu /*******************************************************************************
172*91f16700Schasinglulu  * Memcpy using GPCDMA block (Mem2Mem copy)
173*91f16700Schasinglulu  ******************************************************************************/
174*91f16700Schasinglulu void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr,
175*91f16700Schasinglulu 			 uint32_t num_bytes)
176*91f16700Schasinglulu {
177*91f16700Schasinglulu 	tegra_gpcdma_memcpy_priv(dst_addr, src_addr, num_bytes,
178*91f16700Schasinglulu 				 DMA_CH_CSR_DMA_MODE_MEM2MEM);
179*91f16700Schasinglulu }
180*91f16700Schasinglulu 
181*91f16700Schasinglulu /*******************************************************************************
182*91f16700Schasinglulu  * Memset using GPCDMA block (Fixed pattern write)
183*91f16700Schasinglulu  ******************************************************************************/
184*91f16700Schasinglulu void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes)
185*91f16700Schasinglulu {
186*91f16700Schasinglulu 	tegra_gpcdma_memcpy_priv(dst_addr, 0, num_bytes,
187*91f16700Schasinglulu 				 DMA_CH_CSR_DMA_MODE_FIXEDPATTERN);
188*91f16700Schasinglulu }
189