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