• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <console/console.h>
5 #include <stdint.h>
6 #include <soc/addressmap.h>
7 #include <soc/dma.h>
8 
9 struct 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)
13 struct 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 
dma_busy(struct apb_dma_channel * const channel)48 int 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 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.
58 	 */
59 	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;
69 }
70 /* claim a DMA channel */
dma_claim(void)71 struct 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 	 */
80 	setbits32(&apb_dma->command, APB_COMMAND_GEN);
81 
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 */
dma_release(struct apb_dma_channel * const channel)104 void 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 
120 	clrbits32(&apb_dma->command, APB_COMMAND_GEN);
121 }
122 
dma_start(struct apb_dma_channel * const channel)123 int 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 */
128 	setbits32(&regs->csr, APB_CSR_ENB);
129 
130 	return 0;
131 }
132 
dma_stop(struct apb_dma_channel * const channel)133 int 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 */
138 	clrbits32(&regs->csr, APB_CSR_ENB);
139 
140 	return 0;
141 }
142