blob: 7dfe92c8968452fb3276cbc58f76623c0ec7eab5 [file] [log] [blame]
Patrick Georgi40a3e322015-06-22 19:41:29 +02001/*
2 * (C) Copyright 2010,2011
3 * NVIDIA Corporation <www.nvidia.com>
4 * Copyright 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
Patrick Georgi40a3e322015-06-22 19:41:29 +020014 */
15
16#include <arch/io.h>
17#include <console/console.h>
18#include <inttypes.h>
19#include <soc/addressmap.h>
20#include <soc/dma.h>
21#include <stddef.h>
22#include <stdlib.h>
23
24struct apb_dma * const apb_dma = (struct apb_dma *)TEGRA_APB_DMA_BASE;
25
26#define APB_DMA_OFFSET(n) \
27 (struct apb_dma_channel_regs *)(TEGRA_APB_DMA_BASE + n)
28struct apb_dma_channel apb_dma_channels[] = {
29 { .num = 0, .regs = APB_DMA_OFFSET(0x1000) },
30 { .num = 1, .regs = APB_DMA_OFFSET(0x1040) },
31 { .num = 2, .regs = APB_DMA_OFFSET(0x1080) },
32 { .num = 3, .regs = APB_DMA_OFFSET(0x10c0) },
33 { .num = 4, .regs = APB_DMA_OFFSET(0x1100) },
34 { .num = 5, .regs = APB_DMA_OFFSET(0x1140) },
35 { .num = 6, .regs = APB_DMA_OFFSET(0x1180) },
36 { .num = 7, .regs = APB_DMA_OFFSET(0x11c0) },
37 { .num = 8, .regs = APB_DMA_OFFSET(0x1200) },
38 { .num = 9, .regs = APB_DMA_OFFSET(0x1240) },
39 { .num = 10, .regs = APB_DMA_OFFSET(0x1280) },
40 { .num = 11, .regs = APB_DMA_OFFSET(0x12c0) },
41 { .num = 12, .regs = APB_DMA_OFFSET(0x1300) },
42 { .num = 13, .regs = APB_DMA_OFFSET(0x1340) },
43 { .num = 14, .regs = APB_DMA_OFFSET(0x1380) },
44 { .num = 15, .regs = APB_DMA_OFFSET(0x13c0) },
45 { .num = 16, .regs = APB_DMA_OFFSET(0x1400) },
46 { .num = 17, .regs = APB_DMA_OFFSET(0x1440) },
47 { .num = 18, .regs = APB_DMA_OFFSET(0x1480) },
48 { .num = 19, .regs = APB_DMA_OFFSET(0x14c0) },
49 { .num = 20, .regs = APB_DMA_OFFSET(0x1500) },
50 { .num = 21, .regs = APB_DMA_OFFSET(0x1540) },
51 { .num = 22, .regs = APB_DMA_OFFSET(0x1580) },
52 { .num = 23, .regs = APB_DMA_OFFSET(0x15c0) },
53 { .num = 24, .regs = APB_DMA_OFFSET(0x1600) },
54 { .num = 25, .regs = APB_DMA_OFFSET(0x1640) },
55 { .num = 26, .regs = APB_DMA_OFFSET(0x1680) },
56 { .num = 27, .regs = APB_DMA_OFFSET(0x16c0) },
57 { .num = 28, .regs = APB_DMA_OFFSET(0x1700) },
58 { .num = 29, .regs = APB_DMA_OFFSET(0x1740) },
59 { .num = 30, .regs = APB_DMA_OFFSET(0x1780) },
60 { .num = 31, .regs = APB_DMA_OFFSET(0x17c0) },
61};
62
63int dma_busy(struct apb_dma_channel * const channel)
64{
65 /*
66 * In continuous mode, the BSY_n bit in APB_DMA_STATUS and
67 * BSY in APBDMACHAN_CHANNEL_n_STA_0 will remain set as '1' so long
68 * as the channel is enabled. So for this function we'll use the
Furquan Shaikhfe48f092015-07-13 09:48:52 -070069 * DMA_ACTIVITY bit in case of continuous mode.
70 *
71 * However, for ONCE mode, the BSY_n bit in APB_DMA_STATUS will be used
72 * to determine end of dma operation.
Patrick Georgi40a3e322015-06-22 19:41:29 +020073 */
Furquan Shaikhfe48f092015-07-13 09:48:52 -070074 uint32_t bit;
75
76 if (read32(&channel->regs->csr) & APB_CSR_ONCE)
77 /* Once mode */
78 bit = APB_STA_BSY;
79 else
80 /* Continuous mode */
81 bit = APB_STA_DMA_ACTIVITY;
82
83 return read32(&channel->regs->sta) & bit ? 1 : 0;
Patrick Georgi40a3e322015-06-22 19:41:29 +020084}
85/* claim a DMA channel */
86struct apb_dma_channel * const dma_claim(void)
87{
88 int i;
89 struct apb_dma_channel_regs *regs = NULL;
90
91 /*
92 * Set global enable bit, otherwise register access to channel
93 * DMA registers will not be possible.
94 */
95 setbits_le32(&apb_dma->command, APB_COMMAND_GEN);
96
97 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
98 regs = apb_dma_channels[i].regs;
99
100 if (!apb_dma_channels[i].in_use) {
101 u32 status = read32(&regs->sta);
102 if (status & (1 << i)) {
103 /* FIXME: should this be fatal? */
104 printk(BIOS_DEBUG, "%s: DMA channel %d busy?\n",
105 __func__, i);
106 }
107 break;
108 }
109 }
110
111 if (i == ARRAY_SIZE(apb_dma_channels))
112 return NULL;
113
114 apb_dma_channels[i].in_use = 1;
115 return &apb_dma_channels[i];
116}
117
118/* release a DMA channel */
119void dma_release(struct apb_dma_channel * const channel)
120{
121 int i;
122
123 /* FIXME: make this "thread" friendly */
124 while (dma_busy(channel))
125 ;
126
127 channel->in_use = 0;
128
129 /* clear the global enable bit if no channels are in use */
130 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
131 if (apb_dma_channels[i].in_use)
132 return;
133 }
134
135 clrbits_le32(&apb_dma->command, APB_COMMAND_GEN);
136}
137
138int dma_start(struct apb_dma_channel * const channel)
139{
140 struct apb_dma_channel_regs *regs = channel->regs;
141
142 /* Set ENB bit for this channel */
143 setbits_le32(&regs->csr, APB_CSR_ENB);
144
145 return 0;
146}
147
148int dma_stop(struct apb_dma_channel * const channel)
149{
150 struct apb_dma_channel_regs *regs = channel->regs;
151
152 /* Clear ENB bit for this channel */
153 clrbits_le32(&regs->csr, APB_CSR_ENB);
154
155 return 0;
156}