blob: 167f4a12294efe80ffecae7a619d79cbd1773d40 [file] [log] [blame]
Angel Ponsa2ee7612020-04-04 18:51:15 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Gabe Blackd40be112013-10-09 23:45:07 -07002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -07004#include <console/console.h>
Jacob Garber5cf9ccc2019-08-08 13:35:31 -06005#include <stdint.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -07006#include <soc/addressmap.h>
7#include <soc/dma.h>
Gabe Blackd40be112013-10-09 23:45:07 -07008
Gabe Blackd40be112013-10-09 23:45:07 -07009struct apb_dma * const apb_dma = (struct apb_dma *)TEGRA_APB_DMA_BASE;
10
Gabe Blackd40be112013-10-09 23:45:07 -070011#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
54 * DMA_ACTIVITY bit.
55 */
Julius Werneredf6b572013-10-25 17:49:26 -070056 return read32(&channel->regs->sta) & APB_STA_DMA_ACTIVITY ? 1 : 0;
Gabe Blackd40be112013-10-09 23:45:07 -070057}
58/* claim a DMA channel */
59struct apb_dma_channel * const dma_claim(void)
60{
61 int i;
62 struct apb_dma_channel_regs *regs = NULL;
63
64 /*
65 * Set global enable bit, otherwise register access to channel
66 * DMA registers will not be possible.
67 */
Julius Werner55009af2019-12-02 22:03:27 -080068 setbits32(&apb_dma->command, APB_COMMAND_GEN);
Gabe Blackd40be112013-10-09 23:45:07 -070069
70 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
71 regs = apb_dma_channels[i].regs;
72
73 if (!apb_dma_channels[i].in_use) {
74 u32 status = read32(&regs->sta);
75 if (status & (1 << i)) {
76 /* FIXME: should this be fatal? */
77 printk(BIOS_DEBUG, "%s: DMA channel %d busy?\n",
78 __func__, i);
79 }
80 break;
81 }
82 }
83
84 if (i == ARRAY_SIZE(apb_dma_channels))
85 return NULL;
86
87 apb_dma_channels[i].in_use = 1;
88 return &apb_dma_channels[i];
89}
90
91/* release a DMA channel */
92void dma_release(struct apb_dma_channel * const channel)
93{
94 int i;
95
96 /* FIXME: make this "thread" friendly */
97 while (dma_busy(channel))
98 ;
99
100 channel->in_use = 0;
101
102 /* clear the global enable bit if no channels are in use */
103 for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
104 if (apb_dma_channels[i].in_use)
105 return;
106 }
107
Julius Werner55009af2019-12-02 22:03:27 -0800108 clrbits32(&apb_dma->command, APB_COMMAND_GEN);
Gabe Blackd40be112013-10-09 23:45:07 -0700109}
110
111int dma_start(struct apb_dma_channel * const channel)
112{
113 struct apb_dma_channel_regs *regs = channel->regs;
114
115 /* Set ENB bit for this channel */
Julius Werner55009af2019-12-02 22:03:27 -0800116 setbits32(&regs->csr, APB_CSR_ENB);
Gabe Blackd40be112013-10-09 23:45:07 -0700117
118 return 0;
119}
120
121int dma_stop(struct apb_dma_channel * const channel)
122{
123 struct apb_dma_channel_regs *regs = channel->regs;
124
125 /* Clear ENB bit for this channel */
Julius Werner55009af2019-12-02 22:03:27 -0800126 clrbits32(&regs->csr, APB_CSR_ENB);
Gabe Blackd40be112013-10-09 23:45:07 -0700127
128 return 0;
129}