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