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 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 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 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 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 ******************************************************************************/ 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 ******************************************************************************/ 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