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