blob: 26b64c8b34c42f0600e4ca22b93e5250a1610189 [file] [log] [blame]
Angel Ponsa2ee7612020-04-04 18:51:15 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgi40a3e322015-06-22 19:41:29 +02002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Patrick Georgi40a3e322015-06-22 19:41:29 +02004#include <console/console.h>
Jacob Garber5cf9ccc2019-08-08 13:35:31 -06005#include <stdint.h>
Patrick Georgi40a3e322015-06-22 19:41:29 +02006#include <soc/addressmap.h>
7#include <soc/dma.h>
Patrick Georgi40a3e322015-06-22 19:41:29 +02008
9struct apb_dma * const apb_dma = (struct apb_dma *)TEGRA_APB_DMA_BASE;
10
11#define APB_DMA_OFFSET(n) \
12 (struct apb_dma_channel_regs *)(TEGRA_APB_DMA_BASE + n)
13struct apb_dma_channel apb_dma_channels[] = {
14 { .num = 0, .regs = APB_DMA_OFFSET(0x1000) },
15 { .num = 1, .regs = APB_DMA_OFFSET(0x1040) },
16 { .num = 2, .regs = APB_DMA_OFFSET(0x1080) },
17 { .num = 3, .regs = APB_DMA_OFFSET(0x10c0) },
18 { .num = 4, .regs = APB_DMA_OFFSET(0x1100) },
19 { .num = 5, .regs = APB_DMA_OFFSET(0x1140) },
20 { .num = 6, .regs = APB_DMA_OFFSET(0x1180) },
21 { .num = 7, .regs = APB_DMA_OFFSET(0x11c0) },
22 { .num = 8, .regs = APB_DMA_OFFSET(0x1200) },
23 { .num = 9, .regs = APB_DMA_OFFSET(0x1240) },
24 { .num = 10, .regs = APB_DMA_OFFSET(0x1280) },
25 { .num = 11, .regs = APB_DMA_OFFSET(0x12c0) },
26 { .num = 12, .regs = APB_DMA_OFFSET(0x1300) },
27 { .num = 13, .regs = APB_DMA_OFFSET(0x1340) },
28 { .num = 14, .regs = APB_DMA_OFFSET(0x1380) },
29 { .num = 15, .regs = APB_DMA_OFFSET(0x13c0) },
30 { .num = 16, .regs = APB_DMA_OFFSET(0x1400) },
31 { .num = 17, .regs = APB_DMA_OFFSET(0x1440) },
32 { .num = 18, .regs = APB_DMA_OFFSET(0x1480) },
33 { .num = 19, .regs = APB_DMA_OFFSET(0x14c0) },
34 { .num = 20, .regs = APB_DMA_OFFSET(0x1500) },
35 { .num = 21, .regs = APB_DMA_OFFSET(0x1540) },
36 { .num = 22, .regs = APB_DMA_OFFSET(0x1580) },
37 { .num = 23, .regs = APB_DMA_OFFSET(0x15c0) },
38 { .num = 24, .regs = APB_DMA_OFFSET(0x1600) },
39 { .num = 25, .regs = APB_DMA_OFFSET(0x1640) },
40 { .num = 26, .regs = APB_DMA_OFFSET(0x1680) },
41 { .num = 27, .regs = APB_DMA_OFFSET(0x16c0) },
42 { .num = 28, .regs = APB_DMA_OFFSET(0x1700) },
43 { .num = 29, .regs = APB_DMA_OFFSET(0x1740) },
44 { .num = 30, .regs = APB_DMA_OFFSET(0x1780) },
45 { .num = 31, .regs = APB_DMA_OFFSET(0x17c0) },
46};
47
48int dma_busy(struct apb_dma_channel * const channel)
49{
50 /*
51 * In continuous mode, the BSY_n bit in APB_DMA_STATUS and
52 * BSY in APBDMACHAN_CHANNEL_n_STA_0 will remain set as '1' so long
53 * as the channel is enabled. So for this function we'll use the
Furquan Shaikhfe48f092015-07-13 09:48:52 -070054 * DMA_ACTIVITY bit in case of continuous mode.
55 *
56 * However, for ONCE mode, the BSY_n bit in APB_DMA_STATUS will be used
57 * to determine end of dma operation.
Patrick Georgi40a3e322015-06-22 19:41:29 +020058 */
Furquan Shaikhfe48f092015-07-13 09:48:52 -070059 uint32_t bit;
60
61 if (read32(&channel->regs->csr) & APB_CSR_ONCE)
62 /* Once mode */
63 bit = APB_STA_BSY;
64 else
65 /* Continuous mode */
66 bit = APB_STA_DMA_ACTIVITY;
67
68 return read32(&channel->regs->sta) & bit ? 1 : 0;
Patrick Georgi40a3e322015-06-22 19:41:29 +020069}
70/* claim a DMA channel */
71struct apb_dma_channel * const dma_claim(void)
72{
73 int i;
74 struct apb_dma_channel_regs *regs = NULL;
75
76 /*
77 * Set global enable bit, otherwise register access to channel
78 * DMA registers will not be possible.
79 */
Julius Werner55009af2019-12-02 22:03:27 -080080 setbits32(&apb_dma->command, APB_COMMAND_GEN);
Patrick Georgi40a3e322015-06-22 19:41:29 +020081
82 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
83 regs = apb_dma_channels[i].regs;
84
85 if (!apb_dma_channels[i].in_use) {
86 u32 status = read32(&regs->sta);
87 if (status & (1 << i)) {
88 /* FIXME: should this be fatal? */
89 printk(BIOS_DEBUG, "%s: DMA channel %d busy?\n",
90 __func__, i);
91 }
92 break;
93 }
94 }
95
96 if (i == ARRAY_SIZE(apb_dma_channels))
97 return NULL;
98
99 apb_dma_channels[i].in_use = 1;
100 return &apb_dma_channels[i];
101}
102
103/* release a DMA channel */
104void dma_release(struct apb_dma_channel * const channel)
105{
106 int i;
107
108 /* FIXME: make this "thread" friendly */
109 while (dma_busy(channel))
110 ;
111
112 channel->in_use = 0;
113
114 /* clear the global enable bit if no channels are in use */
115 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
116 if (apb_dma_channels[i].in_use)
117 return;
118 }
119
Julius Werner55009af2019-12-02 22:03:27 -0800120 clrbits32(&apb_dma->command, APB_COMMAND_GEN);
Patrick Georgi40a3e322015-06-22 19:41:29 +0200121}
122
123int dma_start(struct apb_dma_channel * const channel)
124{
125 struct apb_dma_channel_regs *regs = channel->regs;
126
127 /* Set ENB bit for this channel */
Julius Werner55009af2019-12-02 22:03:27 -0800128 setbits32(&regs->csr, APB_CSR_ENB);
Patrick Georgi40a3e322015-06-22 19:41:29 +0200129
130 return 0;
131}
132
133int dma_stop(struct apb_dma_channel * const channel)
134{
135 struct apb_dma_channel_regs *regs = channel->regs;
136
137 /* Clear ENB bit for this channel */
Julius Werner55009af2019-12-02 22:03:27 -0800138 clrbits32(&regs->csr, APB_CSR_ENB);
Patrick Georgi40a3e322015-06-22 19:41:29 +0200139
140 return 0;
141}