aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-04 21:02:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-04 21:02:25 -0400
commitfba9569924e06da076cb2ad12474bbd82d69f54d (patch)
treef0b7d9c82f8dd90f0dc757a4c00afc0872fc1484 /arch
parent3d0a8d10cfb4cc3d1877c29a866ee7d8a46aa2fa (diff)
parent4598fc2c94b68740e0269db03c98a1e7ad5af773 (diff)
Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
* 'next' of git://git.infradead.org/users/vkoul/slave-dma: (63 commits) dmaengine: mid_dma: mask_peripheral_interrupt only when dmac is idle dmaengine/ep93xx_dma: add module.h include pch_dma: Reduce wasting memory pch_dma: Fix suspend issue dma/timberdale: free_irq() on an error path dma: shdma: transfer based runtime PM dmaengine: shdma: protect against the IRQ handler dmaengine i.MX DMA/SDMA: add missing include of linux/module.h dmaengine: delete redundant chan_id and chancnt initialization in dma drivers dmaengine/amba-pl08x: Check txd->llis_va before freeing dma_pool dmaengine/amba-pl08x: Add support for sg len greater than one for slave transfers serial: sh-sci: don't filter on DMA device, use only channel ID ARM: SAMSUNG: Remove Samsung specific enum type for dma direction ASoC: Samsung: Update DMA interface spi/s3c64xx: Merge dma control code spi/s3c64xx: Add support DMA engine API ARM: SAMSUNG: Remove S3C-PL330-DMA driver ARM: S5P64X0: Use generic DMA PL330 driver ARM: S5PC100: Use generic DMA PL330 driver ARM: S5PV210: Use generic DMA PL330 driver ... Fix up fairly trivial conflicts in - arch/arm/mach-exynos4/{Kconfig,clock.c} - arch/arm/mach-s5p64x0/dma.c
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/hardware/pl080.h4
-rw-r--r--arch/arm/mach-exynos4/Kconfig2
-rw-r--r--arch/arm/mach-exynos4/clock.c14
-rw-r--r--arch/arm/mach-exynos4/dma.c299
-rw-r--r--arch/arm/mach-exynos4/include/mach/dma.h4
-rw-r--r--arch/arm/mach-s3c2410/include/mach/dma.h20
-rw-r--r--arch/arm/mach-s3c2412/dma.c4
-rw-r--r--arch/arm/mach-s3c64xx/dma.c10
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/dma.h8
-rw-r--r--arch/arm/mach-s5p64x0/Kconfig4
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6440.c9
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6450.c9
-rw-r--r--arch/arm/mach-s5p64x0/dma.c269
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/dma.h4
-rw-r--r--arch/arm/mach-s5pc100/Kconfig2
-rw-r--r--arch/arm/mach-s5pc100/clock.c11
-rw-r--r--arch/arm/mach-s5pc100/dma.c323
-rw-r--r--arch/arm/mach-s5pc100/include/mach/dma.h4
-rw-r--r--arch/arm/mach-s5pv210/Kconfig2
-rw-r--r--arch/arm/mach-s5pv210/clock.c10
-rw-r--r--arch/arm/mach-s5pv210/dma.c316
-rw-r--r--arch/arm/mach-s5pv210/include/mach/dma.h4
-rw-r--r--arch/arm/plat-s3c24xx/dma.c10
-rw-r--r--arch/arm/plat-samsung/Kconfig9
-rw-r--r--arch/arm/plat-samsung/Makefile4
-rw-r--r--arch/arm/plat-samsung/dma-ops.c131
-rw-r--r--arch/arm/plat-samsung/include/plat/dma-ops.h63
-rw-r--r--arch/arm/plat-samsung/include/plat/dma-pl330.h (renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h)24
-rw-r--r--arch/arm/plat-samsung/include/plat/dma-s3c24xx.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/dma.h10
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h32
-rw-r--r--arch/arm/plat-samsung/s3c-dma-ops.c130
-rw-r--r--arch/arm/plat-samsung/s3c-pl330.c1244
33 files changed, 1229 insertions, 1762 deletions
diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h
index e4a04e4e5627..33c78d7af2e1 100644
--- a/arch/arm/include/asm/hardware/pl080.h
+++ b/arch/arm/include/asm/hardware/pl080.h
@@ -21,6 +21,9 @@
21 * OneNAND features. 21 * OneNAND features.
22*/ 22*/
23 23
24#ifndef ASM_PL080_H
25#define ASM_PL080_H
26
24#define PL080_INT_STATUS (0x00) 27#define PL080_INT_STATUS (0x00)
25#define PL080_TC_STATUS (0x04) 28#define PL080_TC_STATUS (0x04)
26#define PL080_TC_CLEAR (0x08) 29#define PL080_TC_CLEAR (0x08)
@@ -138,3 +141,4 @@ struct pl080s_lli {
138 u32 control1; 141 u32 control1;
139}; 142};
140 143
144#endif /* ASM_PL080_H */
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index a65273598036..44013e0672fe 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
11 11
12config CPU_EXYNOS4210 12config CPU_EXYNOS4210
13 bool 13 bool
14 select S3C_PL330_DMA 14 select SAMSUNG_DMADEV
15 select ARM_CPU_SUSPEND if PM 15 select ARM_CPU_SUSPEND if PM
16 help 16 help
17 Enable EXYNOS4210 CPU support 17 Enable EXYNOS4210 CPU support
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 0d59be3fa1fe..e21952dfb7e1 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -111,6 +111,11 @@ struct clk clk_sclk_usbphy1 = {
111 .name = "sclk_usbphy1", 111 .name = "sclk_usbphy1",
112}; 112};
113 113
114static struct clk dummy_apb_pclk = {
115 .name = "apb_pclk",
116 .id = -1,
117};
118
114static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable) 119static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
115{ 120{
116 return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable); 121 return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
@@ -503,12 +508,12 @@ static struct clk init_clocks_off[] = {
503 .enable = exynos4_clk_ip_fsys_ctrl, 508 .enable = exynos4_clk_ip_fsys_ctrl,
504 .ctrlbit = (1 << 9), 509 .ctrlbit = (1 << 9),
505 }, { 510 }, {
506 .name = "pdma", 511 .name = "dma",
507 .devname = "s3c-pl330.0", 512 .devname = "s3c-pl330.0",
508 .enable = exynos4_clk_ip_fsys_ctrl, 513 .enable = exynos4_clk_ip_fsys_ctrl,
509 .ctrlbit = (1 << 0), 514 .ctrlbit = (1 << 0),
510 }, { 515 }, {
511 .name = "pdma", 516 .name = "dma",
512 .devname = "s3c-pl330.1", 517 .devname = "s3c-pl330.1",
513 .enable = exynos4_clk_ip_fsys_ctrl, 518 .enable = exynos4_clk_ip_fsys_ctrl,
514 .ctrlbit = (1 << 1), 519 .ctrlbit = (1 << 1),
@@ -1281,6 +1286,11 @@ void __init exynos4_register_clocks(void)
1281 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1286 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1282 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1287 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1283 1288
1289<<<<<<< HEAD
1284 register_syscore_ops(&exynos4_clock_syscore_ops); 1290 register_syscore_ops(&exynos4_clock_syscore_ops);
1291=======
1292 s3c24xx_register_clock(&dummy_apb_pclk);
1293
1294>>>>>>> 4598fc2c94b68740e0269db03c98a1e7ad5af773
1285 s3c_pwmclk_init(); 1295 s3c_pwmclk_init();
1286} 1296}
diff --git a/arch/arm/mach-exynos4/dma.c b/arch/arm/mach-exynos4/dma.c
index 564bb530f332..d57d66255021 100644
--- a/arch/arm/mach-exynos4/dma.c
+++ b/arch/arm/mach-exynos4/dma.c
@@ -21,151 +21,228 @@
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */ 22 */
23 23
24#include <linux/platform_device.h>
25#include <linux/dma-mapping.h> 24#include <linux/dma-mapping.h>
25#include <linux/amba/bus.h>
26#include <linux/amba/pl330.h>
26 27
28#include <asm/irq.h>
27#include <plat/devs.h> 29#include <plat/devs.h>
28#include <plat/irqs.h> 30#include <plat/irqs.h>
29 31
30#include <mach/map.h> 32#include <mach/map.h>
31#include <mach/irqs.h> 33#include <mach/irqs.h>
32 34#include <mach/dma.h>
33#include <plat/s3c-pl330-pdata.h>
34 35
35static u64 dma_dmamask = DMA_BIT_MASK(32); 36static u64 dma_dmamask = DMA_BIT_MASK(32);
36 37
37static struct resource exynos4_pdma0_resource[] = { 38struct dma_pl330_peri pdma0_peri[28] = {
38 [0] = { 39 {
39 .start = EXYNOS4_PA_PDMA0, 40 .peri_id = (u8)DMACH_PCM0_RX,
40 .end = EXYNOS4_PA_PDMA0 + SZ_4K, 41 .rqtype = DEVTOMEM,
41 .flags = IORESOURCE_MEM, 42 }, {
42 }, 43 .peri_id = (u8)DMACH_PCM0_TX,
43 [1] = { 44 .rqtype = MEMTODEV,
44 .start = IRQ_PDMA0, 45 }, {
45 .end = IRQ_PDMA0, 46 .peri_id = (u8)DMACH_PCM2_RX,
46 .flags = IORESOURCE_IRQ, 47 .rqtype = DEVTOMEM,
48 }, {
49 .peri_id = (u8)DMACH_PCM2_TX,
50 .rqtype = MEMTODEV,
51 }, {
52 .peri_id = (u8)DMACH_MSM_REQ0,
53 }, {
54 .peri_id = (u8)DMACH_MSM_REQ2,
55 }, {
56 .peri_id = (u8)DMACH_SPI0_RX,
57 .rqtype = DEVTOMEM,
58 }, {
59 .peri_id = (u8)DMACH_SPI0_TX,
60 .rqtype = MEMTODEV,
61 }, {
62 .peri_id = (u8)DMACH_SPI2_RX,
63 .rqtype = DEVTOMEM,
64 }, {
65 .peri_id = (u8)DMACH_SPI2_TX,
66 .rqtype = MEMTODEV,
67 }, {
68 .peri_id = (u8)DMACH_I2S0S_TX,
69 .rqtype = MEMTODEV,
70 }, {
71 .peri_id = (u8)DMACH_I2S0_RX,
72 .rqtype = DEVTOMEM,
73 }, {
74 .peri_id = (u8)DMACH_I2S0_TX,
75 .rqtype = MEMTODEV,
76 }, {
77 .peri_id = (u8)DMACH_UART0_RX,
78 .rqtype = DEVTOMEM,
79 }, {
80 .peri_id = (u8)DMACH_UART0_TX,
81 .rqtype = MEMTODEV,
82 }, {
83 .peri_id = (u8)DMACH_UART2_RX,
84 .rqtype = DEVTOMEM,
85 }, {
86 .peri_id = (u8)DMACH_UART2_TX,
87 .rqtype = MEMTODEV,
88 }, {
89 .peri_id = (u8)DMACH_UART4_RX,
90 .rqtype = DEVTOMEM,
91 }, {
92 .peri_id = (u8)DMACH_UART4_TX,
93 .rqtype = MEMTODEV,
94 }, {
95 .peri_id = (u8)DMACH_SLIMBUS0_RX,
96 .rqtype = DEVTOMEM,
97 }, {
98 .peri_id = (u8)DMACH_SLIMBUS0_TX,
99 .rqtype = MEMTODEV,
100 }, {
101 .peri_id = (u8)DMACH_SLIMBUS2_RX,
102 .rqtype = DEVTOMEM,
103 }, {
104 .peri_id = (u8)DMACH_SLIMBUS2_TX,
105 .rqtype = MEMTODEV,
106 }, {
107 .peri_id = (u8)DMACH_SLIMBUS4_RX,
108 .rqtype = DEVTOMEM,
109 }, {
110 .peri_id = (u8)DMACH_SLIMBUS4_TX,
111 .rqtype = MEMTODEV,
112 }, {
113 .peri_id = (u8)DMACH_AC97_MICIN,
114 .rqtype = DEVTOMEM,
115 }, {
116 .peri_id = (u8)DMACH_AC97_PCMIN,
117 .rqtype = DEVTOMEM,
118 }, {
119 .peri_id = (u8)DMACH_AC97_PCMOUT,
120 .rqtype = MEMTODEV,
47 }, 121 },
48}; 122};
49 123
50static struct s3c_pl330_platdata exynos4_pdma0_pdata = { 124struct dma_pl330_platdata exynos4_pdma0_pdata = {
51 .peri = { 125 .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
52 [0] = DMACH_PCM0_RX, 126 .peri = pdma0_peri,
53 [1] = DMACH_PCM0_TX,
54 [2] = DMACH_PCM2_RX,
55 [3] = DMACH_PCM2_TX,
56 [4] = DMACH_MSM_REQ0,
57 [5] = DMACH_MSM_REQ2,
58 [6] = DMACH_SPI0_RX,
59 [7] = DMACH_SPI0_TX,
60 [8] = DMACH_SPI2_RX,
61 [9] = DMACH_SPI2_TX,
62 [10] = DMACH_I2S0S_TX,
63 [11] = DMACH_I2S0_RX,
64 [12] = DMACH_I2S0_TX,
65 [13] = DMACH_I2S2_RX,
66 [14] = DMACH_I2S2_TX,
67 [15] = DMACH_UART0_RX,
68 [16] = DMACH_UART0_TX,
69 [17] = DMACH_UART2_RX,
70 [18] = DMACH_UART2_TX,
71 [19] = DMACH_UART4_RX,
72 [20] = DMACH_UART4_TX,
73 [21] = DMACH_SLIMBUS0_RX,
74 [22] = DMACH_SLIMBUS0_TX,
75 [23] = DMACH_SLIMBUS2_RX,
76 [24] = DMACH_SLIMBUS2_TX,
77 [25] = DMACH_SLIMBUS4_RX,
78 [26] = DMACH_SLIMBUS4_TX,
79 [27] = DMACH_AC97_MICIN,
80 [28] = DMACH_AC97_PCMIN,
81 [29] = DMACH_AC97_PCMOUT,
82 [30] = DMACH_MAX,
83 [31] = DMACH_MAX,
84 },
85}; 127};
86 128
87static struct platform_device exynos4_device_pdma0 = { 129struct amba_device exynos4_device_pdma0 = {
88 .name = "s3c-pl330", 130 .dev = {
89 .id = 0, 131 .init_name = "dma-pl330.0",
90 .num_resources = ARRAY_SIZE(exynos4_pdma0_resource),
91 .resource = exynos4_pdma0_resource,
92 .dev = {
93 .dma_mask = &dma_dmamask, 132 .dma_mask = &dma_dmamask,
94 .coherent_dma_mask = DMA_BIT_MASK(32), 133 .coherent_dma_mask = DMA_BIT_MASK(32),
95 .platform_data = &exynos4_pdma0_pdata, 134 .platform_data = &exynos4_pdma0_pdata,
96 }, 135 },
136 .res = {
137 .start = EXYNOS4_PA_PDMA0,
138 .end = EXYNOS4_PA_PDMA0 + SZ_4K,
139 .flags = IORESOURCE_MEM,
140 },
141 .irq = {IRQ_PDMA0, NO_IRQ},
142 .periphid = 0x00041330,
97}; 143};
98 144
99static struct resource exynos4_pdma1_resource[] = { 145struct dma_pl330_peri pdma1_peri[25] = {
100 [0] = { 146 {
101 .start = EXYNOS4_PA_PDMA1, 147 .peri_id = (u8)DMACH_PCM0_RX,
102 .end = EXYNOS4_PA_PDMA1 + SZ_4K, 148 .rqtype = DEVTOMEM,
103 .flags = IORESOURCE_MEM, 149 }, {
104 }, 150 .peri_id = (u8)DMACH_PCM0_TX,
105 [1] = { 151 .rqtype = MEMTODEV,
106 .start = IRQ_PDMA1, 152 }, {
107 .end = IRQ_PDMA1, 153 .peri_id = (u8)DMACH_PCM1_RX,
108 .flags = IORESOURCE_IRQ, 154 .rqtype = DEVTOMEM,
155 }, {
156 .peri_id = (u8)DMACH_PCM1_TX,
157 .rqtype = MEMTODEV,
158 }, {
159 .peri_id = (u8)DMACH_MSM_REQ1,
160 }, {
161 .peri_id = (u8)DMACH_MSM_REQ3,
162 }, {
163 .peri_id = (u8)DMACH_SPI1_RX,
164 .rqtype = DEVTOMEM,
165 }, {
166 .peri_id = (u8)DMACH_SPI1_TX,
167 .rqtype = MEMTODEV,
168 }, {
169 .peri_id = (u8)DMACH_I2S0S_TX,
170 .rqtype = MEMTODEV,
171 }, {
172 .peri_id = (u8)DMACH_I2S0_RX,
173 .rqtype = DEVTOMEM,
174 }, {
175 .peri_id = (u8)DMACH_I2S0_TX,
176 .rqtype = MEMTODEV,
177 }, {
178 .peri_id = (u8)DMACH_I2S1_RX,
179 .rqtype = DEVTOMEM,
180 }, {
181 .peri_id = (u8)DMACH_I2S1_TX,
182 .rqtype = MEMTODEV,
183 }, {
184 .peri_id = (u8)DMACH_UART0_RX,
185 .rqtype = DEVTOMEM,
186 }, {
187 .peri_id = (u8)DMACH_UART0_TX,
188 .rqtype = MEMTODEV,
189 }, {
190 .peri_id = (u8)DMACH_UART1_RX,
191 .rqtype = DEVTOMEM,
192 }, {
193 .peri_id = (u8)DMACH_UART1_TX,
194 .rqtype = MEMTODEV,
195 }, {
196 .peri_id = (u8)DMACH_UART3_RX,
197 .rqtype = DEVTOMEM,
198 }, {
199 .peri_id = (u8)DMACH_UART3_TX,
200 .rqtype = MEMTODEV,
201 }, {
202 .peri_id = (u8)DMACH_SLIMBUS1_RX,
203 .rqtype = DEVTOMEM,
204 }, {
205 .peri_id = (u8)DMACH_SLIMBUS1_TX,
206 .rqtype = MEMTODEV,
207 }, {
208 .peri_id = (u8)DMACH_SLIMBUS3_RX,
209 .rqtype = DEVTOMEM,
210 }, {
211 .peri_id = (u8)DMACH_SLIMBUS3_TX,
212 .rqtype = MEMTODEV,
213 }, {
214 .peri_id = (u8)DMACH_SLIMBUS5_RX,
215 .rqtype = DEVTOMEM,
216 }, {
217 .peri_id = (u8)DMACH_SLIMBUS5_TX,
218 .rqtype = MEMTODEV,
109 }, 219 },
110}; 220};
111 221
112static struct s3c_pl330_platdata exynos4_pdma1_pdata = { 222struct dma_pl330_platdata exynos4_pdma1_pdata = {
113 .peri = { 223 .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
114 [0] = DMACH_PCM0_RX, 224 .peri = pdma1_peri,
115 [1] = DMACH_PCM0_TX,
116 [2] = DMACH_PCM1_RX,
117 [3] = DMACH_PCM1_TX,
118 [4] = DMACH_MSM_REQ1,
119 [5] = DMACH_MSM_REQ3,
120 [6] = DMACH_SPI1_RX,
121 [7] = DMACH_SPI1_TX,
122 [8] = DMACH_I2S0S_TX,
123 [9] = DMACH_I2S0_RX,
124 [10] = DMACH_I2S0_TX,
125 [11] = DMACH_I2S1_RX,
126 [12] = DMACH_I2S1_TX,
127 [13] = DMACH_UART0_RX,
128 [14] = DMACH_UART0_TX,
129 [15] = DMACH_UART1_RX,
130 [16] = DMACH_UART1_TX,
131 [17] = DMACH_UART3_RX,
132 [18] = DMACH_UART3_TX,
133 [19] = DMACH_SLIMBUS1_RX,
134 [20] = DMACH_SLIMBUS1_TX,
135 [21] = DMACH_SLIMBUS3_RX,
136 [22] = DMACH_SLIMBUS3_TX,
137 [23] = DMACH_SLIMBUS5_RX,
138 [24] = DMACH_SLIMBUS5_TX,
139 [25] = DMACH_SLIMBUS0AUX_RX,
140 [26] = DMACH_SLIMBUS0AUX_TX,
141 [27] = DMACH_SPDIF,
142 [28] = DMACH_MAX,
143 [29] = DMACH_MAX,
144 [30] = DMACH_MAX,
145 [31] = DMACH_MAX,
146 },
147}; 225};
148 226
149static struct platform_device exynos4_device_pdma1 = { 227struct amba_device exynos4_device_pdma1 = {
150 .name = "s3c-pl330", 228 .dev = {
151 .id = 1, 229 .init_name = "dma-pl330.1",
152 .num_resources = ARRAY_SIZE(exynos4_pdma1_resource),
153 .resource = exynos4_pdma1_resource,
154 .dev = {
155 .dma_mask = &dma_dmamask, 230 .dma_mask = &dma_dmamask,
156 .coherent_dma_mask = DMA_BIT_MASK(32), 231 .coherent_dma_mask = DMA_BIT_MASK(32),
157 .platform_data = &exynos4_pdma1_pdata, 232 .platform_data = &exynos4_pdma1_pdata,
158 }, 233 },
159}; 234 .res = {
160 235 .start = EXYNOS4_PA_PDMA1,
161static struct platform_device *exynos4_dmacs[] __initdata = { 236 .end = EXYNOS4_PA_PDMA1 + SZ_4K,
162 &exynos4_device_pdma0, 237 .flags = IORESOURCE_MEM,
163 &exynos4_device_pdma1, 238 },
239 .irq = {IRQ_PDMA1, NO_IRQ},
240 .periphid = 0x00041330,
164}; 241};
165 242
166static int __init exynos4_dma_init(void) 243static int __init exynos4_dma_init(void)
167{ 244{
168 platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs)); 245 amba_device_register(&exynos4_device_pdma0, &iomem_resource);
169 246
170 return 0; 247 return 0;
171} 248}
diff --git a/arch/arm/mach-exynos4/include/mach/dma.h b/arch/arm/mach-exynos4/include/mach/dma.h
index 81209eb1409b..201842a3769e 100644
--- a/arch/arm/mach-exynos4/include/mach/dma.h
+++ b/arch/arm/mach-exynos4/include/mach/dma.h
@@ -20,7 +20,7 @@
20#ifndef __MACH_DMA_H 20#ifndef __MACH_DMA_H
21#define __MACH_DMA_H 21#define __MACH_DMA_H
22 22
23/* This platform uses the common S3C DMA API driver for PL330 */ 23/* This platform uses the common DMA API driver for PL330 */
24#include <plat/s3c-dma-pl330.h> 24#include <plat/dma-pl330.h>
25 25
26#endif /* __MACH_DMA_H */ 26#endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index b2b2a5bb275e..ae8e482b6427 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -13,7 +13,6 @@
13#ifndef __ASM_ARCH_DMA_H 13#ifndef __ASM_ARCH_DMA_H
14#define __ASM_ARCH_DMA_H __FILE__ 14#define __ASM_ARCH_DMA_H __FILE__
15 15
16#include <plat/dma.h>
17#include <linux/sysdev.h> 16#include <linux/sysdev.h>
18 17
19#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ 18#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
@@ -51,6 +50,18 @@ enum dma_ch {
51 DMACH_MAX, /* the end entry */ 50 DMACH_MAX, /* the end entry */
52}; 51};
53 52
53static inline bool samsung_dma_has_circular(void)
54{
55 return false;
56}
57
58static inline bool samsung_dma_is_dmadev(void)
59{
60 return false;
61}
62
63#include <plat/dma.h>
64
54#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ 65#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
55 66
56/* we have 4 dma channels */ 67/* we have 4 dma channels */
@@ -163,7 +174,7 @@ struct s3c2410_dma_chan {
163 struct s3c2410_dma_client *client; 174 struct s3c2410_dma_client *client;
164 175
165 /* channel configuration */ 176 /* channel configuration */
166 enum s3c2410_dmasrc source; 177 enum dma_data_direction source;
167 enum dma_ch req_ch; 178 enum dma_ch req_ch;
168 unsigned long dev_addr; 179 unsigned long dev_addr;
169 unsigned long load_timeout; 180 unsigned long load_timeout;
@@ -196,9 +207,4 @@ struct s3c2410_dma_chan {
196 207
197typedef unsigned long dma_device_t; 208typedef unsigned long dma_device_t;
198 209
199static inline bool s3c_dma_has_circular(void)
200{
201 return false;
202}
203
204#endif /* __ASM_ARCH_DMA_H */ 210#endif /* __ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index c61e3261615d..d2a7d5ef3e67 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -130,11 +130,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
130 130
131static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan, 131static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
132 struct s3c24xx_dma_map *map, 132 struct s3c24xx_dma_map *map,
133 enum s3c2410_dmasrc dir) 133 enum dma_data_direction dir)
134{ 134{
135 unsigned long chsel; 135 unsigned long chsel;
136 136
137 if (dir == S3C2410_DMASRC_HW) 137 if (dir == DMA_FROM_DEVICE)
138 chsel = map->channels_rx[0]; 138 chsel = map->channels_rx[0];
139 else 139 else
140 chsel = map->channels[0]; 140 chsel = map->channels[0];
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
index 204bfafe4bfc..67c97fab62fd 100644
--- a/arch/arm/mach-s3c64xx/dma.c
+++ b/arch/arm/mach-s3c64xx/dma.c
@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
147 u32 control0, control1; 147 u32 control0, control1;
148 148
149 switch (chan->source) { 149 switch (chan->source) {
150 case S3C2410_DMASRC_HW: 150 case DMA_FROM_DEVICE:
151 src = chan->dev_addr; 151 src = chan->dev_addr;
152 dst = data; 152 dst = data;
153 control0 = PL080_CONTROL_SRC_AHB2; 153 control0 = PL080_CONTROL_SRC_AHB2;
154 control0 |= PL080_CONTROL_DST_INCR; 154 control0 |= PL080_CONTROL_DST_INCR;
155 break; 155 break;
156 156
157 case S3C2410_DMASRC_MEM: 157 case DMA_TO_DEVICE:
158 src = data; 158 src = data;
159 dst = chan->dev_addr; 159 dst = chan->dev_addr;
160 control0 = PL080_CONTROL_DST_AHB2; 160 control0 = PL080_CONTROL_DST_AHB2;
@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue);
416 416
417 417
418int s3c2410_dma_devconfig(enum dma_ch channel, 418int s3c2410_dma_devconfig(enum dma_ch channel,
419 enum s3c2410_dmasrc source, 419 enum dma_data_direction source,
420 unsigned long devaddr) 420 unsigned long devaddr)
421{ 421{
422 struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 422 struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
437 pr_debug("%s: peripheral %d\n", __func__, peripheral); 437 pr_debug("%s: peripheral %d\n", __func__, peripheral);
438 438
439 switch (source) { 439 switch (source) {
440 case S3C2410_DMASRC_HW: 440 case DMA_FROM_DEVICE:
441 config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT; 441 config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
442 config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT; 442 config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
443 break; 443 break;
444 case S3C2410_DMASRC_MEM: 444 case DMA_TO_DEVICE:
445 config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT; 445 config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
446 config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT; 446 config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
447 break; 447 break;
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index 0a5d9268a23e..fe1a98cf0e4c 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -58,11 +58,15 @@ enum dma_ch {
58 DMACH_MAX /* the end */ 58 DMACH_MAX /* the end */
59}; 59};
60 60
61static __inline__ bool s3c_dma_has_circular(void) 61static inline bool samsung_dma_has_circular(void)
62{ 62{
63 return true; 63 return true;
64} 64}
65 65
66static inline bool samsung_dma_is_dmadev(void)
67{
68 return false;
69}
66#define S3C2410_DMAF_CIRCULAR (1 << 0) 70#define S3C2410_DMAF_CIRCULAR (1 << 0)
67 71
68#include <plat/dma.h> 72#include <plat/dma.h>
@@ -95,7 +99,7 @@ struct s3c2410_dma_chan {
95 unsigned char peripheral; 99 unsigned char peripheral;
96 100
97 unsigned int flags; 101 unsigned int flags;
98 enum s3c2410_dmasrc source; 102 enum dma_data_direction source;
99 103
100 104
101 dma_addr_t dev_addr; 105 dma_addr_t dev_addr;
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 65c7518dad7f..9527ed24dbff 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -9,14 +9,14 @@ if ARCH_S5P64X0
9 9
10config CPU_S5P6440 10config CPU_S5P6440
11 bool 11 bool
12 select S3C_PL330_DMA 12 select SAMSUNG_DMADEV
13 select S5P_HRT 13 select S5P_HRT
14 help 14 help
15 Enable S5P6440 CPU support 15 Enable S5P6440 CPU support
16 16
17config CPU_S5P6450 17config CPU_S5P6450
18 bool 18 bool
19 select S3C_PL330_DMA 19 select SAMSUNG_DMADEV
20 select S5P_HRT 20 select S5P_HRT
21 help 21 help
22 Enable S5P6450 CPU support 22 Enable S5P6450 CPU support
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 0e9cd3092dd2..c1f548f69a0d 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -146,7 +146,7 @@ static struct clk init_clocks_off[] = {
146 .enable = s5p64x0_hclk0_ctrl, 146 .enable = s5p64x0_hclk0_ctrl,
147 .ctrlbit = (1 << 8), 147 .ctrlbit = (1 << 8),
148 }, { 148 }, {
149 .name = "pdma", 149 .name = "dma",
150 .parent = &clk_hclk_low.clk, 150 .parent = &clk_hclk_low.clk,
151 .enable = s5p64x0_hclk0_ctrl, 151 .enable = s5p64x0_hclk0_ctrl,
152 .ctrlbit = (1 << 12), 152 .ctrlbit = (1 << 12),
@@ -499,6 +499,11 @@ static struct clksrc_clk *sysclks[] = {
499 &clk_pclk_low, 499 &clk_pclk_low,
500}; 500};
501 501
502static struct clk dummy_apb_pclk = {
503 .name = "apb_pclk",
504 .id = -1,
505};
506
502void __init_or_cpufreq s5p6440_setup_clocks(void) 507void __init_or_cpufreq s5p6440_setup_clocks(void)
503{ 508{
504 struct clk *xtal_clk; 509 struct clk *xtal_clk;
@@ -581,5 +586,7 @@ void __init s5p6440_register_clocks(void)
581 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 586 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
582 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 587 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
583 588
589 s3c24xx_register_clock(&dummy_apb_pclk);
590
584 s3c_pwmclk_init(); 591 s3c_pwmclk_init();
585} 592}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index d9dc16cde109..3d9b60975570 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -179,7 +179,7 @@ static struct clk init_clocks_off[] = {
179 .enable = s5p64x0_hclk0_ctrl, 179 .enable = s5p64x0_hclk0_ctrl,
180 .ctrlbit = (1 << 3), 180 .ctrlbit = (1 << 3),
181 }, { 181 }, {
182 .name = "pdma", 182 .name = "dma",
183 .parent = &clk_hclk_low.clk, 183 .parent = &clk_hclk_low.clk,
184 .enable = s5p64x0_hclk0_ctrl, 184 .enable = s5p64x0_hclk0_ctrl,
185 .ctrlbit = (1 << 12), 185 .ctrlbit = (1 << 12),
@@ -553,6 +553,11 @@ static struct clksrc_clk *sysclks[] = {
553 &clk_sclk_audio0, 553 &clk_sclk_audio0,
554}; 554};
555 555
556static struct clk dummy_apb_pclk = {
557 .name = "apb_pclk",
558 .id = -1,
559};
560
556void __init_or_cpufreq s5p6450_setup_clocks(void) 561void __init_or_cpufreq s5p6450_setup_clocks(void)
557{ 562{
558 struct clk *xtal_clk; 563 struct clk *xtal_clk;
@@ -632,5 +637,7 @@ void __init s5p6450_register_clocks(void)
632 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 637 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
633 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 638 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
634 639
640 s3c24xx_register_clock(&dummy_apb_pclk);
641
635 s3c_pwmclk_init(); 642 s3c_pwmclk_init();
636} 643}
diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c
index 0e5b3e63e5b3..442dd4ad12da 100644
--- a/arch/arm/mach-s5p64x0/dma.c
+++ b/arch/arm/mach-s5p64x0/dma.c
@@ -21,115 +21,208 @@
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/ 22*/
23 23
24#include <linux/platform_device.h>
25#include <linux/dma-mapping.h> 24#include <linux/dma-mapping.h>
25#include <linux/amba/bus.h>
26#include <linux/amba/pl330.h>
27
28#include <asm/irq.h>
26 29
27#include <mach/map.h> 30#include <mach/map.h>
28#include <mach/irqs.h> 31#include <mach/irqs.h>
29#include <mach/regs-clock.h> 32#include <mach/regs-clock.h>
33#include <mach/dma.h>
30 34
31#include <plat/cpu.h> 35#include <plat/cpu.h>
32#include <plat/devs.h> 36#include <plat/devs.h>
33#include <plat/s3c-pl330-pdata.h> 37#include <plat/irqs.h>
34 38
35static u64 dma_dmamask = DMA_BIT_MASK(32); 39static u64 dma_dmamask = DMA_BIT_MASK(32);
36 40
37static struct resource s5p64x0_pdma_resource[] = { 41struct dma_pl330_peri s5p6440_pdma_peri[22] = {
38 [0] = { 42 {
39 .start = S5P64X0_PA_PDMA, 43 .peri_id = (u8)DMACH_UART0_RX,
40 .end = S5P64X0_PA_PDMA + SZ_4K, 44 .rqtype = DEVTOMEM,
41 .flags = IORESOURCE_MEM, 45 }, {
42 }, 46 .peri_id = (u8)DMACH_UART0_TX,
43 [1] = { 47 .rqtype = MEMTODEV,
44 .start = IRQ_DMA0, 48 }, {
45 .end = IRQ_DMA0, 49 .peri_id = (u8)DMACH_UART1_RX,
46 .flags = IORESOURCE_IRQ, 50 .rqtype = DEVTOMEM,
51 }, {
52 .peri_id = (u8)DMACH_UART1_TX,
53 .rqtype = MEMTODEV,
54 }, {
55 .peri_id = (u8)DMACH_UART2_RX,
56 .rqtype = DEVTOMEM,
57 }, {
58 .peri_id = (u8)DMACH_UART2_TX,
59 .rqtype = MEMTODEV,
60 }, {
61 .peri_id = (u8)DMACH_UART3_RX,
62 .rqtype = DEVTOMEM,
63 }, {
64 .peri_id = (u8)DMACH_UART3_TX,
65 .rqtype = MEMTODEV,
66 }, {
67 .peri_id = DMACH_MAX,
68 }, {
69 .peri_id = DMACH_MAX,
70 }, {
71 .peri_id = (u8)DMACH_PCM0_TX,
72 .rqtype = MEMTODEV,
73 }, {
74 .peri_id = (u8)DMACH_PCM0_RX,
75 .rqtype = DEVTOMEM,
76 }, {
77 .peri_id = (u8)DMACH_I2S0_TX,
78 .rqtype = MEMTODEV,
79 }, {
80 .peri_id = (u8)DMACH_I2S0_RX,
81 .rqtype = DEVTOMEM,
82 }, {
83 .peri_id = (u8)DMACH_SPI0_TX,
84 .rqtype = MEMTODEV,
85 }, {
86 .peri_id = (u8)DMACH_SPI0_RX,
87 .rqtype = DEVTOMEM,
88 }, {
89 .peri_id = (u8)DMACH_MAX,
90 }, {
91 .peri_id = (u8)DMACH_MAX,
92 }, {
93 .peri_id = (u8)DMACH_MAX,
94 }, {
95 .peri_id = (u8)DMACH_MAX,
96 }, {
97 .peri_id = (u8)DMACH_SPI1_TX,
98 .rqtype = MEMTODEV,
99 }, {
100 .peri_id = (u8)DMACH_SPI1_RX,
101 .rqtype = DEVTOMEM,
47 }, 102 },
48}; 103};
49 104
50static struct s3c_pl330_platdata s5p6440_pdma_pdata = { 105struct dma_pl330_platdata s5p6440_pdma_pdata = {
51 .peri = { 106 .nr_valid_peri = ARRAY_SIZE(s5p6440_pdma_peri),
52 [0] = DMACH_UART0_RX, 107 .peri = s5p6440_pdma_peri,
53 [1] = DMACH_UART0_TX,
54 [2] = DMACH_UART1_RX,
55 [3] = DMACH_UART1_TX,
56 [4] = DMACH_UART2_RX,
57 [5] = DMACH_UART2_TX,
58 [6] = DMACH_UART3_RX,
59 [7] = DMACH_UART3_TX,
60 [8] = DMACH_MAX,
61 [9] = DMACH_MAX,
62 [10] = DMACH_PCM0_TX,
63 [11] = DMACH_PCM0_RX,
64 [12] = DMACH_I2S0_TX,
65 [13] = DMACH_I2S0_RX,
66 [14] = DMACH_SPI0_TX,
67 [15] = DMACH_SPI0_RX,
68 [16] = DMACH_MAX,
69 [17] = DMACH_MAX,
70 [18] = DMACH_MAX,
71 [19] = DMACH_MAX,
72 [20] = DMACH_SPI1_TX,
73 [21] = DMACH_SPI1_RX,
74 [22] = DMACH_MAX,
75 [23] = DMACH_MAX,
76 [24] = DMACH_MAX,
77 [25] = DMACH_MAX,
78 [26] = DMACH_MAX,
79 [27] = DMACH_MAX,
80 [28] = DMACH_MAX,
81 [29] = DMACH_PWM,
82 [30] = DMACH_MAX,
83 [31] = DMACH_MAX,
84 },
85}; 108};
86 109
87static struct s3c_pl330_platdata s5p6450_pdma_pdata = { 110struct dma_pl330_peri s5p6450_pdma_peri[32] = {
88 .peri = { 111 {
89 [0] = DMACH_UART0_RX, 112 .peri_id = (u8)DMACH_UART0_RX,
90 [1] = DMACH_UART0_TX, 113 .rqtype = DEVTOMEM,
91 [2] = DMACH_UART1_RX, 114 }, {
92 [3] = DMACH_UART1_TX, 115 .peri_id = (u8)DMACH_UART0_TX,
93 [4] = DMACH_UART2_RX, 116 .rqtype = MEMTODEV,
94 [5] = DMACH_UART2_TX, 117 }, {
95 [6] = DMACH_UART3_RX, 118 .peri_id = (u8)DMACH_UART1_RX,
96 [7] = DMACH_UART3_TX, 119 .rqtype = DEVTOMEM,
97 [8] = DMACH_UART4_RX, 120 }, {
98 [9] = DMACH_UART4_TX, 121 .peri_id = (u8)DMACH_UART1_TX,
99 [10] = DMACH_PCM0_TX, 122 .rqtype = MEMTODEV,
100 [11] = DMACH_PCM0_RX, 123 }, {
101 [12] = DMACH_I2S0_TX, 124 .peri_id = (u8)DMACH_UART2_RX,
102 [13] = DMACH_I2S0_RX, 125 .rqtype = DEVTOMEM,
103 [14] = DMACH_SPI0_TX, 126 }, {
104 [15] = DMACH_SPI0_RX, 127 .peri_id = (u8)DMACH_UART2_TX,
105 [16] = DMACH_PCM1_TX, 128 .rqtype = MEMTODEV,
106 [17] = DMACH_PCM1_RX, 129 }, {
107 [18] = DMACH_PCM2_TX, 130 .peri_id = (u8)DMACH_UART3_RX,
108 [19] = DMACH_PCM2_RX, 131 .rqtype = DEVTOMEM,
109 [20] = DMACH_SPI1_TX, 132 }, {
110 [21] = DMACH_SPI1_RX, 133 .peri_id = (u8)DMACH_UART3_TX,
111 [22] = DMACH_USI_TX, 134 .rqtype = MEMTODEV,
112 [23] = DMACH_USI_RX, 135 }, {
113 [24] = DMACH_MAX, 136 .peri_id = (u8)DMACH_UART4_RX,
114 [25] = DMACH_I2S1_TX, 137 .rqtype = DEVTOMEM,
115 [26] = DMACH_I2S1_RX, 138 }, {
116 [27] = DMACH_I2S2_TX, 139 .peri_id = (u8)DMACH_UART4_TX,
117 [28] = DMACH_I2S2_RX, 140 .rqtype = MEMTODEV,
118 [29] = DMACH_PWM, 141 }, {
119 [30] = DMACH_UART5_RX, 142 .peri_id = (u8)DMACH_PCM0_TX,
120 [31] = DMACH_UART5_TX, 143 .rqtype = MEMTODEV,
144 }, {
145 .peri_id = (u8)DMACH_PCM0_RX,
146 .rqtype = DEVTOMEM,
147 }, {
148 .peri_id = (u8)DMACH_I2S0_TX,
149 .rqtype = MEMTODEV,
150 }, {
151 .peri_id = (u8)DMACH_I2S0_RX,
152 .rqtype = DEVTOMEM,
153 }, {
154 .peri_id = (u8)DMACH_SPI0_TX,
155 .rqtype = MEMTODEV,
156 }, {
157 .peri_id = (u8)DMACH_SPI0_RX,
158 .rqtype = DEVTOMEM,
159 }, {
160 .peri_id = (u8)DMACH_PCM1_TX,
161 .rqtype = MEMTODEV,
162 }, {
163 .peri_id = (u8)DMACH_PCM1_RX,
164 .rqtype = DEVTOMEM,
165 }, {
166 .peri_id = (u8)DMACH_PCM2_TX,
167 .rqtype = MEMTODEV,
168 }, {
169 .peri_id = (u8)DMACH_PCM2_RX,
170 .rqtype = DEVTOMEM,
171 }, {
172 .peri_id = (u8)DMACH_SPI1_TX,
173 .rqtype = MEMTODEV,
174 }, {
175 .peri_id = (u8)DMACH_SPI1_RX,
176 .rqtype = DEVTOMEM,
177 }, {
178 .peri_id = (u8)DMACH_USI_TX,
179 .rqtype = MEMTODEV,
180 }, {
181 .peri_id = (u8)DMACH_USI_RX,
182 .rqtype = DEVTOMEM,
183 }, {
184 .peri_id = (u8)DMACH_MAX,
185 }, {
186 .peri_id = (u8)DMACH_I2S1_TX,
187 .rqtype = MEMTODEV,
188 }, {
189 .peri_id = (u8)DMACH_I2S1_RX,
190 .rqtype = DEVTOMEM,
191 }, {
192 .peri_id = (u8)DMACH_I2S2_TX,
193 .rqtype = MEMTODEV,
194 }, {
195 .peri_id = (u8)DMACH_I2S2_RX,
196 .rqtype = DEVTOMEM,
197 }, {
198 .peri_id = (u8)DMACH_PWM,
199 }, {
200 .peri_id = (u8)DMACH_UART5_RX,
201 .rqtype = DEVTOMEM,
202 }, {
203 .peri_id = (u8)DMACH_UART5_TX,
204 .rqtype = MEMTODEV,
121 }, 205 },
122}; 206};
123 207
124static struct platform_device s5p64x0_device_pdma = { 208struct dma_pl330_platdata s5p6450_pdma_pdata = {
125 .name = "s3c-pl330", 209 .nr_valid_peri = ARRAY_SIZE(s5p6450_pdma_peri),
126 .id = -1, 210 .peri = s5p6450_pdma_peri,
127 .num_resources = ARRAY_SIZE(s5p64x0_pdma_resource), 211};
128 .resource = s5p64x0_pdma_resource, 212
129 .dev = { 213struct amba_device s5p64x0_device_pdma = {
214 .dev = {
215 .init_name = "dma-pl330",
130 .dma_mask = &dma_dmamask, 216 .dma_mask = &dma_dmamask,
131 .coherent_dma_mask = DMA_BIT_MASK(32), 217 .coherent_dma_mask = DMA_BIT_MASK(32),
132 }, 218 },
219 .res = {
220 .start = S5P64X0_PA_PDMA,
221 .end = S5P64X0_PA_PDMA + SZ_4K,
222 .flags = IORESOURCE_MEM,
223 },
224 .irq = {IRQ_DMA0, NO_IRQ},
225 .periphid = 0x00041330,
133}; 226};
134 227
135static int __init s5p64x0_dma_init(void) 228static int __init s5p64x0_dma_init(void)
@@ -139,7 +232,7 @@ static int __init s5p64x0_dma_init(void)
139 else 232 else
140 s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata; 233 s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
141 234
142 platform_device_register(&s5p64x0_device_pdma); 235 amba_device_register(&s5p64x0_device_pdma, &iomem_resource);
143 236
144 return 0; 237 return 0;
145} 238}
diff --git a/arch/arm/mach-s5p64x0/include/mach/dma.h b/arch/arm/mach-s5p64x0/include/mach/dma.h
index 81209eb1409b..5a622af461d7 100644
--- a/arch/arm/mach-s5p64x0/include/mach/dma.h
+++ b/arch/arm/mach-s5p64x0/include/mach/dma.h
@@ -20,7 +20,7 @@
20#ifndef __MACH_DMA_H 20#ifndef __MACH_DMA_H
21#define __MACH_DMA_H 21#define __MACH_DMA_H
22 22
23/* This platform uses the common S3C DMA API driver for PL330 */ 23/* This platform uses the common common DMA API driver for PL330 */
24#include <plat/s3c-dma-pl330.h> 24#include <plat/dma-pl330.h>
25 25
26#endif /* __MACH_DMA_H */ 26#endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index e8a33c4b054c..e538a4c67e9c 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -10,7 +10,7 @@ if ARCH_S5PC100
10config CPU_S5PC100 10config CPU_S5PC100
11 bool 11 bool
12 select S5P_EXT_INT 12 select S5P_EXT_INT
13 select S3C_PL330_DMA 13 select SAMSUNG_DMADEV
14 help 14 help
15 Enable S5PC100 CPU support 15 Enable S5PC100 CPU support
16 16
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index ff5cbb30de5b..6527c05c5fa1 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -33,6 +33,11 @@ static struct clk s5p_clk_otgphy = {
33 .name = "otg_phy", 33 .name = "otg_phy",
34}; 34};
35 35
36static struct clk dummy_apb_pclk = {
37 .name = "apb_pclk",
38 .id = -1,
39};
40
36static struct clk *clk_src_mout_href_list[] = { 41static struct clk *clk_src_mout_href_list[] = {
37 [0] = &s5p_clk_27m, 42 [0] = &s5p_clk_27m,
38 [1] = &clk_fin_hpll, 43 [1] = &clk_fin_hpll,
@@ -454,13 +459,13 @@ static struct clk init_clocks_off[] = {
454 .enable = s5pc100_d1_0_ctrl, 459 .enable = s5pc100_d1_0_ctrl,
455 .ctrlbit = (1 << 2), 460 .ctrlbit = (1 << 2),
456 }, { 461 }, {
457 .name = "pdma", 462 .name = "dma",
458 .devname = "s3c-pl330.1", 463 .devname = "s3c-pl330.1",
459 .parent = &clk_div_d1_bus.clk, 464 .parent = &clk_div_d1_bus.clk,
460 .enable = s5pc100_d1_0_ctrl, 465 .enable = s5pc100_d1_0_ctrl,
461 .ctrlbit = (1 << 1), 466 .ctrlbit = (1 << 1),
462 }, { 467 }, {
463 .name = "pdma", 468 .name = "dma",
464 .devname = "s3c-pl330.0", 469 .devname = "s3c-pl330.0",
465 .parent = &clk_div_d1_bus.clk, 470 .parent = &clk_div_d1_bus.clk,
466 .enable = s5pc100_d1_0_ctrl, 471 .enable = s5pc100_d1_0_ctrl,
@@ -1276,5 +1281,7 @@ void __init s5pc100_register_clocks(void)
1276 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1281 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1277 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1282 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1278 1283
1284 s3c24xx_register_clock(&dummy_apb_pclk);
1285
1279 s3c_pwmclk_init(); 1286 s3c_pwmclk_init();
1280} 1287}
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c
index bf4cd0fb97c6..ef803e92d35d 100644
--- a/arch/arm/mach-s5pc100/dma.c
+++ b/arch/arm/mach-s5pc100/dma.c
@@ -1,4 +1,8 @@
1/* 1/* linux/arch/arm/mach-s5pc100/dma.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
2 * Copyright (C) 2010 Samsung Electronics Co. Ltd. 6 * Copyright (C) 2010 Samsung Electronics Co. Ltd.
3 * Jaswinder Singh <jassi.brar@samsung.com> 7 * Jaswinder Singh <jassi.brar@samsung.com>
4 * 8 *
@@ -17,150 +21,245 @@
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */ 22 */
19 23
20#include <linux/platform_device.h>
21#include <linux/dma-mapping.h> 24#include <linux/dma-mapping.h>
25#include <linux/amba/bus.h>
26#include <linux/amba/pl330.h>
22 27
28#include <asm/irq.h>
23#include <plat/devs.h> 29#include <plat/devs.h>
30#include <plat/irqs.h>
24 31
25#include <mach/map.h> 32#include <mach/map.h>
26#include <mach/irqs.h> 33#include <mach/irqs.h>
27 34#include <mach/dma.h>
28#include <plat/s3c-pl330-pdata.h>
29 35
30static u64 dma_dmamask = DMA_BIT_MASK(32); 36static u64 dma_dmamask = DMA_BIT_MASK(32);
31 37
32static struct resource s5pc100_pdma0_resource[] = { 38struct dma_pl330_peri pdma0_peri[30] = {
33 [0] = { 39 {
34 .start = S5PC100_PA_PDMA0, 40 .peri_id = (u8)DMACH_UART0_RX,
35 .end = S5PC100_PA_PDMA0 + SZ_4K, 41 .rqtype = DEVTOMEM,
36 .flags = IORESOURCE_MEM, 42 }, {
37 }, 43 .peri_id = (u8)DMACH_UART0_TX,
38 [1] = { 44 .rqtype = MEMTODEV,
39 .start = IRQ_PDMA0, 45 }, {
40 .end = IRQ_PDMA0, 46 .peri_id = (u8)DMACH_UART1_RX,
41 .flags = IORESOURCE_IRQ, 47 .rqtype = DEVTOMEM,
48 }, {
49 .peri_id = (u8)DMACH_UART1_TX,
50 .rqtype = MEMTODEV,
51 }, {
52 .peri_id = (u8)DMACH_UART2_RX,
53 .rqtype = DEVTOMEM,
54 }, {
55 .peri_id = (u8)DMACH_UART2_TX,
56 .rqtype = MEMTODEV,
57 }, {
58 .peri_id = (u8)DMACH_UART3_RX,
59 .rqtype = DEVTOMEM,
60 }, {
61 .peri_id = (u8)DMACH_UART3_TX,
62 .rqtype = MEMTODEV,
63 }, {
64 .peri_id = DMACH_IRDA,
65 }, {
66 .peri_id = (u8)DMACH_I2S0_RX,
67 .rqtype = DEVTOMEM,
68 }, {
69 .peri_id = (u8)DMACH_I2S0_TX,
70 .rqtype = MEMTODEV,
71 }, {
72 .peri_id = (u8)DMACH_I2S0S_TX,
73 .rqtype = MEMTODEV,
74 }, {
75 .peri_id = (u8)DMACH_I2S1_RX,
76 .rqtype = DEVTOMEM,
77 }, {
78 .peri_id = (u8)DMACH_I2S1_TX,
79 .rqtype = MEMTODEV,
80 }, {
81 .peri_id = (u8)DMACH_I2S2_RX,
82 .rqtype = DEVTOMEM,
83 }, {
84 .peri_id = (u8)DMACH_I2S2_TX,
85 .rqtype = MEMTODEV,
86 }, {
87 .peri_id = (u8)DMACH_SPI0_RX,
88 .rqtype = DEVTOMEM,
89 }, {
90 .peri_id = (u8)DMACH_SPI0_TX,
91 .rqtype = MEMTODEV,
92 }, {
93 .peri_id = (u8)DMACH_SPI1_RX,
94 .rqtype = DEVTOMEM,
95 }, {
96 .peri_id = (u8)DMACH_SPI1_TX,
97 .rqtype = MEMTODEV,
98 }, {
99 .peri_id = (u8)DMACH_SPI2_RX,
100 .rqtype = DEVTOMEM,
101 }, {
102 .peri_id = (u8)DMACH_SPI2_TX,
103 .rqtype = MEMTODEV,
104 }, {
105 .peri_id = (u8)DMACH_AC97_MICIN,
106 .rqtype = DEVTOMEM,
107 }, {
108 .peri_id = (u8)DMACH_AC97_PCMIN,
109 .rqtype = DEVTOMEM,
110 }, {
111 .peri_id = (u8)DMACH_AC97_PCMOUT,
112 .rqtype = MEMTODEV,
113 }, {
114 .peri_id = (u8)DMACH_EXTERNAL,
115 }, {
116 .peri_id = (u8)DMACH_PWM,
117 }, {
118 .peri_id = (u8)DMACH_SPDIF,
119 .rqtype = MEMTODEV,
120 }, {
121 .peri_id = (u8)DMACH_HSI_RX,
122 .rqtype = DEVTOMEM,
123 }, {
124 .peri_id = (u8)DMACH_HSI_TX,
125 .rqtype = MEMTODEV,
42 }, 126 },
43}; 127};
44 128
45static struct s3c_pl330_platdata s5pc100_pdma0_pdata = { 129struct dma_pl330_platdata s5pc100_pdma0_pdata = {
46 .peri = { 130 .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
47 [0] = DMACH_UART0_RX, 131 .peri = pdma0_peri,
48 [1] = DMACH_UART0_TX,
49 [2] = DMACH_UART1_RX,
50 [3] = DMACH_UART1_TX,
51 [4] = DMACH_UART2_RX,
52 [5] = DMACH_UART2_TX,
53 [6] = DMACH_UART3_RX,
54 [7] = DMACH_UART3_TX,
55 [8] = DMACH_IRDA,
56 [9] = DMACH_I2S0_RX,
57 [10] = DMACH_I2S0_TX,
58 [11] = DMACH_I2S0S_TX,
59 [12] = DMACH_I2S1_RX,
60 [13] = DMACH_I2S1_TX,
61 [14] = DMACH_I2S2_RX,
62 [15] = DMACH_I2S2_TX,
63 [16] = DMACH_SPI0_RX,
64 [17] = DMACH_SPI0_TX,
65 [18] = DMACH_SPI1_RX,
66 [19] = DMACH_SPI1_TX,
67 [20] = DMACH_SPI2_RX,
68 [21] = DMACH_SPI2_TX,
69 [22] = DMACH_AC97_MICIN,
70 [23] = DMACH_AC97_PCMIN,
71 [24] = DMACH_AC97_PCMOUT,
72 [25] = DMACH_EXTERNAL,
73 [26] = DMACH_PWM,
74 [27] = DMACH_SPDIF,
75 [28] = DMACH_HSI_RX,
76 [29] = DMACH_HSI_TX,
77 [30] = DMACH_MAX,
78 [31] = DMACH_MAX,
79 },
80}; 132};
81 133
82static struct platform_device s5pc100_device_pdma0 = { 134struct amba_device s5pc100_device_pdma0 = {
83 .name = "s3c-pl330", 135 .dev = {
84 .id = 0, 136 .init_name = "dma-pl330.0",
85 .num_resources = ARRAY_SIZE(s5pc100_pdma0_resource),
86 .resource = s5pc100_pdma0_resource,
87 .dev = {
88 .dma_mask = &dma_dmamask, 137 .dma_mask = &dma_dmamask,
89 .coherent_dma_mask = DMA_BIT_MASK(32), 138 .coherent_dma_mask = DMA_BIT_MASK(32),
90 .platform_data = &s5pc100_pdma0_pdata, 139 .platform_data = &s5pc100_pdma0_pdata,
91 }, 140 },
92}; 141 .res = {
93 142 .start = S5PC100_PA_PDMA0,
94static struct resource s5pc100_pdma1_resource[] = { 143 .end = S5PC100_PA_PDMA0 + SZ_4K,
95 [0] = {
96 .start = S5PC100_PA_PDMA1,
97 .end = S5PC100_PA_PDMA1 + SZ_4K,
98 .flags = IORESOURCE_MEM, 144 .flags = IORESOURCE_MEM,
99 }, 145 },
100 [1] = { 146 .irq = {IRQ_PDMA0, NO_IRQ},
101 .start = IRQ_PDMA1, 147 .periphid = 0x00041330,
102 .end = IRQ_PDMA1,
103 .flags = IORESOURCE_IRQ,
104 },
105}; 148};
106 149
107static struct s3c_pl330_platdata s5pc100_pdma1_pdata = { 150struct dma_pl330_peri pdma1_peri[30] = {
108 .peri = { 151 {
109 [0] = DMACH_UART0_RX, 152 .peri_id = (u8)DMACH_UART0_RX,
110 [1] = DMACH_UART0_TX, 153 .rqtype = DEVTOMEM,
111 [2] = DMACH_UART1_RX, 154 }, {
112 [3] = DMACH_UART1_TX, 155 .peri_id = (u8)DMACH_UART0_TX,
113 [4] = DMACH_UART2_RX, 156 .rqtype = MEMTODEV,
114 [5] = DMACH_UART2_TX, 157 }, {
115 [6] = DMACH_UART3_RX, 158 .peri_id = (u8)DMACH_UART1_RX,
116 [7] = DMACH_UART3_TX, 159 .rqtype = DEVTOMEM,
117 [8] = DMACH_IRDA, 160 }, {
118 [9] = DMACH_I2S0_RX, 161 .peri_id = (u8)DMACH_UART1_TX,
119 [10] = DMACH_I2S0_TX, 162 .rqtype = MEMTODEV,
120 [11] = DMACH_I2S0S_TX, 163 }, {
121 [12] = DMACH_I2S1_RX, 164 .peri_id = (u8)DMACH_UART2_RX,
122 [13] = DMACH_I2S1_TX, 165 .rqtype = DEVTOMEM,
123 [14] = DMACH_I2S2_RX, 166 }, {
124 [15] = DMACH_I2S2_TX, 167 .peri_id = (u8)DMACH_UART2_TX,
125 [16] = DMACH_SPI0_RX, 168 .rqtype = MEMTODEV,
126 [17] = DMACH_SPI0_TX, 169 }, {
127 [18] = DMACH_SPI1_RX, 170 .peri_id = (u8)DMACH_UART3_RX,
128 [19] = DMACH_SPI1_TX, 171 .rqtype = DEVTOMEM,
129 [20] = DMACH_SPI2_RX, 172 }, {
130 [21] = DMACH_SPI2_TX, 173 .peri_id = (u8)DMACH_UART3_TX,
131 [22] = DMACH_PCM0_RX, 174 .rqtype = MEMTODEV,
132 [23] = DMACH_PCM0_TX, 175 }, {
133 [24] = DMACH_PCM1_RX, 176 .peri_id = DMACH_IRDA,
134 [25] = DMACH_PCM1_TX, 177 }, {
135 [26] = DMACH_MSM_REQ0, 178 .peri_id = (u8)DMACH_I2S0_RX,
136 [27] = DMACH_MSM_REQ1, 179 .rqtype = DEVTOMEM,
137 [28] = DMACH_MSM_REQ2, 180 }, {
138 [29] = DMACH_MSM_REQ3, 181 .peri_id = (u8)DMACH_I2S0_TX,
139 [30] = DMACH_MAX, 182 .rqtype = MEMTODEV,
140 [31] = DMACH_MAX, 183 }, {
184 .peri_id = (u8)DMACH_I2S0S_TX,
185 .rqtype = MEMTODEV,
186 }, {
187 .peri_id = (u8)DMACH_I2S1_RX,
188 .rqtype = DEVTOMEM,
189 }, {
190 .peri_id = (u8)DMACH_I2S1_TX,
191 .rqtype = MEMTODEV,
192 }, {
193 .peri_id = (u8)DMACH_I2S2_RX,
194 .rqtype = DEVTOMEM,
195 }, {
196 .peri_id = (u8)DMACH_I2S2_TX,
197 .rqtype = MEMTODEV,
198 }, {
199 .peri_id = (u8)DMACH_SPI0_RX,
200 .rqtype = DEVTOMEM,
201 }, {
202 .peri_id = (u8)DMACH_SPI0_TX,
203 .rqtype = MEMTODEV,
204 }, {
205 .peri_id = (u8)DMACH_SPI1_RX,
206 .rqtype = DEVTOMEM,
207 }, {
208 .peri_id = (u8)DMACH_SPI1_TX,
209 .rqtype = MEMTODEV,
210 }, {
211 .peri_id = (u8)DMACH_SPI2_RX,
212 .rqtype = DEVTOMEM,
213 }, {
214 .peri_id = (u8)DMACH_SPI2_TX,
215 .rqtype = MEMTODEV,
216 }, {
217 .peri_id = (u8)DMACH_PCM0_RX,
218 .rqtype = DEVTOMEM,
219 }, {
220 .peri_id = (u8)DMACH_PCM1_TX,
221 .rqtype = MEMTODEV,
222 }, {
223 .peri_id = (u8)DMACH_PCM1_RX,
224 .rqtype = DEVTOMEM,
225 }, {
226 .peri_id = (u8)DMACH_PCM1_TX,
227 .rqtype = MEMTODEV,
228 }, {
229 .peri_id = (u8)DMACH_MSM_REQ0,
230 }, {
231 .peri_id = (u8)DMACH_MSM_REQ1,
232 }, {
233 .peri_id = (u8)DMACH_MSM_REQ2,
234 }, {
235 .peri_id = (u8)DMACH_MSM_REQ3,
141 }, 236 },
142}; 237};
143 238
144static struct platform_device s5pc100_device_pdma1 = { 239struct dma_pl330_platdata s5pc100_pdma1_pdata = {
145 .name = "s3c-pl330", 240 .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
146 .id = 1, 241 .peri = pdma1_peri,
147 .num_resources = ARRAY_SIZE(s5pc100_pdma1_resource), 242};
148 .resource = s5pc100_pdma1_resource, 243
149 .dev = { 244struct amba_device s5pc100_device_pdma1 = {
245 .dev = {
246 .init_name = "dma-pl330.1",
150 .dma_mask = &dma_dmamask, 247 .dma_mask = &dma_dmamask,
151 .coherent_dma_mask = DMA_BIT_MASK(32), 248 .coherent_dma_mask = DMA_BIT_MASK(32),
152 .platform_data = &s5pc100_pdma1_pdata, 249 .platform_data = &s5pc100_pdma1_pdata,
153 }, 250 },
154}; 251 .res = {
155 252 .start = S5PC100_PA_PDMA1,
156static struct platform_device *s5pc100_dmacs[] __initdata = { 253 .end = S5PC100_PA_PDMA1 + SZ_4K,
157 &s5pc100_device_pdma0, 254 .flags = IORESOURCE_MEM,
158 &s5pc100_device_pdma1, 255 },
256 .irq = {IRQ_PDMA1, NO_IRQ},
257 .periphid = 0x00041330,
159}; 258};
160 259
161static int __init s5pc100_dma_init(void) 260static int __init s5pc100_dma_init(void)
162{ 261{
163 platform_add_devices(s5pc100_dmacs, ARRAY_SIZE(s5pc100_dmacs)); 262 amba_device_register(&s5pc100_device_pdma0, &iomem_resource);
164 263
165 return 0; 264 return 0;
166} 265}
diff --git a/arch/arm/mach-s5pc100/include/mach/dma.h b/arch/arm/mach-s5pc100/include/mach/dma.h
index 81209eb1409b..201842a3769e 100644
--- a/arch/arm/mach-s5pc100/include/mach/dma.h
+++ b/arch/arm/mach-s5pc100/include/mach/dma.h
@@ -20,7 +20,7 @@
20#ifndef __MACH_DMA_H 20#ifndef __MACH_DMA_H
21#define __MACH_DMA_H 21#define __MACH_DMA_H
22 22
23/* This platform uses the common S3C DMA API driver for PL330 */ 23/* This platform uses the common DMA API driver for PL330 */
24#include <plat/s3c-dma-pl330.h> 24#include <plat/dma-pl330.h>
25 25
26#endif /* __MACH_DMA_H */ 26#endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index aaeb44a73716..e3ebe96923c8 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -11,7 +11,7 @@ if ARCH_S5PV210
11 11
12config CPU_S5PV210 12config CPU_S5PV210
13 bool 13 bool
14 select S3C_PL330_DMA 14 select SAMSUNG_DMADEV
15 select S5P_EXT_INT 15 select S5P_EXT_INT
16 select S5P_HRT 16 select S5P_HRT
17 help 17 help
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index f5f8fa89679c..1ab34000cc7e 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -203,6 +203,11 @@ static struct clk clk_pcmcdclk2 = {
203 .name = "pcmcdclk", 203 .name = "pcmcdclk",
204}; 204};
205 205
206static struct clk dummy_apb_pclk = {
207 .name = "apb_pclk",
208 .id = -1,
209};
210
206static struct clk *clkset_vpllsrc_list[] = { 211static struct clk *clkset_vpllsrc_list[] = {
207 [0] = &clk_fin_vpll, 212 [0] = &clk_fin_vpll,
208 [1] = &clk_sclk_hdmi27m, 213 [1] = &clk_sclk_hdmi27m,
@@ -289,13 +294,13 @@ static struct clk_ops clk_fout_apll_ops = {
289 294
290static struct clk init_clocks_off[] = { 295static struct clk init_clocks_off[] = {
291 { 296 {
292 .name = "pdma", 297 .name = "dma",
293 .devname = "s3c-pl330.0", 298 .devname = "s3c-pl330.0",
294 .parent = &clk_hclk_psys.clk, 299 .parent = &clk_hclk_psys.clk,
295 .enable = s5pv210_clk_ip0_ctrl, 300 .enable = s5pv210_clk_ip0_ctrl,
296 .ctrlbit = (1 << 3), 301 .ctrlbit = (1 << 3),
297 }, { 302 }, {
298 .name = "pdma", 303 .name = "dma",
299 .devname = "s3c-pl330.1", 304 .devname = "s3c-pl330.1",
300 .parent = &clk_hclk_psys.clk, 305 .parent = &clk_hclk_psys.clk,
301 .enable = s5pv210_clk_ip0_ctrl, 306 .enable = s5pv210_clk_ip0_ctrl,
@@ -1159,5 +1164,6 @@ void __init s5pv210_register_clocks(void)
1159 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1164 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1160 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 1165 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
1161 1166
1167 s3c24xx_register_clock(&dummy_apb_pclk);
1162 s3c_pwmclk_init(); 1168 s3c_pwmclk_init();
1163} 1169}
diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c
index 497d3439a142..f79d0b06cbf9 100644
--- a/arch/arm/mach-s5pv210/dma.c
+++ b/arch/arm/mach-s5pv210/dma.c
@@ -1,4 +1,8 @@
1/* 1/* linux/arch/arm/mach-s5pv210/dma.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
2 * Copyright (C) 2010 Samsung Electronics Co. Ltd. 6 * Copyright (C) 2010 Samsung Electronics Co. Ltd.
3 * Jaswinder Singh <jassi.brar@samsung.com> 7 * Jaswinder Singh <jassi.brar@samsung.com>
4 * 8 *
@@ -17,151 +21,239 @@
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */ 22 */
19 23
20#include <linux/platform_device.h>
21#include <linux/dma-mapping.h> 24#include <linux/dma-mapping.h>
25#include <linux/amba/bus.h>
26#include <linux/amba/pl330.h>
22 27
28#include <asm/irq.h>
23#include <plat/devs.h> 29#include <plat/devs.h>
24#include <plat/irqs.h> 30#include <plat/irqs.h>
25 31
26#include <mach/map.h> 32#include <mach/map.h>
27#include <mach/irqs.h> 33#include <mach/irqs.h>
28 34#include <mach/dma.h>
29#include <plat/s3c-pl330-pdata.h>
30 35
31static u64 dma_dmamask = DMA_BIT_MASK(32); 36static u64 dma_dmamask = DMA_BIT_MASK(32);
32 37
33static struct resource s5pv210_pdma0_resource[] = { 38struct dma_pl330_peri pdma0_peri[28] = {
34 [0] = { 39 {
35 .start = S5PV210_PA_PDMA0, 40 .peri_id = (u8)DMACH_UART0_RX,
36 .end = S5PV210_PA_PDMA0 + SZ_4K, 41 .rqtype = DEVTOMEM,
37 .flags = IORESOURCE_MEM, 42 }, {
38 }, 43 .peri_id = (u8)DMACH_UART0_TX,
39 [1] = { 44 .rqtype = MEMTODEV,
40 .start = IRQ_PDMA0, 45 }, {
41 .end = IRQ_PDMA0, 46 .peri_id = (u8)DMACH_UART1_RX,
42 .flags = IORESOURCE_IRQ, 47 .rqtype = DEVTOMEM,
48 }, {
49 .peri_id = (u8)DMACH_UART1_TX,
50 .rqtype = MEMTODEV,
51 }, {
52 .peri_id = (u8)DMACH_UART2_RX,
53 .rqtype = DEVTOMEM,
54 }, {
55 .peri_id = (u8)DMACH_UART2_TX,
56 .rqtype = MEMTODEV,
57 }, {
58 .peri_id = (u8)DMACH_UART3_RX,
59 .rqtype = DEVTOMEM,
60 }, {
61 .peri_id = (u8)DMACH_UART3_TX,
62 .rqtype = MEMTODEV,
63 }, {
64 .peri_id = DMACH_MAX,
65 }, {
66 .peri_id = (u8)DMACH_I2S0_RX,
67 .rqtype = DEVTOMEM,
68 }, {
69 .peri_id = (u8)DMACH_I2S0_TX,
70 .rqtype = MEMTODEV,
71 }, {
72 .peri_id = (u8)DMACH_I2S0S_TX,
73 .rqtype = MEMTODEV,
74 }, {
75 .peri_id = (u8)DMACH_I2S1_RX,
76 .rqtype = DEVTOMEM,
77 }, {
78 .peri_id = (u8)DMACH_I2S1_TX,
79 .rqtype = MEMTODEV,
80 }, {
81 .peri_id = (u8)DMACH_MAX,
82 }, {
83 .peri_id = (u8)DMACH_MAX,
84 }, {
85 .peri_id = (u8)DMACH_SPI0_RX,
86 .rqtype = DEVTOMEM,
87 }, {
88 .peri_id = (u8)DMACH_SPI0_TX,
89 .rqtype = MEMTODEV,
90 }, {
91 .peri_id = (u8)DMACH_SPI1_RX,
92 .rqtype = DEVTOMEM,
93 }, {
94 .peri_id = (u8)DMACH_SPI1_TX,
95 .rqtype = MEMTODEV,
96 }, {
97 .peri_id = (u8)DMACH_MAX,
98 }, {
99 .peri_id = (u8)DMACH_MAX,
100 }, {
101 .peri_id = (u8)DMACH_AC97_MICIN,
102 .rqtype = DEVTOMEM,
103 }, {
104 .peri_id = (u8)DMACH_AC97_PCMIN,
105 .rqtype = DEVTOMEM,
106 }, {
107 .peri_id = (u8)DMACH_AC97_PCMOUT,
108 .rqtype = MEMTODEV,
109 }, {
110 .peri_id = (u8)DMACH_MAX,
111 }, {
112 .peri_id = (u8)DMACH_PWM,
113 }, {
114 .peri_id = (u8)DMACH_SPDIF,
115 .rqtype = MEMTODEV,
43 }, 116 },
44}; 117};
45 118
46static struct s3c_pl330_platdata s5pv210_pdma0_pdata = { 119struct dma_pl330_platdata s5pv210_pdma0_pdata = {
47 .peri = { 120 .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
48 [0] = DMACH_UART0_RX, 121 .peri = pdma0_peri,
49 [1] = DMACH_UART0_TX,
50 [2] = DMACH_UART1_RX,
51 [3] = DMACH_UART1_TX,
52 [4] = DMACH_UART2_RX,
53 [5] = DMACH_UART2_TX,
54 [6] = DMACH_UART3_RX,
55 [7] = DMACH_UART3_TX,
56 [8] = DMACH_MAX,
57 [9] = DMACH_I2S0_RX,
58 [10] = DMACH_I2S0_TX,
59 [11] = DMACH_I2S0S_TX,
60 [12] = DMACH_I2S1_RX,
61 [13] = DMACH_I2S1_TX,
62 [14] = DMACH_MAX,
63 [15] = DMACH_MAX,
64 [16] = DMACH_SPI0_RX,
65 [17] = DMACH_SPI0_TX,
66 [18] = DMACH_SPI1_RX,
67 [19] = DMACH_SPI1_TX,
68 [20] = DMACH_MAX,
69 [21] = DMACH_MAX,
70 [22] = DMACH_AC97_MICIN,
71 [23] = DMACH_AC97_PCMIN,
72 [24] = DMACH_AC97_PCMOUT,
73 [25] = DMACH_MAX,
74 [26] = DMACH_PWM,
75 [27] = DMACH_SPDIF,
76 [28] = DMACH_MAX,
77 [29] = DMACH_MAX,
78 [30] = DMACH_MAX,
79 [31] = DMACH_MAX,
80 },
81}; 122};
82 123
83static struct platform_device s5pv210_device_pdma0 = { 124struct amba_device s5pv210_device_pdma0 = {
84 .name = "s3c-pl330", 125 .dev = {
85 .id = 0, 126 .init_name = "dma-pl330.0",
86 .num_resources = ARRAY_SIZE(s5pv210_pdma0_resource),
87 .resource = s5pv210_pdma0_resource,
88 .dev = {
89 .dma_mask = &dma_dmamask, 127 .dma_mask = &dma_dmamask,
90 .coherent_dma_mask = DMA_BIT_MASK(32), 128 .coherent_dma_mask = DMA_BIT_MASK(32),
91 .platform_data = &s5pv210_pdma0_pdata, 129 .platform_data = &s5pv210_pdma0_pdata,
92 }, 130 },
93}; 131 .res = {
94 132 .start = S5PV210_PA_PDMA0,
95static struct resource s5pv210_pdma1_resource[] = { 133 .end = S5PV210_PA_PDMA0 + SZ_4K,
96 [0] = {
97 .start = S5PV210_PA_PDMA1,
98 .end = S5PV210_PA_PDMA1 + SZ_4K,
99 .flags = IORESOURCE_MEM, 134 .flags = IORESOURCE_MEM,
100 }, 135 },
101 [1] = { 136 .irq = {IRQ_PDMA0, NO_IRQ},
102 .start = IRQ_PDMA1, 137 .periphid = 0x00041330,
103 .end = IRQ_PDMA1,
104 .flags = IORESOURCE_IRQ,
105 },
106}; 138};
107 139
108static struct s3c_pl330_platdata s5pv210_pdma1_pdata = { 140struct dma_pl330_peri pdma1_peri[32] = {
109 .peri = { 141 {
110 [0] = DMACH_UART0_RX, 142 .peri_id = (u8)DMACH_UART0_RX,
111 [1] = DMACH_UART0_TX, 143 .rqtype = DEVTOMEM,
112 [2] = DMACH_UART1_RX, 144 }, {
113 [3] = DMACH_UART1_TX, 145 .peri_id = (u8)DMACH_UART0_TX,
114 [4] = DMACH_UART2_RX, 146 .rqtype = MEMTODEV,
115 [5] = DMACH_UART2_TX, 147 }, {
116 [6] = DMACH_UART3_RX, 148 .peri_id = (u8)DMACH_UART1_RX,
117 [7] = DMACH_UART3_TX, 149 .rqtype = DEVTOMEM,
118 [8] = DMACH_MAX, 150 }, {
119 [9] = DMACH_I2S0_RX, 151 .peri_id = (u8)DMACH_UART1_TX,
120 [10] = DMACH_I2S0_TX, 152 .rqtype = MEMTODEV,
121 [11] = DMACH_I2S0S_TX, 153 }, {
122 [12] = DMACH_I2S1_RX, 154 .peri_id = (u8)DMACH_UART2_RX,
123 [13] = DMACH_I2S1_TX, 155 .rqtype = DEVTOMEM,
124 [14] = DMACH_I2S2_RX, 156 }, {
125 [15] = DMACH_I2S2_TX, 157 .peri_id = (u8)DMACH_UART2_TX,
126 [16] = DMACH_SPI0_RX, 158 .rqtype = MEMTODEV,
127 [17] = DMACH_SPI0_TX, 159 }, {
128 [18] = DMACH_SPI1_RX, 160 .peri_id = (u8)DMACH_UART3_RX,
129 [19] = DMACH_SPI1_TX, 161 .rqtype = DEVTOMEM,
130 [20] = DMACH_MAX, 162 }, {
131 [21] = DMACH_MAX, 163 .peri_id = (u8)DMACH_UART3_TX,
132 [22] = DMACH_PCM0_RX, 164 .rqtype = MEMTODEV,
133 [23] = DMACH_PCM0_TX, 165 }, {
134 [24] = DMACH_PCM1_RX, 166 .peri_id = DMACH_MAX,
135 [25] = DMACH_PCM1_TX, 167 }, {
136 [26] = DMACH_MSM_REQ0, 168 .peri_id = (u8)DMACH_I2S0_RX,
137 [27] = DMACH_MSM_REQ1, 169 .rqtype = DEVTOMEM,
138 [28] = DMACH_MSM_REQ2, 170 }, {
139 [29] = DMACH_MSM_REQ3, 171 .peri_id = (u8)DMACH_I2S0_TX,
140 [30] = DMACH_PCM2_RX, 172 .rqtype = MEMTODEV,
141 [31] = DMACH_PCM2_TX, 173 }, {
174 .peri_id = (u8)DMACH_I2S0S_TX,
175 .rqtype = MEMTODEV,
176 }, {
177 .peri_id = (u8)DMACH_I2S1_RX,
178 .rqtype = DEVTOMEM,
179 }, {
180 .peri_id = (u8)DMACH_I2S1_TX,
181 .rqtype = MEMTODEV,
182 }, {
183 .peri_id = (u8)DMACH_I2S2_RX,
184 .rqtype = DEVTOMEM,
185 }, {
186 .peri_id = (u8)DMACH_I2S2_TX,
187 .rqtype = MEMTODEV,
188 }, {
189 .peri_id = (u8)DMACH_SPI0_RX,
190 .rqtype = DEVTOMEM,
191 }, {
192 .peri_id = (u8)DMACH_SPI0_TX,
193 .rqtype = MEMTODEV,
194 }, {
195 .peri_id = (u8)DMACH_SPI1_RX,
196 .rqtype = DEVTOMEM,
197 }, {
198 .peri_id = (u8)DMACH_SPI1_TX,
199 .rqtype = MEMTODEV,
200 }, {
201 .peri_id = (u8)DMACH_MAX,
202 }, {
203 .peri_id = (u8)DMACH_MAX,
204 }, {
205 .peri_id = (u8)DMACH_PCM0_RX,
206 .rqtype = DEVTOMEM,
207 }, {
208 .peri_id = (u8)DMACH_PCM0_TX,
209 .rqtype = MEMTODEV,
210 }, {
211 .peri_id = (u8)DMACH_PCM1_RX,
212 .rqtype = DEVTOMEM,
213 }, {
214 .peri_id = (u8)DMACH_PCM1_TX,
215 .rqtype = MEMTODEV,
216 }, {
217 .peri_id = (u8)DMACH_MSM_REQ0,
218 }, {
219 .peri_id = (u8)DMACH_MSM_REQ1,
220 }, {
221 .peri_id = (u8)DMACH_MSM_REQ2,
222 }, {
223 .peri_id = (u8)DMACH_MSM_REQ3,
224 }, {
225 .peri_id = (u8)DMACH_PCM2_RX,
226 .rqtype = DEVTOMEM,
227 }, {
228 .peri_id = (u8)DMACH_PCM2_TX,
229 .rqtype = MEMTODEV,
142 }, 230 },
143}; 231};
144 232
145static struct platform_device s5pv210_device_pdma1 = { 233struct dma_pl330_platdata s5pv210_pdma1_pdata = {
146 .name = "s3c-pl330", 234 .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
147 .id = 1, 235 .peri = pdma1_peri,
148 .num_resources = ARRAY_SIZE(s5pv210_pdma1_resource), 236};
149 .resource = s5pv210_pdma1_resource, 237
150 .dev = { 238struct amba_device s5pv210_device_pdma1 = {
239 .dev = {
240 .init_name = "dma-pl330.1",
151 .dma_mask = &dma_dmamask, 241 .dma_mask = &dma_dmamask,
152 .coherent_dma_mask = DMA_BIT_MASK(32), 242 .coherent_dma_mask = DMA_BIT_MASK(32),
153 .platform_data = &s5pv210_pdma1_pdata, 243 .platform_data = &s5pv210_pdma1_pdata,
154 }, 244 },
155}; 245 .res = {
156 246 .start = S5PV210_PA_PDMA1,
157static struct platform_device *s5pv210_dmacs[] __initdata = { 247 .end = S5PV210_PA_PDMA1 + SZ_4K,
158 &s5pv210_device_pdma0, 248 .flags = IORESOURCE_MEM,
159 &s5pv210_device_pdma1, 249 },
250 .irq = {IRQ_PDMA1, NO_IRQ},
251 .periphid = 0x00041330,
160}; 252};
161 253
162static int __init s5pv210_dma_init(void) 254static int __init s5pv210_dma_init(void)
163{ 255{
164 platform_add_devices(s5pv210_dmacs, ARRAY_SIZE(s5pv210_dmacs)); 256 amba_device_register(&s5pv210_device_pdma0, &iomem_resource);
165 257
166 return 0; 258 return 0;
167} 259}
diff --git a/arch/arm/mach-s5pv210/include/mach/dma.h b/arch/arm/mach-s5pv210/include/mach/dma.h
index 81209eb1409b..201842a3769e 100644
--- a/arch/arm/mach-s5pv210/include/mach/dma.h
+++ b/arch/arm/mach-s5pv210/include/mach/dma.h
@@ -20,7 +20,7 @@
20#ifndef __MACH_DMA_H 20#ifndef __MACH_DMA_H
21#define __MACH_DMA_H 21#define __MACH_DMA_H
22 22
23/* This platform uses the common S3C DMA API driver for PL330 */ 23/* This platform uses the common DMA API driver for PL330 */
24#include <plat/s3c-dma-pl330.h> 24#include <plat/dma-pl330.h>
25 25
26#endif /* __MACH_DMA_H */ 26#endif /* __MACH_DMA_H */
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 539bd0e3defd..53754bcf15a7 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config);
1094 * 1094 *
1095 * configure the dma source/destination hardware type and address 1095 * configure the dma source/destination hardware type and address
1096 * 1096 *
1097 * source: S3C2410_DMASRC_HW: source is hardware 1097 * source: DMA_FROM_DEVICE: source is hardware
1098 * S3C2410_DMASRC_MEM: source is memory 1098 * DMA_TO_DEVICE: source is memory
1099 * 1099 *
1100 * devaddr: physical address of the source 1100 * devaddr: physical address of the source
1101*/ 1101*/
1102 1102
1103int s3c2410_dma_devconfig(enum dma_ch channel, 1103int s3c2410_dma_devconfig(enum dma_ch channel,
1104 enum s3c2410_dmasrc source, 1104 enum dma_data_direction source,
1105 unsigned long devaddr) 1105 unsigned long devaddr)
1106{ 1106{
1107 struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); 1107 struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
1131 hwcfg |= S3C2410_DISRCC_INC; 1131 hwcfg |= S3C2410_DISRCC_INC;
1132 1132
1133 switch (source) { 1133 switch (source) {
1134 case S3C2410_DMASRC_HW: 1134 case DMA_FROM_DEVICE:
1135 /* source is hardware */ 1135 /* source is hardware */
1136 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", 1136 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
1137 __func__, devaddr, hwcfg); 1137 __func__, devaddr, hwcfg);
@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
1142 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); 1142 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1143 break; 1143 break;
1144 1144
1145 case S3C2410_DMASRC_MEM: 1145 case DMA_TO_DEVICE:
1146 /* source is memory */ 1146 /* source is memory */
1147 pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n", 1147 pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
1148 __func__, devaddr, hwcfg); 1148 __func__, devaddr, hwcfg);
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 3895f9aff0dc..7a96198e3a78 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -295,11 +295,14 @@ config S3C_DMA
295 help 295 help
296 Internal configuration for S3C DMA core 296 Internal configuration for S3C DMA core
297 297
298config S3C_PL330_DMA 298config SAMSUNG_DMADEV
299 bool 299 bool
300 select PL330 300 select DMADEVICES
301 select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \
302 CPU_S5P6450 || CPU_S5P6440)
303 select ARM_AMBA
301 help 304 help
302 S3C DMA API Driver for PL330 DMAC. 305 Use DMA device engine for PL330 DMAC.
303 306
304comment "Power management" 307comment "Power management"
305 308
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 09adb84f2718..3dd5dbad55c6 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -62,9 +62,9 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
62 62
63# DMA support 63# DMA support
64 64
65obj-$(CONFIG_S3C_DMA) += dma.o 65obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o
66 66
67obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o 67obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o
68 68
69# PM support 69# PM support
70 70
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
new file mode 100644
index 000000000000..6e3d9abc9e2e
--- /dev/null
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -0,0 +1,131 @@
1/* linux/arch/arm/plat-samsung/dma-ops.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Samsung DMA Operations
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/amba/pl330.h>
16#include <linux/scatterlist.h>
17
18#include <mach/dma.h>
19
20static inline bool pl330_filter(struct dma_chan *chan, void *param)
21{
22 struct dma_pl330_peri *peri = chan->private;
23 return peri->peri_id == (unsigned)param;
24}
25
26static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
27 struct samsung_dma_info *info)
28{
29 struct dma_chan *chan;
30 dma_cap_mask_t mask;
31 struct dma_slave_config slave_config;
32
33 dma_cap_zero(mask);
34 dma_cap_set(info->cap, mask);
35
36 chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
37
38 if (info->direction == DMA_FROM_DEVICE) {
39 memset(&slave_config, 0, sizeof(struct dma_slave_config));
40 slave_config.direction = info->direction;
41 slave_config.src_addr = info->fifo;
42 slave_config.src_addr_width = info->width;
43 slave_config.src_maxburst = 1;
44 dmaengine_slave_config(chan, &slave_config);
45 } else if (info->direction == DMA_TO_DEVICE) {
46 memset(&slave_config, 0, sizeof(struct dma_slave_config));
47 slave_config.direction = info->direction;
48 slave_config.dst_addr = info->fifo;
49 slave_config.dst_addr_width = info->width;
50 slave_config.dst_maxburst = 1;
51 dmaengine_slave_config(chan, &slave_config);
52 }
53
54 return (unsigned)chan;
55}
56
57static int samsung_dmadev_release(unsigned ch,
58 struct s3c2410_dma_client *client)
59{
60 dma_release_channel((struct dma_chan *)ch);
61
62 return 0;
63}
64
65static int samsung_dmadev_prepare(unsigned ch,
66 struct samsung_dma_prep_info *info)
67{
68 struct scatterlist sg;
69 struct dma_chan *chan = (struct dma_chan *)ch;
70 struct dma_async_tx_descriptor *desc;
71
72 switch (info->cap) {
73 case DMA_SLAVE:
74 sg_init_table(&sg, 1);
75 sg_dma_len(&sg) = info->len;
76 sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
77 info->len, offset_in_page(info->buf));
78 sg_dma_address(&sg) = info->buf;
79
80 desc = chan->device->device_prep_slave_sg(chan,
81 &sg, 1, info->direction, DMA_PREP_INTERRUPT);
82 break;
83 case DMA_CYCLIC:
84 desc = chan->device->device_prep_dma_cyclic(chan,
85 info->buf, info->len, info->period, info->direction);
86 break;
87 default:
88 dev_err(&chan->dev->device, "unsupported format\n");
89 return -EFAULT;
90 }
91
92 if (!desc) {
93 dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
94 return -EFAULT;
95 }
96
97 desc->callback = info->fp;
98 desc->callback_param = info->fp_param;
99
100 dmaengine_submit((struct dma_async_tx_descriptor *)desc);
101
102 return 0;
103}
104
105static inline int samsung_dmadev_trigger(unsigned ch)
106{
107 dma_async_issue_pending((struct dma_chan *)ch);
108
109 return 0;
110}
111
112static inline int samsung_dmadev_flush(unsigned ch)
113{
114 return dmaengine_terminate_all((struct dma_chan *)ch);
115}
116
117struct samsung_dma_ops dmadev_ops = {
118 .request = samsung_dmadev_request,
119 .release = samsung_dmadev_release,
120 .prepare = samsung_dmadev_prepare,
121 .trigger = samsung_dmadev_trigger,
122 .started = NULL,
123 .flush = samsung_dmadev_flush,
124 .stop = samsung_dmadev_flush,
125};
126
127void *samsung_dmadev_get_ops(void)
128{
129 return &dmadev_ops;
130}
131EXPORT_SYMBOL(samsung_dmadev_get_ops);
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
new file mode 100644
index 000000000000..4c1a363526cf
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
@@ -0,0 +1,63 @@
1/* arch/arm/plat-samsung/include/plat/dma-ops.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Samsung DMA support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __SAMSUNG_DMA_OPS_H_
14#define __SAMSUNG_DMA_OPS_H_ __FILE__
15
16#include <linux/dmaengine.h>
17
18struct samsung_dma_prep_info {
19 enum dma_transaction_type cap;
20 enum dma_data_direction direction;
21 dma_addr_t buf;
22 unsigned long period;
23 unsigned long len;
24 void (*fp)(void *data);
25 void *fp_param;
26};
27
28struct samsung_dma_info {
29 enum dma_transaction_type cap;
30 enum dma_data_direction direction;
31 enum dma_slave_buswidth width;
32 dma_addr_t fifo;
33 struct s3c2410_dma_client *client;
34};
35
36struct samsung_dma_ops {
37 unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
38 int (*release)(unsigned ch, struct s3c2410_dma_client *client);
39 int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
40 int (*trigger)(unsigned ch);
41 int (*started)(unsigned ch);
42 int (*flush)(unsigned ch);
43 int (*stop)(unsigned ch);
44};
45
46extern void *samsung_dmadev_get_ops(void);
47extern void *s3c_dma_get_ops(void);
48
49static inline void *__samsung_dma_get_ops(void)
50{
51 if (samsung_dma_is_dmadev())
52 return samsung_dmadev_get_ops();
53 else
54 return s3c_dma_get_ops();
55}
56
57/*
58 * samsung_dma_get_ops
59 * get the set of samsung dma operations
60 */
61#define samsung_dma_get_ops() __samsung_dma_get_ops()
62
63#endif /* __SAMSUNG_DMA_OPS_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index 810744213120..2e55e5958674 100644
--- a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -8,11 +8,8 @@
8 * (at your option) any later version. 8 * (at your option) any later version.
9 */ 9 */
10 10
11#ifndef __S3C_DMA_PL330_H_ 11#ifndef __DMA_PL330_H_
12#define __S3C_DMA_PL330_H_ 12#define __DMA_PL330_H_ __FILE__
13
14#define S3C2410_DMAF_AUTOSTART (1 << 0)
15#define S3C2410_DMAF_CIRCULAR (1 << 1)
16 13
17/* 14/*
18 * PL330 can assign any channel to communicate with 15 * PL330 can assign any channel to communicate with
@@ -20,7 +17,7 @@
20 * For the sake of consistency across client drivers, 17 * For the sake of consistency across client drivers,
21 * We keep the channel names unchanged and only add 18 * We keep the channel names unchanged and only add
22 * missing peripherals are added. 19 * missing peripherals are added.
23 * Order is not important since S3C PL330 API driver 20 * Order is not important since DMA PL330 API driver
24 * use these just as IDs. 21 * use these just as IDs.
25 */ 22 */
26enum dma_ch { 23enum dma_ch {
@@ -88,11 +85,20 @@ enum dma_ch {
88 DMACH_MAX, 85 DMACH_MAX,
89}; 86};
90 87
91static inline bool s3c_dma_has_circular(void) 88struct s3c2410_dma_client {
89 char *name;
90};
91
92static inline bool samsung_dma_has_circular(void)
93{
94 return true;
95}
96
97static inline bool samsung_dma_is_dmadev(void)
92{ 98{
93 return true; 99 return true;
94} 100}
95 101
96#include <plat/dma.h> 102#include <plat/dma-ops.h>
97 103
98#endif /* __S3C_DMA_PL330_H_ */ 104#endif /* __DMA_PL330_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
index ab9bce637cbd..1c1ed5481253 100644
--- a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
+++ b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
@@ -41,7 +41,7 @@ struct s3c24xx_dma_selection {
41 41
42 void (*direction)(struct s3c2410_dma_chan *chan, 42 void (*direction)(struct s3c2410_dma_chan *chan,
43 struct s3c24xx_dma_map *map, 43 struct s3c24xx_dma_map *map,
44 enum s3c2410_dmasrc dir); 44 enum dma_data_direction dir);
45}; 45};
46 46
47extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); 47extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
index 8c273b7a6f56..b9061128abde 100644
--- a/arch/arm/plat-samsung/include/plat/dma.h
+++ b/arch/arm/plat-samsung/include/plat/dma.h
@@ -10,17 +10,14 @@
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11*/ 11*/
12 12
13#include <linux/dma-mapping.h>
14
13enum s3c2410_dma_buffresult { 15enum s3c2410_dma_buffresult {
14 S3C2410_RES_OK, 16 S3C2410_RES_OK,
15 S3C2410_RES_ERR, 17 S3C2410_RES_ERR,
16 S3C2410_RES_ABORT 18 S3C2410_RES_ABORT
17}; 19};
18 20
19enum s3c2410_dmasrc {
20 S3C2410_DMASRC_HW, /* source is memory */
21 S3C2410_DMASRC_MEM /* source is hardware */
22};
23
24/* enum s3c2410_chan_op 21/* enum s3c2410_chan_op
25 * 22 *
26 * operation codes passed to the DMA code by the user, and also used 23 * operation codes passed to the DMA code by the user, and also used
@@ -112,7 +109,7 @@ extern int s3c2410_dma_config(enum dma_ch channel, int xferunit);
112*/ 109*/
113 110
114extern int s3c2410_dma_devconfig(enum dma_ch channel, 111extern int s3c2410_dma_devconfig(enum dma_ch channel,
115 enum s3c2410_dmasrc source, unsigned long devaddr); 112 enum dma_data_direction source, unsigned long devaddr);
116 113
117/* s3c2410_dma_getposition 114/* s3c2410_dma_getposition
118 * 115 *
@@ -126,3 +123,4 @@ extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn);
126extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); 123extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn);
127 124
128 125
126#include <plat/dma-ops.h>
diff --git a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
deleted file mode 100644
index bf5e2a9d408d..000000000000
--- a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
+++ /dev/null
@@ -1,32 +0,0 @@
1/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
2 *
3 * Copyright (C) 2010 Samsung Electronics Co. Ltd.
4 * Jaswinder Singh <jassi.brar@samsung.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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __S3C_PL330_PDATA_H
13#define __S3C_PL330_PDATA_H
14
15#include <plat/s3c-dma-pl330.h>
16
17/*
18 * Every PL330 DMAC has max 32 peripheral interfaces,
19 * of which some may be not be really used in your
20 * DMAC's configuration.
21 * Populate this array of 32 peri i/fs with relevant
22 * channel IDs for used peri i/f and DMACH_MAX for
23 * those unused.
24 *
25 * The platforms just need to provide this info
26 * to the S3C DMA API driver for PL330.
27 */
28struct s3c_pl330_platdata {
29 enum dma_ch peri[32];
30};
31
32#endif /* __S3C_PL330_PDATA_H */
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
new file mode 100644
index 000000000000..582333c70585
--- /dev/null
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -0,0 +1,130 @@
1/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Samsung S3C-DMA Operations
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/slab.h>
16#include <linux/types.h>
17
18#include <mach/dma.h>
19
20struct cb_data {
21 void (*fp) (void *);
22 void *fp_param;
23 unsigned ch;
24 struct list_head node;
25};
26
27static LIST_HEAD(dma_list);
28
29static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
30 int size, enum s3c2410_dma_buffresult res)
31{
32 struct cb_data *data = param;
33
34 data->fp(data->fp_param);
35}
36
37static unsigned s3c_dma_request(enum dma_ch dma_ch,
38 struct samsung_dma_info *info)
39{
40 struct cb_data *data;
41
42 if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
43 s3c2410_dma_free(dma_ch, info->client);
44 return 0;
45 }
46
47 data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
48 data->ch = dma_ch;
49 list_add_tail(&data->node, &dma_list);
50
51 s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
52
53 if (info->cap == DMA_CYCLIC)
54 s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
55
56 s3c2410_dma_config(dma_ch, info->width);
57
58 return (unsigned)dma_ch;
59}
60
61static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
62{
63 struct cb_data *data;
64
65 list_for_each_entry(data, &dma_list, node)
66 if (data->ch == ch)
67 break;
68 list_del(&data->node);
69
70 s3c2410_dma_free(ch, client);
71 kfree(data);
72
73 return 0;
74}
75
76static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
77{
78 struct cb_data *data;
79 int len = (info->cap == DMA_CYCLIC) ? info->period : info->len;
80
81 list_for_each_entry(data, &dma_list, node)
82 if (data->ch == ch)
83 break;
84
85 if (!data->fp) {
86 s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
87 data->fp = info->fp;
88 data->fp_param = info->fp_param;
89 }
90
91 s3c2410_dma_enqueue(ch, (void *)data, info->buf, len);
92
93 return 0;
94}
95
96static inline int s3c_dma_trigger(unsigned ch)
97{
98 return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
99}
100
101static inline int s3c_dma_started(unsigned ch)
102{
103 return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
104}
105
106static inline int s3c_dma_flush(unsigned ch)
107{
108 return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
109}
110
111static inline int s3c_dma_stop(unsigned ch)
112{
113 return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
114}
115
116static struct samsung_dma_ops s3c_dma_ops = {
117 .request = s3c_dma_request,
118 .release = s3c_dma_release,
119 .prepare = s3c_dma_prepare,
120 .trigger = s3c_dma_trigger,
121 .started = s3c_dma_started,
122 .flush = s3c_dma_flush,
123 .stop = s3c_dma_stop,
124};
125
126void *s3c_dma_get_ops(void)
127{
128 return &s3c_dma_ops;
129}
130EXPORT_SYMBOL(s3c_dma_get_ops);
diff --git a/arch/arm/plat-samsung/s3c-pl330.c b/arch/arm/plat-samsung/s3c-pl330.c
deleted file mode 100644
index f85638c6f5ae..000000000000
--- a/arch/arm/plat-samsung/s3c-pl330.c
+++ /dev/null
@@ -1,1244 +0,0 @@
1/* linux/arch/arm/plat-samsung/s3c-pl330.c
2 *
3 * Copyright (C) 2010 Samsung Electronics Co. Ltd.
4 * Jaswinder Singh <jassi.brar@samsung.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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/io.h>
16#include <linux/slab.h>
17#include <linux/platform_device.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20
21#include <asm/hardware/pl330.h>
22
23#include <plat/s3c-pl330-pdata.h>
24
25/**
26 * struct s3c_pl330_dmac - Logical representation of a PL330 DMAC.
27 * @busy_chan: Number of channels currently busy.
28 * @peri: List of IDs of peripherals this DMAC can work with.
29 * @node: To attach to the global list of DMACs.
30 * @pi: PL330 configuration info for the DMAC.
31 * @kmcache: Pool to quickly allocate xfers for all channels in the dmac.
32 * @clk: Pointer of DMAC operation clock.
33 */
34struct s3c_pl330_dmac {
35 unsigned busy_chan;
36 enum dma_ch *peri;
37 struct list_head node;
38 struct pl330_info *pi;
39 struct kmem_cache *kmcache;
40 struct clk *clk;
41};
42
43/**
44 * struct s3c_pl330_xfer - A request submitted by S3C DMA clients.
45 * @token: Xfer ID provided by the client.
46 * @node: To attach to the list of xfers on a channel.
47 * @px: Xfer for PL330 core.
48 * @chan: Owner channel of this xfer.
49 */
50struct s3c_pl330_xfer {
51 void *token;
52 struct list_head node;
53 struct pl330_xfer px;
54 struct s3c_pl330_chan *chan;
55};
56
57/**
58 * struct s3c_pl330_chan - Logical channel to communicate with
59 * a Physical peripheral.
60 * @pl330_chan_id: Token of a hardware channel thread of PL330 DMAC.
61 * NULL if the channel is available to be acquired.
62 * @id: ID of the peripheral that this channel can communicate with.
63 * @options: Options specified by the client.
64 * @sdaddr: Address provided via s3c2410_dma_devconfig.
65 * @node: To attach to the global list of channels.
66 * @lrq: Pointer to the last submitted pl330_req to PL330 core.
67 * @xfer_list: To manage list of xfers enqueued.
68 * @req: Two requests to communicate with the PL330 engine.
69 * @callback_fn: Callback function to the client.
70 * @rqcfg: Channel configuration for the xfers.
71 * @xfer_head: Pointer to the xfer to be next executed.
72 * @dmac: Pointer to the DMAC that manages this channel, NULL if the
73 * channel is available to be acquired.
74 * @client: Client of this channel. NULL if the
75 * channel is available to be acquired.
76 */
77struct s3c_pl330_chan {
78 void *pl330_chan_id;
79 enum dma_ch id;
80 unsigned int options;
81 unsigned long sdaddr;
82 struct list_head node;
83 struct pl330_req *lrq;
84 struct list_head xfer_list;
85 struct pl330_req req[2];
86 s3c2410_dma_cbfn_t callback_fn;
87 struct pl330_reqcfg rqcfg;
88 struct s3c_pl330_xfer *xfer_head;
89 struct s3c_pl330_dmac *dmac;
90 struct s3c2410_dma_client *client;
91};
92
93/* All DMACs in the platform */
94static LIST_HEAD(dmac_list);
95
96/* All channels to peripherals in the platform */
97static LIST_HEAD(chan_list);
98
99/*
100 * Since we add resources(DMACs and Channels) to the global pool,
101 * we need to guard access to the resources using a global lock
102 */
103static DEFINE_SPINLOCK(res_lock);
104
105/* Returns the channel with ID 'id' in the chan_list */
106static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id)
107{
108 struct s3c_pl330_chan *ch;
109
110 list_for_each_entry(ch, &chan_list, node)
111 if (ch->id == id)
112 return ch;
113
114 return NULL;
115}
116
117/* Allocate a new channel with ID 'id' and add to chan_list */
118static void chan_add(const enum dma_ch id)
119{
120 struct s3c_pl330_chan *ch = id_to_chan(id);
121
122 /* Return if the channel already exists */
123 if (ch)
124 return;
125
126 ch = kmalloc(sizeof(*ch), GFP_KERNEL);
127 /* Return silently to work with other channels */
128 if (!ch)
129 return;
130
131 ch->id = id;
132 ch->dmac = NULL;
133
134 list_add_tail(&ch->node, &chan_list);
135}
136
137/* If the channel is not yet acquired by any client */
138static bool chan_free(struct s3c_pl330_chan *ch)
139{
140 if (!ch)
141 return false;
142
143 /* Channel points to some DMAC only when it's acquired */
144 return ch->dmac ? false : true;
145}
146
147/*
148 * Returns 0 is peripheral i/f is invalid or not present on the dmac.
149 * Index + 1, otherwise.
150 */
151static unsigned iface_of_dmac(struct s3c_pl330_dmac *dmac, enum dma_ch ch_id)
152{
153 enum dma_ch *id = dmac->peri;
154 int i;
155
156 /* Discount invalid markers */
157 if (ch_id == DMACH_MAX)
158 return 0;
159
160 for (i = 0; i < PL330_MAX_PERI; i++)
161 if (id[i] == ch_id)
162 return i + 1;
163
164 return 0;
165}
166
167/* If all channel threads of the DMAC are busy */
168static inline bool dmac_busy(struct s3c_pl330_dmac *dmac)
169{
170 struct pl330_info *pi = dmac->pi;
171
172 return (dmac->busy_chan < pi->pcfg.num_chan) ? false : true;
173}
174
175/*
176 * Returns the number of free channels that
177 * can be handled by this dmac only.
178 */
179static unsigned ch_onlyby_dmac(struct s3c_pl330_dmac *dmac)
180{
181 enum dma_ch *id = dmac->peri;
182 struct s3c_pl330_dmac *d;
183 struct s3c_pl330_chan *ch;
184 unsigned found, count = 0;
185 enum dma_ch p;
186 int i;
187
188 for (i = 0; i < PL330_MAX_PERI; i++) {
189 p = id[i];
190 ch = id_to_chan(p);
191
192 if (p == DMACH_MAX || !chan_free(ch))
193 continue;
194
195 found = 0;
196 list_for_each_entry(d, &dmac_list, node) {
197 if (d != dmac && iface_of_dmac(d, ch->id)) {
198 found = 1;
199 break;
200 }
201 }
202 if (!found)
203 count++;
204 }
205
206 return count;
207}
208
209/*
210 * Measure of suitability of 'dmac' handling 'ch'
211 *
212 * 0 indicates 'dmac' can not handle 'ch' either
213 * because it is not supported by the hardware or
214 * because all dmac channels are currently busy.
215 *
216 * >0 vlaue indicates 'dmac' has the capability.
217 * The bigger the value the more suitable the dmac.
218 */
219#define MAX_SUIT UINT_MAX
220#define MIN_SUIT 0
221
222static unsigned suitablility(struct s3c_pl330_dmac *dmac,
223 struct s3c_pl330_chan *ch)
224{
225 struct pl330_info *pi = dmac->pi;
226 enum dma_ch *id = dmac->peri;
227 struct s3c_pl330_dmac *d;
228 unsigned s;
229 int i;
230
231 s = MIN_SUIT;
232 /* If all the DMAC channel threads are busy */
233 if (dmac_busy(dmac))
234 return s;
235
236 for (i = 0; i < PL330_MAX_PERI; i++)
237 if (id[i] == ch->id)
238 break;
239
240 /* If the 'dmac' can't talk to 'ch' */
241 if (i == PL330_MAX_PERI)
242 return s;
243
244 s = MAX_SUIT;
245 list_for_each_entry(d, &dmac_list, node) {
246 /*
247 * If some other dmac can talk to this
248 * peri and has some channel free.
249 */
250 if (d != dmac && iface_of_dmac(d, ch->id) && !dmac_busy(d)) {
251 s = 0;
252 break;
253 }
254 }
255 if (s)
256 return s;
257
258 s = 100;
259
260 /* Good if free chans are more, bad otherwise */
261 s += (pi->pcfg.num_chan - dmac->busy_chan) - ch_onlyby_dmac(dmac);
262
263 return s;
264}
265
266/* More than one DMAC may have capability to transfer data with the
267 * peripheral. This function assigns most suitable DMAC to manage the
268 * channel and hence communicate with the peripheral.
269 */
270static struct s3c_pl330_dmac *map_chan_to_dmac(struct s3c_pl330_chan *ch)
271{
272 struct s3c_pl330_dmac *d, *dmac = NULL;
273 unsigned sn, sl = MIN_SUIT;
274
275 list_for_each_entry(d, &dmac_list, node) {
276 sn = suitablility(d, ch);
277
278 if (sn == MAX_SUIT)
279 return d;
280
281 if (sn > sl)
282 dmac = d;
283 }
284
285 return dmac;
286}
287
288/* Acquire the channel for peripheral 'id' */
289static struct s3c_pl330_chan *chan_acquire(const enum dma_ch id)
290{
291 struct s3c_pl330_chan *ch = id_to_chan(id);
292 struct s3c_pl330_dmac *dmac;
293
294 /* If the channel doesn't exist or is already acquired */
295 if (!ch || !chan_free(ch)) {
296 ch = NULL;
297 goto acq_exit;
298 }
299
300 dmac = map_chan_to_dmac(ch);
301 /* If couldn't map */
302 if (!dmac) {
303 ch = NULL;
304 goto acq_exit;
305 }
306
307 dmac->busy_chan++;
308 ch->dmac = dmac;
309
310acq_exit:
311 return ch;
312}
313
314/* Delete xfer from the queue */
315static inline void del_from_queue(struct s3c_pl330_xfer *xfer)
316{
317 struct s3c_pl330_xfer *t;
318 struct s3c_pl330_chan *ch;
319 int found;
320
321 if (!xfer)
322 return;
323
324 ch = xfer->chan;
325
326 /* Make sure xfer is in the queue */
327 found = 0;
328 list_for_each_entry(t, &ch->xfer_list, node)
329 if (t == xfer) {
330 found = 1;
331 break;
332 }
333
334 if (!found)
335 return;
336
337 /* If xfer is last entry in the queue */
338 if (xfer->node.next == &ch->xfer_list)
339 t = list_entry(ch->xfer_list.next,
340 struct s3c_pl330_xfer, node);
341 else
342 t = list_entry(xfer->node.next,
343 struct s3c_pl330_xfer, node);
344
345 /* If there was only one node left */
346 if (t == xfer)
347 ch->xfer_head = NULL;
348 else if (ch->xfer_head == xfer)
349 ch->xfer_head = t;
350
351 list_del(&xfer->node);
352}
353
354/* Provides pointer to the next xfer in the queue.
355 * If CIRCULAR option is set, the list is left intact,
356 * otherwise the xfer is removed from the list.
357 * Forced delete 'pluck' can be set to override the CIRCULAR option.
358 */
359static struct s3c_pl330_xfer *get_from_queue(struct s3c_pl330_chan *ch,
360 int pluck)
361{
362 struct s3c_pl330_xfer *xfer = ch->xfer_head;
363
364 if (!xfer)
365 return NULL;
366
367 /* If xfer is last entry in the queue */
368 if (xfer->node.next == &ch->xfer_list)
369 ch->xfer_head = list_entry(ch->xfer_list.next,
370 struct s3c_pl330_xfer, node);
371 else
372 ch->xfer_head = list_entry(xfer->node.next,
373 struct s3c_pl330_xfer, node);
374
375 if (pluck || !(ch->options & S3C2410_DMAF_CIRCULAR))
376 del_from_queue(xfer);
377
378 return xfer;
379}
380
381static inline void add_to_queue(struct s3c_pl330_chan *ch,
382 struct s3c_pl330_xfer *xfer, int front)
383{
384 struct pl330_xfer *xt;
385
386 /* If queue empty */
387 if (ch->xfer_head == NULL)
388 ch->xfer_head = xfer;
389
390 xt = &ch->xfer_head->px;
391 /* If the head already submitted (CIRCULAR head) */
392 if (ch->options & S3C2410_DMAF_CIRCULAR &&
393 (xt == ch->req[0].x || xt == ch->req[1].x))
394 ch->xfer_head = xfer;
395
396 /* If this is a resubmission, it should go at the head */
397 if (front) {
398 ch->xfer_head = xfer;
399 list_add(&xfer->node, &ch->xfer_list);
400 } else {
401 list_add_tail(&xfer->node, &ch->xfer_list);
402 }
403}
404
405static inline void _finish_off(struct s3c_pl330_xfer *xfer,
406 enum s3c2410_dma_buffresult res, int ffree)
407{
408 struct s3c_pl330_chan *ch;
409
410 if (!xfer)
411 return;
412
413 ch = xfer->chan;
414
415 /* Do callback */
416 if (ch->callback_fn)
417 ch->callback_fn(NULL, xfer->token, xfer->px.bytes, res);
418
419 /* Force Free or if buffer is not needed anymore */
420 if (ffree || !(ch->options & S3C2410_DMAF_CIRCULAR))
421 kmem_cache_free(ch->dmac->kmcache, xfer);
422}
423
424static inline int s3c_pl330_submit(struct s3c_pl330_chan *ch,
425 struct pl330_req *r)
426{
427 struct s3c_pl330_xfer *xfer;
428 int ret = 0;
429
430 /* If already submitted */
431 if (r->x)
432 return 0;
433
434 xfer = get_from_queue(ch, 0);
435 if (xfer) {
436 r->x = &xfer->px;
437
438 /* Use max bandwidth for M<->M xfers */
439 if (r->rqtype == MEMTOMEM) {
440 struct pl330_info *pi = xfer->chan->dmac->pi;
441 int burst = 1 << ch->rqcfg.brst_size;
442 u32 bytes = r->x->bytes;
443 int bl;
444
445 bl = pi->pcfg.data_bus_width / 8;
446 bl *= pi->pcfg.data_buf_dep;
447 bl /= burst;
448
449 /* src/dst_burst_len can't be more than 16 */
450 if (bl > 16)
451 bl = 16;
452
453 while (bl > 1) {
454 if (!(bytes % (bl * burst)))
455 break;
456 bl--;
457 }
458
459 ch->rqcfg.brst_len = bl;
460 } else {
461 ch->rqcfg.brst_len = 1;
462 }
463
464 ret = pl330_submit_req(ch->pl330_chan_id, r);
465
466 /* If submission was successful */
467 if (!ret) {
468 ch->lrq = r; /* latest submitted req */
469 return 0;
470 }
471
472 r->x = NULL;
473
474 /* If both of the PL330 ping-pong buffers filled */
475 if (ret == -EAGAIN) {
476 dev_err(ch->dmac->pi->dev, "%s:%d!\n",
477 __func__, __LINE__);
478 /* Queue back again */
479 add_to_queue(ch, xfer, 1);
480 ret = 0;
481 } else {
482 dev_err(ch->dmac->pi->dev, "%s:%d!\n",
483 __func__, __LINE__);
484 _finish_off(xfer, S3C2410_RES_ERR, 0);
485 }
486 }
487
488 return ret;
489}
490
491static void s3c_pl330_rq(struct s3c_pl330_chan *ch,
492 struct pl330_req *r, enum pl330_op_err err)
493{
494 unsigned long flags;
495 struct s3c_pl330_xfer *xfer;
496 struct pl330_xfer *xl = r->x;
497 enum s3c2410_dma_buffresult res;
498
499 spin_lock_irqsave(&res_lock, flags);
500
501 r->x = NULL;
502
503 s3c_pl330_submit(ch, r);
504
505 spin_unlock_irqrestore(&res_lock, flags);
506
507 /* Map result to S3C DMA API */
508 if (err == PL330_ERR_NONE)
509 res = S3C2410_RES_OK;
510 else if (err == PL330_ERR_ABORT)
511 res = S3C2410_RES_ABORT;
512 else
513 res = S3C2410_RES_ERR;
514
515 /* If last request had some xfer */
516 if (xl) {
517 xfer = container_of(xl, struct s3c_pl330_xfer, px);
518 _finish_off(xfer, res, 0);
519 } else {
520 dev_info(ch->dmac->pi->dev, "%s:%d No Xfer?!\n",
521 __func__, __LINE__);
522 }
523}
524
525static void s3c_pl330_rq0(void *token, enum pl330_op_err err)
526{
527 struct pl330_req *r = token;
528 struct s3c_pl330_chan *ch = container_of(r,
529 struct s3c_pl330_chan, req[0]);
530 s3c_pl330_rq(ch, r, err);
531}
532
533static void s3c_pl330_rq1(void *token, enum pl330_op_err err)
534{
535 struct pl330_req *r = token;
536 struct s3c_pl330_chan *ch = container_of(r,
537 struct s3c_pl330_chan, req[1]);
538 s3c_pl330_rq(ch, r, err);
539}
540
541/* Release an acquired channel */
542static void chan_release(struct s3c_pl330_chan *ch)
543{
544 struct s3c_pl330_dmac *dmac;
545
546 if (chan_free(ch))
547 return;
548
549 dmac = ch->dmac;
550 ch->dmac = NULL;
551 dmac->busy_chan--;
552}
553
554int s3c2410_dma_ctrl(enum dma_ch id, enum s3c2410_chan_op op)
555{
556 struct s3c_pl330_xfer *xfer;
557 enum pl330_chan_op pl330op;
558 struct s3c_pl330_chan *ch;
559 unsigned long flags;
560 int idx, ret;
561
562 spin_lock_irqsave(&res_lock, flags);
563
564 ch = id_to_chan(id);
565
566 if (!ch || chan_free(ch)) {
567 ret = -EINVAL;
568 goto ctrl_exit;
569 }
570
571 switch (op) {
572 case S3C2410_DMAOP_START:
573 /* Make sure both reqs are enqueued */
574 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
575 s3c_pl330_submit(ch, &ch->req[idx]);
576 s3c_pl330_submit(ch, &ch->req[1 - idx]);
577 pl330op = PL330_OP_START;
578 break;
579
580 case S3C2410_DMAOP_STOP:
581 pl330op = PL330_OP_ABORT;
582 break;
583
584 case S3C2410_DMAOP_FLUSH:
585 pl330op = PL330_OP_FLUSH;
586 break;
587
588 case S3C2410_DMAOP_PAUSE:
589 case S3C2410_DMAOP_RESUME:
590 case S3C2410_DMAOP_TIMEOUT:
591 case S3C2410_DMAOP_STARTED:
592 spin_unlock_irqrestore(&res_lock, flags);
593 return 0;
594
595 default:
596 spin_unlock_irqrestore(&res_lock, flags);
597 return -EINVAL;
598 }
599
600 ret = pl330_chan_ctrl(ch->pl330_chan_id, pl330op);
601
602 if (pl330op == PL330_OP_START) {
603 spin_unlock_irqrestore(&res_lock, flags);
604 return ret;
605 }
606
607 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
608
609 /* Abort the current xfer */
610 if (ch->req[idx].x) {
611 xfer = container_of(ch->req[idx].x,
612 struct s3c_pl330_xfer, px);
613
614 /* Drop xfer during FLUSH */
615 if (pl330op == PL330_OP_FLUSH)
616 del_from_queue(xfer);
617
618 ch->req[idx].x = NULL;
619
620 spin_unlock_irqrestore(&res_lock, flags);
621 _finish_off(xfer, S3C2410_RES_ABORT,
622 pl330op == PL330_OP_FLUSH ? 1 : 0);
623 spin_lock_irqsave(&res_lock, flags);
624 }
625
626 /* Flush the whole queue */
627 if (pl330op == PL330_OP_FLUSH) {
628
629 if (ch->req[1 - idx].x) {
630 xfer = container_of(ch->req[1 - idx].x,
631 struct s3c_pl330_xfer, px);
632
633 del_from_queue(xfer);
634
635 ch->req[1 - idx].x = NULL;
636
637 spin_unlock_irqrestore(&res_lock, flags);
638 _finish_off(xfer, S3C2410_RES_ABORT, 1);
639 spin_lock_irqsave(&res_lock, flags);
640 }
641
642 /* Finish off the remaining in the queue */
643 xfer = ch->xfer_head;
644 while (xfer) {
645
646 del_from_queue(xfer);
647
648 spin_unlock_irqrestore(&res_lock, flags);
649 _finish_off(xfer, S3C2410_RES_ABORT, 1);
650 spin_lock_irqsave(&res_lock, flags);
651
652 xfer = ch->xfer_head;
653 }
654 }
655
656ctrl_exit:
657 spin_unlock_irqrestore(&res_lock, flags);
658
659 return ret;
660}
661EXPORT_SYMBOL(s3c2410_dma_ctrl);
662
663int s3c2410_dma_enqueue(enum dma_ch id, void *token,
664 dma_addr_t addr, int size)
665{
666 struct s3c_pl330_chan *ch;
667 struct s3c_pl330_xfer *xfer;
668 unsigned long flags;
669 int idx, ret = 0;
670
671 spin_lock_irqsave(&res_lock, flags);
672
673 ch = id_to_chan(id);
674
675 /* Error if invalid or free channel */
676 if (!ch || chan_free(ch)) {
677 ret = -EINVAL;
678 goto enq_exit;
679 }
680
681 /* Error if size is unaligned */
682 if (ch->rqcfg.brst_size && size % (1 << ch->rqcfg.brst_size)) {
683 ret = -EINVAL;
684 goto enq_exit;
685 }
686
687 xfer = kmem_cache_alloc(ch->dmac->kmcache, GFP_ATOMIC);
688 if (!xfer) {
689 ret = -ENOMEM;
690 goto enq_exit;
691 }
692
693 xfer->token = token;
694 xfer->chan = ch;
695 xfer->px.bytes = size;
696 xfer->px.next = NULL; /* Single request */
697
698 /* For S3C DMA API, direction is always fixed for all xfers */
699 if (ch->req[0].rqtype == MEMTODEV) {
700 xfer->px.src_addr = addr;
701 xfer->px.dst_addr = ch->sdaddr;
702 } else {
703 xfer->px.src_addr = ch->sdaddr;
704 xfer->px.dst_addr = addr;
705 }
706
707 add_to_queue(ch, xfer, 0);
708
709 /* Try submitting on either request */
710 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
711
712 if (!ch->req[idx].x)
713 s3c_pl330_submit(ch, &ch->req[idx]);
714 else
715 s3c_pl330_submit(ch, &ch->req[1 - idx]);
716
717 spin_unlock_irqrestore(&res_lock, flags);
718
719 if (ch->options & S3C2410_DMAF_AUTOSTART)
720 s3c2410_dma_ctrl(id, S3C2410_DMAOP_START);
721
722 return 0;
723
724enq_exit:
725 spin_unlock_irqrestore(&res_lock, flags);
726
727 return ret;
728}
729EXPORT_SYMBOL(s3c2410_dma_enqueue);
730
731int s3c2410_dma_request(enum dma_ch id,
732 struct s3c2410_dma_client *client,
733 void *dev)
734{
735 struct s3c_pl330_dmac *dmac;
736 struct s3c_pl330_chan *ch;
737 unsigned long flags;
738 int ret = 0;
739
740 spin_lock_irqsave(&res_lock, flags);
741
742 ch = chan_acquire(id);
743 if (!ch) {
744 ret = -EBUSY;
745 goto req_exit;
746 }
747
748 dmac = ch->dmac;
749
750 ch->pl330_chan_id = pl330_request_channel(dmac->pi);
751 if (!ch->pl330_chan_id) {
752 chan_release(ch);
753 ret = -EBUSY;
754 goto req_exit;
755 }
756
757 ch->client = client;
758 ch->options = 0; /* Clear any option */
759 ch->callback_fn = NULL; /* Clear any callback */
760 ch->lrq = NULL;
761
762 ch->rqcfg.brst_size = 2; /* Default word size */
763 ch->rqcfg.swap = SWAP_NO;
764 ch->rqcfg.scctl = SCCTRL0; /* Noncacheable and nonbufferable */
765 ch->rqcfg.dcctl = DCCTRL0; /* Noncacheable and nonbufferable */
766 ch->rqcfg.privileged = 0;
767 ch->rqcfg.insnaccess = 0;
768
769 /* Set invalid direction */
770 ch->req[0].rqtype = DEVTODEV;
771 ch->req[1].rqtype = ch->req[0].rqtype;
772
773 ch->req[0].cfg = &ch->rqcfg;
774 ch->req[1].cfg = ch->req[0].cfg;
775
776 ch->req[0].peri = iface_of_dmac(dmac, id) - 1; /* Original index */
777 ch->req[1].peri = ch->req[0].peri;
778
779 ch->req[0].token = &ch->req[0];
780 ch->req[0].xfer_cb = s3c_pl330_rq0;
781 ch->req[1].token = &ch->req[1];
782 ch->req[1].xfer_cb = s3c_pl330_rq1;
783
784 ch->req[0].x = NULL;
785 ch->req[1].x = NULL;
786
787 /* Reset xfer list */
788 INIT_LIST_HEAD(&ch->xfer_list);
789 ch->xfer_head = NULL;
790
791req_exit:
792 spin_unlock_irqrestore(&res_lock, flags);
793
794 return ret;
795}
796EXPORT_SYMBOL(s3c2410_dma_request);
797
798int s3c2410_dma_free(enum dma_ch id, struct s3c2410_dma_client *client)
799{
800 struct s3c_pl330_chan *ch;
801 struct s3c_pl330_xfer *xfer;
802 unsigned long flags;
803 int ret = 0;
804 unsigned idx;
805
806 spin_lock_irqsave(&res_lock, flags);
807
808 ch = id_to_chan(id);
809
810 if (!ch || chan_free(ch))
811 goto free_exit;
812
813 /* Refuse if someone else wanted to free the channel */
814 if (ch->client != client) {
815 ret = -EBUSY;
816 goto free_exit;
817 }
818
819 /* Stop any active xfer, Flushe the queue and do callbacks */
820 pl330_chan_ctrl(ch->pl330_chan_id, PL330_OP_FLUSH);
821
822 /* Abort the submitted requests */
823 idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
824
825 if (ch->req[idx].x) {
826 xfer = container_of(ch->req[idx].x,
827 struct s3c_pl330_xfer, px);
828
829 ch->req[idx].x = NULL;
830 del_from_queue(xfer);
831
832 spin_unlock_irqrestore(&res_lock, flags);
833 _finish_off(xfer, S3C2410_RES_ABORT, 1);
834 spin_lock_irqsave(&res_lock, flags);
835 }
836
837 if (ch->req[1 - idx].x) {
838 xfer = container_of(ch->req[1 - idx].x,
839 struct s3c_pl330_xfer, px);
840
841 ch->req[1 - idx].x = NULL;
842 del_from_queue(xfer);
843
844 spin_unlock_irqrestore(&res_lock, flags);
845 _finish_off(xfer, S3C2410_RES_ABORT, 1);
846 spin_lock_irqsave(&res_lock, flags);
847 }
848
849 /* Pluck and Abort the queued requests in order */
850 do {
851 xfer = get_from_queue(ch, 1);
852
853 spin_unlock_irqrestore(&res_lock, flags);
854 _finish_off(xfer, S3C2410_RES_ABORT, 1);
855 spin_lock_irqsave(&res_lock, flags);
856 } while (xfer);
857
858 ch->client = NULL;
859
860 pl330_release_channel(ch->pl330_chan_id);
861
862 ch->pl330_chan_id = NULL;
863
864 chan_release(ch);
865
866free_exit:
867 spin_unlock_irqrestore(&res_lock, flags);
868
869 return ret;
870}
871EXPORT_SYMBOL(s3c2410_dma_free);
872
873int s3c2410_dma_config(enum dma_ch id, int xferunit)
874{
875 struct s3c_pl330_chan *ch;
876 struct pl330_info *pi;
877 unsigned long flags;
878 int i, dbwidth, ret = 0;
879
880 spin_lock_irqsave(&res_lock, flags);
881
882 ch = id_to_chan(id);
883
884 if (!ch || chan_free(ch)) {
885 ret = -EINVAL;
886 goto cfg_exit;
887 }
888
889 pi = ch->dmac->pi;
890 dbwidth = pi->pcfg.data_bus_width / 8;
891
892 /* Max size of xfer can be pcfg.data_bus_width */
893 if (xferunit > dbwidth) {
894 ret = -EINVAL;
895 goto cfg_exit;
896 }
897
898 i = 0;
899 while (xferunit != (1 << i))
900 i++;
901
902 /* If valid value */
903 if (xferunit == (1 << i))
904 ch->rqcfg.brst_size = i;
905 else
906 ret = -EINVAL;
907
908cfg_exit:
909 spin_unlock_irqrestore(&res_lock, flags);
910
911 return ret;
912}
913EXPORT_SYMBOL(s3c2410_dma_config);
914
915/* Options that are supported by this driver */
916#define S3C_PL330_FLAGS (S3C2410_DMAF_CIRCULAR | S3C2410_DMAF_AUTOSTART)
917
918int s3c2410_dma_setflags(enum dma_ch id, unsigned int options)
919{
920 struct s3c_pl330_chan *ch;
921 unsigned long flags;
922 int ret = 0;
923
924 spin_lock_irqsave(&res_lock, flags);
925
926 ch = id_to_chan(id);
927
928 if (!ch || chan_free(ch) || options & ~(S3C_PL330_FLAGS))
929 ret = -EINVAL;
930 else
931 ch->options = options;
932
933 spin_unlock_irqrestore(&res_lock, flags);
934
935 return 0;
936}
937EXPORT_SYMBOL(s3c2410_dma_setflags);
938
939int s3c2410_dma_set_buffdone_fn(enum dma_ch id, s3c2410_dma_cbfn_t rtn)
940{
941 struct s3c_pl330_chan *ch;
942 unsigned long flags;
943 int ret = 0;
944
945 spin_lock_irqsave(&res_lock, flags);
946
947 ch = id_to_chan(id);
948
949 if (!ch || chan_free(ch))
950 ret = -EINVAL;
951 else
952 ch->callback_fn = rtn;
953
954 spin_unlock_irqrestore(&res_lock, flags);
955
956 return ret;
957}
958EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
959
960int s3c2410_dma_devconfig(enum dma_ch id, enum s3c2410_dmasrc source,
961 unsigned long address)
962{
963 struct s3c_pl330_chan *ch;
964 unsigned long flags;
965 int ret = 0;
966
967 spin_lock_irqsave(&res_lock, flags);
968
969 ch = id_to_chan(id);
970
971 if (!ch || chan_free(ch)) {
972 ret = -EINVAL;
973 goto devcfg_exit;
974 }
975
976 switch (source) {
977 case S3C2410_DMASRC_HW: /* P->M */
978 ch->req[0].rqtype = DEVTOMEM;
979 ch->req[1].rqtype = DEVTOMEM;
980 ch->rqcfg.src_inc = 0;
981 ch->rqcfg.dst_inc = 1;
982 break;
983 case S3C2410_DMASRC_MEM: /* M->P */
984 ch->req[0].rqtype = MEMTODEV;
985 ch->req[1].rqtype = MEMTODEV;
986 ch->rqcfg.src_inc = 1;
987 ch->rqcfg.dst_inc = 0;
988 break;
989 default:
990 ret = -EINVAL;
991 goto devcfg_exit;
992 }
993
994 ch->sdaddr = address;
995
996devcfg_exit:
997 spin_unlock_irqrestore(&res_lock, flags);
998
999 return ret;
1000}
1001EXPORT_SYMBOL(s3c2410_dma_devconfig);
1002
1003int s3c2410_dma_getposition(enum dma_ch id, dma_addr_t *src, dma_addr_t *dst)
1004{
1005 struct s3c_pl330_chan *ch = id_to_chan(id);
1006 struct pl330_chanstatus status;
1007 int ret;
1008
1009 if (!ch || chan_free(ch))
1010 return -EINVAL;
1011
1012 ret = pl330_chan_status(ch->pl330_chan_id, &status);
1013 if (ret < 0)
1014 return ret;
1015
1016 *src = status.src_addr;
1017 *dst = status.dst_addr;
1018
1019 return 0;
1020}
1021EXPORT_SYMBOL(s3c2410_dma_getposition);
1022
1023static irqreturn_t pl330_irq_handler(int irq, void *data)
1024{
1025 if (pl330_update(data))
1026 return IRQ_HANDLED;
1027 else
1028 return IRQ_NONE;
1029}
1030
1031static int pl330_probe(struct platform_device *pdev)
1032{
1033 struct s3c_pl330_dmac *s3c_pl330_dmac;
1034 struct s3c_pl330_platdata *pl330pd;
1035 struct pl330_info *pl330_info;
1036 struct resource *res;
1037 int i, ret, irq;
1038
1039 pl330pd = pdev->dev.platform_data;
1040
1041 /* Can't do without the list of _32_ peripherals */
1042 if (!pl330pd || !pl330pd->peri) {
1043 dev_err(&pdev->dev, "platform data missing!\n");
1044 return -ENODEV;
1045 }
1046
1047 pl330_info = kzalloc(sizeof(*pl330_info), GFP_KERNEL);
1048 if (!pl330_info)
1049 return -ENOMEM;
1050
1051 pl330_info->pl330_data = NULL;
1052 pl330_info->dev = &pdev->dev;
1053
1054 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1055 if (!res) {
1056 ret = -ENODEV;
1057 goto probe_err1;
1058 }
1059
1060 request_mem_region(res->start, resource_size(res), pdev->name);
1061
1062 pl330_info->base = ioremap(res->start, resource_size(res));
1063 if (!pl330_info->base) {
1064 ret = -ENXIO;
1065 goto probe_err2;
1066 }
1067
1068 irq = platform_get_irq(pdev, 0);
1069 if (irq < 0) {
1070 ret = irq;
1071 goto probe_err3;
1072 }
1073
1074 ret = request_irq(irq, pl330_irq_handler, 0,
1075 dev_name(&pdev->dev), pl330_info);
1076 if (ret)
1077 goto probe_err4;
1078
1079 /* Allocate a new DMAC */
1080 s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL);
1081 if (!s3c_pl330_dmac) {
1082 ret = -ENOMEM;
1083 goto probe_err5;
1084 }
1085
1086 /* Get operation clock and enable it */
1087 s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma");
1088 if (IS_ERR(s3c_pl330_dmac->clk)) {
1089 dev_err(&pdev->dev, "Cannot get operation clock.\n");
1090 ret = -EINVAL;
1091 goto probe_err6;
1092 }
1093 clk_enable(s3c_pl330_dmac->clk);
1094
1095 ret = pl330_add(pl330_info);
1096 if (ret)
1097 goto probe_err7;
1098
1099 /* Hook the info */
1100 s3c_pl330_dmac->pi = pl330_info;
1101
1102 /* No busy channels */
1103 s3c_pl330_dmac->busy_chan = 0;
1104
1105 s3c_pl330_dmac->kmcache = kmem_cache_create(dev_name(&pdev->dev),
1106 sizeof(struct s3c_pl330_xfer), 0, 0, NULL);
1107
1108 if (!s3c_pl330_dmac->kmcache) {
1109 ret = -ENOMEM;
1110 goto probe_err8;
1111 }
1112
1113 /* Get the list of peripherals */
1114 s3c_pl330_dmac->peri = pl330pd->peri;
1115
1116 /* Attach to the list of DMACs */
1117 list_add_tail(&s3c_pl330_dmac->node, &dmac_list);
1118
1119 /* Create a channel for each peripheral in the DMAC
1120 * that is, if it doesn't already exist
1121 */
1122 for (i = 0; i < PL330_MAX_PERI; i++)
1123 if (s3c_pl330_dmac->peri[i] != DMACH_MAX)
1124 chan_add(s3c_pl330_dmac->peri[i]);
1125
1126 printk(KERN_INFO
1127 "Loaded driver for PL330 DMAC-%d %s\n", pdev->id, pdev->name);
1128 printk(KERN_INFO
1129 "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
1130 pl330_info->pcfg.data_buf_dep,
1131 pl330_info->pcfg.data_bus_width / 8, pl330_info->pcfg.num_chan,
1132 pl330_info->pcfg.num_peri, pl330_info->pcfg.num_events);
1133
1134 return 0;
1135
1136probe_err8:
1137 pl330_del(pl330_info);
1138probe_err7:
1139 clk_disable(s3c_pl330_dmac->clk);
1140 clk_put(s3c_pl330_dmac->clk);
1141probe_err6:
1142 kfree(s3c_pl330_dmac);
1143probe_err5:
1144 free_irq(irq, pl330_info);
1145probe_err4:
1146probe_err3:
1147 iounmap(pl330_info->base);
1148probe_err2:
1149 release_mem_region(res->start, resource_size(res));
1150probe_err1:
1151 kfree(pl330_info);
1152
1153 return ret;
1154}
1155
1156static int pl330_remove(struct platform_device *pdev)
1157{
1158 struct s3c_pl330_dmac *dmac, *d;
1159 struct s3c_pl330_chan *ch;
1160 unsigned long flags;
1161 int del, found;
1162
1163 if (!pdev->dev.platform_data)
1164 return -EINVAL;
1165
1166 spin_lock_irqsave(&res_lock, flags);
1167
1168 found = 0;
1169 list_for_each_entry(d, &dmac_list, node)
1170 if (d->pi->dev == &pdev->dev) {
1171 found = 1;
1172 break;
1173 }
1174
1175 if (!found) {
1176 spin_unlock_irqrestore(&res_lock, flags);
1177 return 0;
1178 }
1179
1180 dmac = d;
1181
1182 /* Remove all Channels that are managed only by this DMAC */
1183 list_for_each_entry(ch, &chan_list, node) {
1184
1185 /* Only channels that are handled by this DMAC */
1186 if (iface_of_dmac(dmac, ch->id))
1187 del = 1;
1188 else
1189 continue;
1190
1191 /* Don't remove if some other DMAC has it too */
1192 list_for_each_entry(d, &dmac_list, node)
1193 if (d != dmac && iface_of_dmac(d, ch->id)) {
1194 del = 0;
1195 break;
1196 }
1197
1198 if (del) {
1199 spin_unlock_irqrestore(&res_lock, flags);
1200 s3c2410_dma_free(ch->id, ch->client);
1201 spin_lock_irqsave(&res_lock, flags);
1202 list_del(&ch->node);
1203 kfree(ch);
1204 }
1205 }
1206
1207 /* Disable operation clock */
1208 clk_disable(dmac->clk);
1209 clk_put(dmac->clk);
1210
1211 /* Remove the DMAC */
1212 list_del(&dmac->node);
1213 kfree(dmac);
1214
1215 spin_unlock_irqrestore(&res_lock, flags);
1216
1217 return 0;
1218}
1219
1220static struct platform_driver pl330_driver = {
1221 .driver = {
1222 .owner = THIS_MODULE,
1223 .name = "s3c-pl330",
1224 },
1225 .probe = pl330_probe,
1226 .remove = pl330_remove,
1227};
1228
1229static int __init pl330_init(void)
1230{
1231 return platform_driver_register(&pl330_driver);
1232}
1233module_init(pl330_init);
1234
1235static void __exit pl330_exit(void)
1236{
1237 platform_driver_unregister(&pl330_driver);
1238 return;
1239}
1240module_exit(pl330_exit);
1241
1242MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
1243MODULE_DESCRIPTION("Driver for PL330 DMA Controller");
1244MODULE_LICENSE("GPL");