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