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
22static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd)
23{
24	return cd->min_signal;
25}
26
27static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch)
28{
29}
30
31/*
32 * DMA0
33 */
34
35static 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
119struct 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
138static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0,
139			0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data);
140
141/*
142 * DMA1
143 */
144
145static 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
209struct 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
228static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0,
229			0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data);
230
231static 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}
244arch_initcall(s3c64xx_pl080_init);
245