1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Samsung's S3C64XX generic DMA support using amba-pl08x driver.
4 //
5 // Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
6
7 #include <linux/kernel.h>
8 #include <linux/amba/bus.h>
9 #include <linux/amba/pl080.h>
10 #include <linux/amba/pl08x.h>
11 #include <linux/of.h>
12
13 #include <plat/cpu.h>
14 #include <mach/irqs.h>
15 #include <mach/map.h>
16
17 #include "regs-sys.h"
18
pl08x_get_xfer_signal(const struct pl08x_channel_data * cd)19 static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd)
20 {
21 return cd->min_signal;
22 }
23
pl08x_put_xfer_signal(const struct pl08x_channel_data * cd,int ch)24 static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch)
25 {
26 }
27
28 /*
29 * DMA0
30 */
31
32 static struct pl08x_channel_data s3c64xx_dma0_info[] = {
33 {
34 .bus_id = "uart0_tx",
35 .min_signal = 0,
36 .max_signal = 0,
37 .periph_buses = PL08X_AHB2,
38 }, {
39 .bus_id = "uart0_rx",
40 .min_signal = 1,
41 .max_signal = 1,
42 .periph_buses = PL08X_AHB2,
43 }, {
44 .bus_id = "uart1_tx",
45 .min_signal = 2,
46 .max_signal = 2,
47 .periph_buses = PL08X_AHB2,
48 }, {
49 .bus_id = "uart1_rx",
50 .min_signal = 3,
51 .max_signal = 3,
52 .periph_buses = PL08X_AHB2,
53 }, {
54 .bus_id = "uart2_tx",
55 .min_signal = 4,
56 .max_signal = 4,
57 .periph_buses = PL08X_AHB2,
58 }, {
59 .bus_id = "uart2_rx",
60 .min_signal = 5,
61 .max_signal = 5,
62 .periph_buses = PL08X_AHB2,
63 }, {
64 .bus_id = "uart3_tx",
65 .min_signal = 6,
66 .max_signal = 6,
67 .periph_buses = PL08X_AHB2,
68 }, {
69 .bus_id = "uart3_rx",
70 .min_signal = 7,
71 .max_signal = 7,
72 .periph_buses = PL08X_AHB2,
73 }, {
74 .bus_id = "pcm0_tx",
75 .min_signal = 8,
76 .max_signal = 8,
77 .periph_buses = PL08X_AHB2,
78 }, {
79 .bus_id = "pcm0_rx",
80 .min_signal = 9,
81 .max_signal = 9,
82 .periph_buses = PL08X_AHB2,
83 }, {
84 .bus_id = "i2s0_tx",
85 .min_signal = 10,
86 .max_signal = 10,
87 .periph_buses = PL08X_AHB2,
88 }, {
89 .bus_id = "i2s0_rx",
90 .min_signal = 11,
91 .max_signal = 11,
92 .periph_buses = PL08X_AHB2,
93 }, {
94 .bus_id = "spi0_tx",
95 .min_signal = 12,
96 .max_signal = 12,
97 .periph_buses = PL08X_AHB2,
98 }, {
99 .bus_id = "spi0_rx",
100 .min_signal = 13,
101 .max_signal = 13,
102 .periph_buses = PL08X_AHB2,
103 }, {
104 .bus_id = "i2s2_tx",
105 .min_signal = 14,
106 .max_signal = 14,
107 .periph_buses = PL08X_AHB2,
108 }, {
109 .bus_id = "i2s2_rx",
110 .min_signal = 15,
111 .max_signal = 15,
112 .periph_buses = PL08X_AHB2,
113 }
114 };
115
116 static const struct dma_slave_map s3c64xx_dma0_slave_map[] = {
117 { "s3c6400-uart.0", "tx", &s3c64xx_dma0_info[0] },
118 { "s3c6400-uart.0", "rx", &s3c64xx_dma0_info[1] },
119 { "s3c6400-uart.1", "tx", &s3c64xx_dma0_info[2] },
120 { "s3c6400-uart.1", "rx", &s3c64xx_dma0_info[3] },
121 { "s3c6400-uart.2", "tx", &s3c64xx_dma0_info[4] },
122 { "s3c6400-uart.2", "rx", &s3c64xx_dma0_info[5] },
123 { "s3c6400-uart.3", "tx", &s3c64xx_dma0_info[6] },
124 { "s3c6400-uart.3", "rx", &s3c64xx_dma0_info[7] },
125 { "samsung-pcm.0", "tx", &s3c64xx_dma0_info[8] },
126 { "samsung-pcm.0", "rx", &s3c64xx_dma0_info[9] },
127 { "samsung-i2s.0", "tx", &s3c64xx_dma0_info[10] },
128 { "samsung-i2s.0", "rx", &s3c64xx_dma0_info[11] },
129 { "s3c6410-spi.0", "tx", &s3c64xx_dma0_info[12] },
130 { "s3c6410-spi.0", "rx", &s3c64xx_dma0_info[13] },
131 { "samsung-i2s.2", "tx", &s3c64xx_dma0_info[14] },
132 { "samsung-i2s.2", "rx", &s3c64xx_dma0_info[15] },
133 };
134
135 struct pl08x_platform_data s3c64xx_dma0_plat_data = {
136 .memcpy_burst_size = PL08X_BURST_SZ_4,
137 .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS,
138 .memcpy_prot_buff = true,
139 .memcpy_prot_cache = true,
140 .lli_buses = PL08X_AHB1,
141 .mem_buses = PL08X_AHB1,
142 .get_xfer_signal = pl08x_get_xfer_signal,
143 .put_xfer_signal = pl08x_put_xfer_signal,
144 .slave_channels = s3c64xx_dma0_info,
145 .num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info),
146 .slave_map = s3c64xx_dma0_slave_map,
147 .slave_map_len = ARRAY_SIZE(s3c64xx_dma0_slave_map),
148 };
149
150 static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0,
151 0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data);
152
153 /*
154 * DMA1
155 */
156
157 static struct pl08x_channel_data s3c64xx_dma1_info[] = {
158 {
159 .bus_id = "pcm1_tx",
160 .min_signal = 0,
161 .max_signal = 0,
162 .periph_buses = PL08X_AHB2,
163 }, {
164 .bus_id = "pcm1_rx",
165 .min_signal = 1,
166 .max_signal = 1,
167 .periph_buses = PL08X_AHB2,
168 }, {
169 .bus_id = "i2s1_tx",
170 .min_signal = 2,
171 .max_signal = 2,
172 .periph_buses = PL08X_AHB2,
173 }, {
174 .bus_id = "i2s1_rx",
175 .min_signal = 3,
176 .max_signal = 3,
177 .periph_buses = PL08X_AHB2,
178 }, {
179 .bus_id = "spi1_tx",
180 .min_signal = 4,
181 .max_signal = 4,
182 .periph_buses = PL08X_AHB2,
183 }, {
184 .bus_id = "spi1_rx",
185 .min_signal = 5,
186 .max_signal = 5,
187 .periph_buses = PL08X_AHB2,
188 }, {
189 .bus_id = "ac97_out",
190 .min_signal = 6,
191 .max_signal = 6,
192 .periph_buses = PL08X_AHB2,
193 }, {
194 .bus_id = "ac97_in",
195 .min_signal = 7,
196 .max_signal = 7,
197 .periph_buses = PL08X_AHB2,
198 }, {
199 .bus_id = "ac97_mic",
200 .min_signal = 8,
201 .max_signal = 8,
202 .periph_buses = PL08X_AHB2,
203 }, {
204 .bus_id = "pwm",
205 .min_signal = 9,
206 .max_signal = 9,
207 .periph_buses = PL08X_AHB2,
208 }, {
209 .bus_id = "irda",
210 .min_signal = 10,
211 .max_signal = 10,
212 .periph_buses = PL08X_AHB2,
213 }, {
214 .bus_id = "external",
215 .min_signal = 11,
216 .max_signal = 11,
217 .periph_buses = PL08X_AHB2,
218 },
219 };
220
221 static const struct dma_slave_map s3c64xx_dma1_slave_map[] = {
222 { "samsung-pcm.1", "tx", &s3c64xx_dma1_info[0] },
223 { "samsung-pcm.1", "rx", &s3c64xx_dma1_info[1] },
224 { "samsung-i2s.1", "tx", &s3c64xx_dma1_info[2] },
225 { "samsung-i2s.1", "rx", &s3c64xx_dma1_info[3] },
226 { "s3c6410-spi.1", "tx", &s3c64xx_dma1_info[4] },
227 { "s3c6410-spi.1", "rx", &s3c64xx_dma1_info[5] },
228 };
229
230 struct pl08x_platform_data s3c64xx_dma1_plat_data = {
231 .memcpy_burst_size = PL08X_BURST_SZ_4,
232 .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS,
233 .memcpy_prot_buff = true,
234 .memcpy_prot_cache = true,
235 .lli_buses = PL08X_AHB1,
236 .mem_buses = PL08X_AHB1,
237 .get_xfer_signal = pl08x_get_xfer_signal,
238 .put_xfer_signal = pl08x_put_xfer_signal,
239 .slave_channels = s3c64xx_dma1_info,
240 .num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info),
241 .slave_map = s3c64xx_dma1_slave_map,
242 .slave_map_len = ARRAY_SIZE(s3c64xx_dma1_slave_map),
243 };
244
245 static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0,
246 0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data);
247
s3c64xx_pl080_init(void)248 static int __init s3c64xx_pl080_init(void)
249 {
250 if (!soc_is_s3c64xx())
251 return 0;
252
253 /* Set all DMA configuration to be DMA, not SDMA */
254 writel(0xffffff, S3C64XX_SDMA_SEL);
255
256 if (of_have_populated_dt())
257 return 0;
258
259 amba_device_register(&s3c64xx_dma0_device, &iomem_resource);
260 amba_device_register(&s3c64xx_dma1_device, &iomem_resource);
261
262 return 0;
263 }
264 arch_initcall(s3c64xx_pl080_init);
265