Commit 0745c9a5 authored by Vinod Koul's avatar Vinod Koul Committed by Vinod Koul

Merge branch 'samsung_dma' into next

parents f8de8f4c 51ddf31d
...@@ -11,7 +11,7 @@ if ARCH_EXYNOS4 ...@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
config CPU_EXYNOS4210 config CPU_EXYNOS4210
bool bool
select S3C_PL330_DMA select SAMSUNG_DMADEV
help help
Enable EXYNOS4210 CPU support Enable EXYNOS4210 CPU support
......
...@@ -43,6 +43,11 @@ static struct clk clk_sclk_usbphy1 = { ...@@ -43,6 +43,11 @@ static struct clk clk_sclk_usbphy1 = {
.name = "sclk_usbphy1", .name = "sclk_usbphy1",
}; };
static struct clk dummy_apb_pclk = {
.name = "apb_pclk",
.id = -1,
};
static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable) static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
{ {
return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable); return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
...@@ -454,12 +459,12 @@ static struct clk init_clocks_off[] = { ...@@ -454,12 +459,12 @@ static struct clk init_clocks_off[] = {
.enable = exynos4_clk_ip_fsys_ctrl, .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 10), .ctrlbit = (1 << 10),
}, { }, {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.0", .devname = "s3c-pl330.0",
.enable = exynos4_clk_ip_fsys_ctrl, .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 0), .ctrlbit = (1 << 0),
}, { }, {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.1", .devname = "s3c-pl330.1",
.enable = exynos4_clk_ip_fsys_ctrl, .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 1), .ctrlbit = (1 << 1),
...@@ -1210,5 +1215,7 @@ void __init exynos4_register_clocks(void) ...@@ -1210,5 +1215,7 @@ void __init exynos4_register_clocks(void)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init(); s3c_pwmclk_init();
} }
...@@ -21,151 +21,228 @@ ...@@ -21,151 +21,228 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
#include <asm/irq.h>
#include <plat/devs.h> #include <plat/devs.h>
#include <plat/irqs.h> #include <plat/irqs.h>
#include <mach/map.h> #include <mach/map.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/dma.h>
#include <plat/s3c-pl330-pdata.h>
static u64 dma_dmamask = DMA_BIT_MASK(32); static u64 dma_dmamask = DMA_BIT_MASK(32);
static struct resource exynos4_pdma0_resource[] = { struct dma_pl330_peri pdma0_peri[28] = {
[0] = { {
.start = EXYNOS4_PA_PDMA0, .peri_id = (u8)DMACH_PCM0_RX,
.end = EXYNOS4_PA_PDMA0 + SZ_4K, .rqtype = DEVTOMEM,
.flags = IORESOURCE_MEM, }, {
}, .peri_id = (u8)DMACH_PCM0_TX,
[1] = { .rqtype = MEMTODEV,
.start = IRQ_PDMA0, }, {
.end = IRQ_PDMA0, .peri_id = (u8)DMACH_PCM2_RX,
.flags = IORESOURCE_IRQ, .rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MSM_REQ0,
}, {
.peri_id = (u8)DMACH_MSM_REQ2,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART4_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART4_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS4_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS4_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_AC97_MICIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMOUT,
.rqtype = MEMTODEV,
}, },
}; };
static struct s3c_pl330_platdata exynos4_pdma0_pdata = { struct dma_pl330_platdata exynos4_pdma0_pdata = {
.peri = { .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
[0] = DMACH_PCM0_RX, .peri = pdma0_peri,
[1] = DMACH_PCM0_TX,
[2] = DMACH_PCM2_RX,
[3] = DMACH_PCM2_TX,
[4] = DMACH_MSM_REQ0,
[5] = DMACH_MSM_REQ2,
[6] = DMACH_SPI0_RX,
[7] = DMACH_SPI0_TX,
[8] = DMACH_SPI2_RX,
[9] = DMACH_SPI2_TX,
[10] = DMACH_I2S0S_TX,
[11] = DMACH_I2S0_RX,
[12] = DMACH_I2S0_TX,
[13] = DMACH_I2S2_RX,
[14] = DMACH_I2S2_TX,
[15] = DMACH_UART0_RX,
[16] = DMACH_UART0_TX,
[17] = DMACH_UART2_RX,
[18] = DMACH_UART2_TX,
[19] = DMACH_UART4_RX,
[20] = DMACH_UART4_TX,
[21] = DMACH_SLIMBUS0_RX,
[22] = DMACH_SLIMBUS0_TX,
[23] = DMACH_SLIMBUS2_RX,
[24] = DMACH_SLIMBUS2_TX,
[25] = DMACH_SLIMBUS4_RX,
[26] = DMACH_SLIMBUS4_TX,
[27] = DMACH_AC97_MICIN,
[28] = DMACH_AC97_PCMIN,
[29] = DMACH_AC97_PCMOUT,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
}; };
static struct platform_device exynos4_device_pdma0 = { struct amba_device exynos4_device_pdma0 = {
.name = "s3c-pl330", .dev = {
.id = 0, .init_name = "dma-pl330.0",
.num_resources = ARRAY_SIZE(exynos4_pdma0_resource),
.resource = exynos4_pdma0_resource,
.dev = {
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &exynos4_pdma0_pdata, .platform_data = &exynos4_pdma0_pdata,
}, },
.res = {
.start = EXYNOS4_PA_PDMA0,
.end = EXYNOS4_PA_PDMA0 + SZ_4K,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_PDMA0, NO_IRQ},
.periphid = 0x00041330,
}; };
static struct resource exynos4_pdma1_resource[] = { struct dma_pl330_peri pdma1_peri[25] = {
[0] = { {
.start = EXYNOS4_PA_PDMA1, .peri_id = (u8)DMACH_PCM0_RX,
.end = EXYNOS4_PA_PDMA1 + SZ_4K, .rqtype = DEVTOMEM,
.flags = IORESOURCE_MEM, }, {
}, .peri_id = (u8)DMACH_PCM0_TX,
[1] = { .rqtype = MEMTODEV,
.start = IRQ_PDMA1, }, {
.end = IRQ_PDMA1, .peri_id = (u8)DMACH_PCM1_RX,
.flags = IORESOURCE_IRQ, .rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MSM_REQ1,
}, {
.peri_id = (u8)DMACH_MSM_REQ3,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART3_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART3_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS3_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS3_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SLIMBUS5_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SLIMBUS5_TX,
.rqtype = MEMTODEV,
}, },
}; };
static struct s3c_pl330_platdata exynos4_pdma1_pdata = { struct dma_pl330_platdata exynos4_pdma1_pdata = {
.peri = { .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
[0] = DMACH_PCM0_RX, .peri = pdma1_peri,
[1] = DMACH_PCM0_TX,
[2] = DMACH_PCM1_RX,
[3] = DMACH_PCM1_TX,
[4] = DMACH_MSM_REQ1,
[5] = DMACH_MSM_REQ3,
[6] = DMACH_SPI1_RX,
[7] = DMACH_SPI1_TX,
[8] = DMACH_I2S0S_TX,
[9] = DMACH_I2S0_RX,
[10] = DMACH_I2S0_TX,
[11] = DMACH_I2S1_RX,
[12] = DMACH_I2S1_TX,
[13] = DMACH_UART0_RX,
[14] = DMACH_UART0_TX,
[15] = DMACH_UART1_RX,
[16] = DMACH_UART1_TX,
[17] = DMACH_UART3_RX,
[18] = DMACH_UART3_TX,
[19] = DMACH_SLIMBUS1_RX,
[20] = DMACH_SLIMBUS1_TX,
[21] = DMACH_SLIMBUS3_RX,
[22] = DMACH_SLIMBUS3_TX,
[23] = DMACH_SLIMBUS5_RX,
[24] = DMACH_SLIMBUS5_TX,
[25] = DMACH_SLIMBUS0AUX_RX,
[26] = DMACH_SLIMBUS0AUX_TX,
[27] = DMACH_SPDIF,
[28] = DMACH_MAX,
[29] = DMACH_MAX,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
}; };
static struct platform_device exynos4_device_pdma1 = { struct amba_device exynos4_device_pdma1 = {
.name = "s3c-pl330", .dev = {
.id = 1, .init_name = "dma-pl330.1",
.num_resources = ARRAY_SIZE(exynos4_pdma1_resource),
.resource = exynos4_pdma1_resource,
.dev = {
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &exynos4_pdma1_pdata, .platform_data = &exynos4_pdma1_pdata,
}, },
}; .res = {
.start = EXYNOS4_PA_PDMA1,
static struct platform_device *exynos4_dmacs[] __initdata = { .end = EXYNOS4_PA_PDMA1 + SZ_4K,
&exynos4_device_pdma0, .flags = IORESOURCE_MEM,
&exynos4_device_pdma1, },
.irq = {IRQ_PDMA1, NO_IRQ},
.periphid = 0x00041330,
}; };
static int __init exynos4_dma_init(void) static int __init exynos4_dma_init(void)
{ {
platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs)); amba_device_register(&exynos4_device_pdma0, &iomem_resource);
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H #ifndef __MACH_DMA_H
#define __MACH_DMA_H #define __MACH_DMA_H
/* This platform uses the common S3C DMA API driver for PL330 */ /* This platform uses the common DMA API driver for PL330 */
#include <plat/s3c-dma-pl330.h> #include <plat/dma-pl330.h>
#endif /* __MACH_DMA_H */ #endif /* __MACH_DMA_H */
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#ifndef __ASM_ARCH_DMA_H #ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__ #define __ASM_ARCH_DMA_H __FILE__
#include <plat/dma.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
...@@ -51,6 +50,18 @@ enum dma_ch { ...@@ -51,6 +50,18 @@ enum dma_ch {
DMACH_MAX, /* the end entry */ DMACH_MAX, /* the end entry */
}; };
static inline bool samsung_dma_has_circular(void)
{
return false;
}
static inline bool samsung_dma_is_dmadev(void)
{
return false;
}
#include <plat/dma.h>
#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ #define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
/* we have 4 dma channels */ /* we have 4 dma channels */
...@@ -163,7 +174,7 @@ struct s3c2410_dma_chan { ...@@ -163,7 +174,7 @@ struct s3c2410_dma_chan {
struct s3c2410_dma_client *client; struct s3c2410_dma_client *client;
/* channel configuration */ /* channel configuration */
enum s3c2410_dmasrc source; enum dma_data_direction source;
enum dma_ch req_ch; enum dma_ch req_ch;
unsigned long dev_addr; unsigned long dev_addr;
unsigned long load_timeout; unsigned long load_timeout;
...@@ -196,9 +207,4 @@ struct s3c2410_dma_chan { ...@@ -196,9 +207,4 @@ struct s3c2410_dma_chan {
typedef unsigned long dma_device_t; typedef unsigned long dma_device_t;
static inline bool s3c_dma_has_circular(void)
{
return false;
}
#endif /* __ASM_ARCH_DMA_H */ #endif /* __ASM_ARCH_DMA_H */
...@@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = { ...@@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan, static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
struct s3c24xx_dma_map *map, struct s3c24xx_dma_map *map,
enum s3c2410_dmasrc dir) enum dma_data_direction dir)
{ {
unsigned long chsel; unsigned long chsel;
if (dir == S3C2410_DMASRC_HW) if (dir == DMA_FROM_DEVICE)
chsel = map->channels_rx[0]; chsel = map->channels_rx[0];
else else
chsel = map->channels[0]; chsel = map->channels[0];
......
...@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, ...@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
u32 control0, control1; u32 control0, control1;
switch (chan->source) { switch (chan->source) {
case S3C2410_DMASRC_HW: case DMA_FROM_DEVICE:
src = chan->dev_addr; src = chan->dev_addr;
dst = data; dst = data;
control0 = PL080_CONTROL_SRC_AHB2; control0 = PL080_CONTROL_SRC_AHB2;
control0 |= PL080_CONTROL_DST_INCR; control0 |= PL080_CONTROL_DST_INCR;
break; break;
case S3C2410_DMASRC_MEM: case DMA_TO_DEVICE:
src = data; src = data;
dst = chan->dev_addr; dst = chan->dev_addr;
control0 = PL080_CONTROL_DST_AHB2; control0 = PL080_CONTROL_DST_AHB2;
...@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue); ...@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue);
int s3c2410_dma_devconfig(enum dma_ch channel, int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source, enum dma_data_direction source,
unsigned long devaddr) unsigned long devaddr)
{ {
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
...@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(enum dma_ch channel, ...@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
pr_debug("%s: peripheral %d\n", __func__, peripheral); pr_debug("%s: peripheral %d\n", __func__, peripheral);
switch (source) { switch (source) {
case S3C2410_DMASRC_HW: case DMA_FROM_DEVICE:
config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT; config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT; config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
break; break;
case S3C2410_DMASRC_MEM: case DMA_TO_DEVICE:
config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT; config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT; config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
break; break;
......
...@@ -58,11 +58,15 @@ enum dma_ch { ...@@ -58,11 +58,15 @@ enum dma_ch {
DMACH_MAX /* the end */ DMACH_MAX /* the end */
}; };
static __inline__ bool s3c_dma_has_circular(void) static inline bool samsung_dma_has_circular(void)
{ {
return true; return true;
} }
static inline bool samsung_dma_is_dmadev(void)
{
return false;
}
#define S3C2410_DMAF_CIRCULAR (1 << 0) #define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h> #include <plat/dma.h>
...@@ -95,7 +99,7 @@ struct s3c2410_dma_chan { ...@@ -95,7 +99,7 @@ struct s3c2410_dma_chan {
unsigned char peripheral; unsigned char peripheral;
unsigned int flags; unsigned int flags;
enum s3c2410_dmasrc source; enum dma_data_direction source;
dma_addr_t dev_addr; dma_addr_t dev_addr;
......
...@@ -9,14 +9,14 @@ if ARCH_S5P64X0 ...@@ -9,14 +9,14 @@ if ARCH_S5P64X0
config CPU_S5P6440 config CPU_S5P6440
bool bool
select S3C_PL330_DMA select SAMSUNG_DMADEV
select S5P_HRT select S5P_HRT
help help
Enable S5P6440 CPU support Enable S5P6440 CPU support
config CPU_S5P6450 config CPU_S5P6450
bool bool
select S3C_PL330_DMA select SAMSUNG_DMADEV
select S5P_HRT select S5P_HRT
help help
Enable S5P6450 CPU support Enable S5P6450 CPU support
......
...@@ -146,7 +146,7 @@ static struct clk init_clocks_off[] = { ...@@ -146,7 +146,7 @@ static struct clk init_clocks_off[] = {
.enable = s5p64x0_hclk0_ctrl, .enable = s5p64x0_hclk0_ctrl,
.ctrlbit = (1 << 8), .ctrlbit = (1 << 8),
}, { }, {
.name = "pdma", .name = "dma",
.parent = &clk_hclk_low.clk, .parent = &clk_hclk_low.clk,
.enable = s5p64x0_hclk0_ctrl, .enable = s5p64x0_hclk0_ctrl,
.ctrlbit = (1 << 12), .ctrlbit = (1 << 12),
...@@ -499,6 +499,11 @@ static struct clksrc_clk *sysclks[] = { ...@@ -499,6 +499,11 @@ static struct clksrc_clk *sysclks[] = {
&clk_pclk_low, &clk_pclk_low,
}; };
static struct clk dummy_apb_pclk = {
.name = "apb_pclk",
.id = -1,
};
void __init_or_cpufreq s5p6440_setup_clocks(void) void __init_or_cpufreq s5p6440_setup_clocks(void)
{ {
struct clk *xtal_clk; struct clk *xtal_clk;
...@@ -581,5 +586,7 @@ void __init s5p6440_register_clocks(void) ...@@ -581,5 +586,7 @@ void __init s5p6440_register_clocks(void)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init(); s3c_pwmclk_init();
} }
...@@ -179,7 +179,7 @@ static struct clk init_clocks_off[] = { ...@@ -179,7 +179,7 @@ static struct clk init_clocks_off[] = {
.enable = s5p64x0_hclk0_ctrl, .enable = s5p64x0_hclk0_ctrl,
.ctrlbit = (1 << 3), .ctrlbit = (1 << 3),
}, { }, {
.name = "pdma", .name = "dma",
.parent = &clk_hclk_low.clk, .parent = &clk_hclk_low.clk,
.enable = s5p64x0_hclk0_ctrl, .enable = s5p64x0_hclk0_ctrl,
.ctrlbit = (1 << 12), .ctrlbit = (1 << 12),
...@@ -553,6 +553,11 @@ static struct clksrc_clk *sysclks[] = { ...@@ -553,6 +553,11 @@ static struct clksrc_clk *sysclks[] = {
&clk_sclk_audio0, &clk_sclk_audio0,
}; };
static struct clk dummy_apb_pclk = {
.name = "apb_pclk",
.id = -1,
};
void __init_or_cpufreq s5p6450_setup_clocks(void) void __init_or_cpufreq s5p6450_setup_clocks(void)
{ {
struct clk *xtal_clk; struct clk *xtal_clk;
...@@ -632,5 +637,7 @@ void __init s5p6450_register_clocks(void) ...@@ -632,5 +637,7 @@ void __init s5p6450_register_clocks(void)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init(); s3c_pwmclk_init();
} }
...@@ -21,128 +21,219 @@ ...@@ -21,128 +21,219 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
#include <asm/irq.h>
#include <mach/map.h> #include <mach/map.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/regs-clock.h> #include <mach/regs-clock.h>
#include <mach/dma.h>
#include <plat/devs.h> #include <plat/devs.h>
#include <plat/s3c-pl330-pdata.h> #include <plat/irqs.h>
static u64 dma_dmamask = DMA_BIT_MASK(32); static u64 dma_dmamask = DMA_BIT_MASK(32);
static struct resource s5p64x0_pdma_resource[] = { struct dma_pl330_peri s5p6440_pdma_peri[22] = {
[0] = { {
.start = S5P64X0_PA_PDMA, .peri_id = (u8)DMACH_UART0_RX,
.end = S5P64X0_PA_PDMA + SZ_4K, .rqtype = DEVTOMEM,
.flags = IORESOURCE_MEM, }, {
}, .peri_id = (u8)DMACH_UART0_TX,
[1] = { .rqtype = MEMTODEV,
.start = IRQ_DMA0, }, {
.end = IRQ_DMA0, .peri_id = (u8)DMACH_UART1_RX,
.flags = IORESOURCE_IRQ, .rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART3_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART3_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = DMACH_MAX,
}, {
.peri_id = DMACH_MAX,
}, {
.peri_id = (u8)DMACH_PCM0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, },
}; };
static struct s3c_pl330_platdata s5p6440_pdma_pdata = { struct dma_pl330_platdata s5p6440_pdma_pdata = {
.peri = { .nr_valid_peri = ARRAY_SIZE(s5p6440_pdma_peri),
[0] = DMACH_UART0_RX, .peri = s5p6440_pdma_peri,
[1] = DMACH_UART0_TX,
[2] = DMACH_UART1_RX,
[3] = DMACH_UART1_TX,
[4] = DMACH_UART2_RX,
[5] = DMACH_UART2_TX,
[6] = DMACH_UART3_RX,
[7] = DMACH_UART3_TX,
[8] = DMACH_MAX,
[9] = DMACH_MAX,
[10] = DMACH_PCM0_TX,
[11] = DMACH_PCM0_RX,
[12] = DMACH_I2S0_TX,
[13] = DMACH_I2S0_RX,
[14] = DMACH_SPI0_TX,
[15] = DMACH_SPI0_RX,
[16] = DMACH_MAX,
[17] = DMACH_MAX,
[18] = DMACH_MAX,
[19] = DMACH_MAX,
[20] = DMACH_SPI1_TX,
[21] = DMACH_SPI1_RX,
[22] = DMACH_MAX,
[23] = DMACH_MAX,
[24] = DMACH_MAX,
[25] = DMACH_MAX,
[26] = DMACH_MAX,
[27] = DMACH_MAX,
[28] = DMACH_MAX,
[29] = DMACH_PWM,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
}; };
static struct s3c_pl330_platdata s5p6450_pdma_pdata = { struct dma_pl330_peri s5p6450_pdma_peri[32] = {
.peri = { {
[0] = DMACH_UART0_RX, .peri_id = (u8)DMACH_UART0_RX,
[1] = DMACH_UART0_TX, .rqtype = DEVTOMEM,
[2] = DMACH_UART1_RX, }, {
[3] = DMACH_UART1_TX, .peri_id = (u8)DMACH_UART0_TX,
[4] = DMACH_UART2_RX, .rqtype = MEMTODEV,
[5] = DMACH_UART2_TX, }, {
[6] = DMACH_UART3_RX, .peri_id = (u8)DMACH_UART1_RX,
[7] = DMACH_UART3_TX, .rqtype = DEVTOMEM,
[8] = DMACH_UART4_RX, }, {
[9] = DMACH_UART4_TX, .peri_id = (u8)DMACH_UART1_TX,
[10] = DMACH_PCM0_TX, .rqtype = MEMTODEV,
[11] = DMACH_PCM0_RX, }, {
[12] = DMACH_I2S0_TX, .peri_id = (u8)DMACH_UART2_RX,
[13] = DMACH_I2S0_RX, .rqtype = DEVTOMEM,
[14] = DMACH_SPI0_TX, }, {
[15] = DMACH_SPI0_RX, .peri_id = (u8)DMACH_UART2_TX,
[16] = DMACH_PCM1_TX, .rqtype = MEMTODEV,
[17] = DMACH_PCM1_RX, }, {
[18] = DMACH_PCM2_TX, .peri_id = (u8)DMACH_UART3_RX,
[19] = DMACH_PCM2_RX, .rqtype = DEVTOMEM,
[20] = DMACH_SPI1_TX, }, {
[21] = DMACH_SPI1_RX, .peri_id = (u8)DMACH_UART3_TX,
[22] = DMACH_USI_TX, .rqtype = MEMTODEV,
[23] = DMACH_USI_RX, }, {
[24] = DMACH_MAX, .peri_id = (u8)DMACH_UART4_RX,
[25] = DMACH_I2S1_TX, .rqtype = DEVTOMEM,
[26] = DMACH_I2S1_RX, }, {
[27] = DMACH_I2S2_TX, .peri_id = (u8)DMACH_UART4_TX,
[28] = DMACH_I2S2_RX, .rqtype = MEMTODEV,
[29] = DMACH_PWM, }, {
[30] = DMACH_UART5_RX, .peri_id = (u8)DMACH_PCM0_TX,
[31] = DMACH_UART5_TX, .rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_USI_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_USI_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PWM,
}, {
.peri_id = (u8)DMACH_UART5_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART5_TX,
.rqtype = MEMTODEV,
}, },
}; };
static struct platform_device s5p64x0_device_pdma = { struct dma_pl330_platdata s5p6450_pdma_pdata = {
.name = "s3c-pl330", .nr_valid_peri = ARRAY_SIZE(s5p6450_pdma_peri),
.id = -1, .peri = s5p6450_pdma_peri,
.num_resources = ARRAY_SIZE(s5p64x0_pdma_resource), };
.resource = s5p64x0_pdma_resource,
.dev = { struct amba_device s5p64x0_device_pdma = {
.dev = {
.init_name = "dma-pl330",
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
}, },
.res = {
.start = S5P64X0_PA_PDMA,
.end = S5P64X0_PA_PDMA + SZ_4K,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DMA0, NO_IRQ},
.periphid = 0x00041330,
}; };
static int __init s5p64x0_dma_init(void) static int __init s5p64x0_dma_init(void)
{ {
unsigned int id; unsigned int id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
if (id == 0x50000) if (id == 0x50000)
s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata; s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
else else
s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata; s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
platform_device_register(&s5p64x0_device_pdma); amba_device_register(&s5p64x0_device_pdma, &iomem_resource);
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H #ifndef __MACH_DMA_H
#define __MACH_DMA_H #define __MACH_DMA_H
/* This platform uses the common S3C DMA API driver for PL330 */ /* This platform uses the common common DMA API driver for PL330 */
#include <plat/s3c-dma-pl330.h> #include <plat/dma-pl330.h>
#endif /* __MACH_DMA_H */ #endif /* __MACH_DMA_H */
...@@ -10,7 +10,7 @@ if ARCH_S5PC100 ...@@ -10,7 +10,7 @@ if ARCH_S5PC100
config CPU_S5PC100 config CPU_S5PC100
bool bool
select S5P_EXT_INT select S5P_EXT_INT
select S3C_PL330_DMA select SAMSUNG_DMADEV
help help
Enable S5PC100 CPU support Enable S5PC100 CPU support
......
...@@ -33,6 +33,11 @@ static struct clk s5p_clk_otgphy = { ...@@ -33,6 +33,11 @@ static struct clk s5p_clk_otgphy = {
.name = "otg_phy", .name = "otg_phy",
}; };
static struct clk dummy_apb_pclk = {
.name = "apb_pclk",
.id = -1,
};
static struct clk *clk_src_mout_href_list[] = { static struct clk *clk_src_mout_href_list[] = {
[0] = &s5p_clk_27m, [0] = &s5p_clk_27m,
[1] = &clk_fin_hpll, [1] = &clk_fin_hpll,
...@@ -454,13 +459,13 @@ static struct clk init_clocks_off[] = { ...@@ -454,13 +459,13 @@ static struct clk init_clocks_off[] = {
.enable = s5pc100_d1_0_ctrl, .enable = s5pc100_d1_0_ctrl,
.ctrlbit = (1 << 2), .ctrlbit = (1 << 2),
}, { }, {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.1", .devname = "s3c-pl330.1",
.parent = &clk_div_d1_bus.clk, .parent = &clk_div_d1_bus.clk,
.enable = s5pc100_d1_0_ctrl, .enable = s5pc100_d1_0_ctrl,
.ctrlbit = (1 << 1), .ctrlbit = (1 << 1),
}, { }, {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.0", .devname = "s3c-pl330.0",
.parent = &clk_div_d1_bus.clk, .parent = &clk_div_d1_bus.clk,
.enable = s5pc100_d1_0_ctrl, .enable = s5pc100_d1_0_ctrl,
...@@ -1276,5 +1281,7 @@ void __init s5pc100_register_clocks(void) ...@@ -1276,5 +1281,7 @@ void __init s5pc100_register_clocks(void)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init(); s3c_pwmclk_init();
} }
/* /* linux/arch/arm/mach-s5pc100/dma.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd. * Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com> * Jaswinder Singh <jassi.brar@samsung.com>
* *
...@@ -17,150 +21,245 @@ ...@@ -17,150 +21,245 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
#include <asm/irq.h>
#include <plat/devs.h> #include <plat/devs.h>
#include <plat/irqs.h>
#include <mach/map.h> #include <mach/map.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/dma.h>
#include <plat/s3c-pl330-pdata.h>
static u64 dma_dmamask = DMA_BIT_MASK(32); static u64 dma_dmamask = DMA_BIT_MASK(32);
static struct resource s5pc100_pdma0_resource[] = { struct dma_pl330_peri pdma0_peri[30] = {
[0] = { {
.start = S5PC100_PA_PDMA0, .peri_id = (u8)DMACH_UART0_RX,
.end = S5PC100_PA_PDMA0 + SZ_4K, .rqtype = DEVTOMEM,
.flags = IORESOURCE_MEM, }, {
}, .peri_id = (u8)DMACH_UART0_TX,
[1] = { .rqtype = MEMTODEV,
.start = IRQ_PDMA0, }, {
.end = IRQ_PDMA0, .peri_id = (u8)DMACH_UART1_RX,
.flags = IORESOURCE_IRQ, .rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART3_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART3_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = DMACH_IRDA,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_AC97_MICIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMOUT,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_EXTERNAL,
}, {
.peri_id = (u8)DMACH_PWM,
}, {
.peri_id = (u8)DMACH_SPDIF,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_HSI_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_HSI_TX,
.rqtype = MEMTODEV,
}, },
}; };
static struct s3c_pl330_platdata s5pc100_pdma0_pdata = { struct dma_pl330_platdata s5pc100_pdma0_pdata = {
.peri = { .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
[0] = DMACH_UART0_RX, .peri = pdma0_peri,
[1] = DMACH_UART0_TX,
[2] = DMACH_UART1_RX,
[3] = DMACH_UART1_TX,
[4] = DMACH_UART2_RX,
[5] = DMACH_UART2_TX,
[6] = DMACH_UART3_RX,
[7] = DMACH_UART3_TX,
[8] = DMACH_IRDA,
[9] = DMACH_I2S0_RX,
[10] = DMACH_I2S0_TX,
[11] = DMACH_I2S0S_TX,
[12] = DMACH_I2S1_RX,
[13] = DMACH_I2S1_TX,
[14] = DMACH_I2S2_RX,
[15] = DMACH_I2S2_TX,
[16] = DMACH_SPI0_RX,
[17] = DMACH_SPI0_TX,
[18] = DMACH_SPI1_RX,
[19] = DMACH_SPI1_TX,
[20] = DMACH_SPI2_RX,
[21] = DMACH_SPI2_TX,
[22] = DMACH_AC97_MICIN,
[23] = DMACH_AC97_PCMIN,
[24] = DMACH_AC97_PCMOUT,
[25] = DMACH_EXTERNAL,
[26] = DMACH_PWM,
[27] = DMACH_SPDIF,
[28] = DMACH_HSI_RX,
[29] = DMACH_HSI_TX,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
}; };
static struct platform_device s5pc100_device_pdma0 = { struct amba_device s5pc100_device_pdma0 = {
.name = "s3c-pl330", .dev = {
.id = 0, .init_name = "dma-pl330.0",
.num_resources = ARRAY_SIZE(s5pc100_pdma0_resource),
.resource = s5pc100_pdma0_resource,
.dev = {
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pc100_pdma0_pdata, .platform_data = &s5pc100_pdma0_pdata,
}, },
}; .res = {
.start = S5PC100_PA_PDMA0,
static struct resource s5pc100_pdma1_resource[] = { .end = S5PC100_PA_PDMA0 + SZ_4K,
[0] = {
.start = S5PC100_PA_PDMA1,
.end = S5PC100_PA_PDMA1 + SZ_4K,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { .irq = {IRQ_PDMA0, NO_IRQ},
.start = IRQ_PDMA1, .periphid = 0x00041330,
.end = IRQ_PDMA1,
.flags = IORESOURCE_IRQ,
},
}; };
static struct s3c_pl330_platdata s5pc100_pdma1_pdata = { struct dma_pl330_peri pdma1_peri[30] = {
.peri = { {
[0] = DMACH_UART0_RX, .peri_id = (u8)DMACH_UART0_RX,
[1] = DMACH_UART0_TX, .rqtype = DEVTOMEM,
[2] = DMACH_UART1_RX, }, {
[3] = DMACH_UART1_TX, .peri_id = (u8)DMACH_UART0_TX,
[4] = DMACH_UART2_RX, .rqtype = MEMTODEV,
[5] = DMACH_UART2_TX, }, {
[6] = DMACH_UART3_RX, .peri_id = (u8)DMACH_UART1_RX,
[7] = DMACH_UART3_TX, .rqtype = DEVTOMEM,
[8] = DMACH_IRDA, }, {
[9] = DMACH_I2S0_RX, .peri_id = (u8)DMACH_UART1_TX,
[10] = DMACH_I2S0_TX, .rqtype = MEMTODEV,
[11] = DMACH_I2S0S_TX, }, {
[12] = DMACH_I2S1_RX, .peri_id = (u8)DMACH_UART2_RX,
[13] = DMACH_I2S1_TX, .rqtype = DEVTOMEM,
[14] = DMACH_I2S2_RX, }, {
[15] = DMACH_I2S2_TX, .peri_id = (u8)DMACH_UART2_TX,
[16] = DMACH_SPI0_RX, .rqtype = MEMTODEV,
[17] = DMACH_SPI0_TX, }, {
[18] = DMACH_SPI1_RX, .peri_id = (u8)DMACH_UART3_RX,
[19] = DMACH_SPI1_TX, .rqtype = DEVTOMEM,
[20] = DMACH_SPI2_RX, }, {
[21] = DMACH_SPI2_TX, .peri_id = (u8)DMACH_UART3_TX,
[22] = DMACH_PCM0_RX, .rqtype = MEMTODEV,
[23] = DMACH_PCM0_TX, }, {
[24] = DMACH_PCM1_RX, .peri_id = DMACH_IRDA,
[25] = DMACH_PCM1_TX, }, {
[26] = DMACH_MSM_REQ0, .peri_id = (u8)DMACH_I2S0_RX,
[27] = DMACH_MSM_REQ1, .rqtype = DEVTOMEM,
[28] = DMACH_MSM_REQ2, }, {
[29] = DMACH_MSM_REQ3, .peri_id = (u8)DMACH_I2S0_TX,
[30] = DMACH_MAX, .rqtype = MEMTODEV,
[31] = DMACH_MAX, }, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MSM_REQ0,
}, {
.peri_id = (u8)DMACH_MSM_REQ1,
}, {
.peri_id = (u8)DMACH_MSM_REQ2,
}, {
.peri_id = (u8)DMACH_MSM_REQ3,
}, },
}; };
static struct platform_device s5pc100_device_pdma1 = { struct dma_pl330_platdata s5pc100_pdma1_pdata = {
.name = "s3c-pl330", .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
.id = 1, .peri = pdma1_peri,
.num_resources = ARRAY_SIZE(s5pc100_pdma1_resource), };
.resource = s5pc100_pdma1_resource,
.dev = { struct amba_device s5pc100_device_pdma1 = {
.dev = {
.init_name = "dma-pl330.1",
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pc100_pdma1_pdata, .platform_data = &s5pc100_pdma1_pdata,
}, },
}; .res = {
.start = S5PC100_PA_PDMA1,
static struct platform_device *s5pc100_dmacs[] __initdata = { .end = S5PC100_PA_PDMA1 + SZ_4K,
&s5pc100_device_pdma0, .flags = IORESOURCE_MEM,
&s5pc100_device_pdma1, },
.irq = {IRQ_PDMA1, NO_IRQ},
.periphid = 0x00041330,
}; };
static int __init s5pc100_dma_init(void) static int __init s5pc100_dma_init(void)
{ {
platform_add_devices(s5pc100_dmacs, ARRAY_SIZE(s5pc100_dmacs)); amba_device_register(&s5pc100_device_pdma0, &iomem_resource);
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H #ifndef __MACH_DMA_H
#define __MACH_DMA_H #define __MACH_DMA_H
/* This platform uses the common S3C DMA API driver for PL330 */ /* This platform uses the common DMA API driver for PL330 */
#include <plat/s3c-dma-pl330.h> #include <plat/dma-pl330.h>
#endif /* __MACH_DMA_H */ #endif /* __MACH_DMA_H */
...@@ -11,7 +11,7 @@ if ARCH_S5PV210 ...@@ -11,7 +11,7 @@ if ARCH_S5PV210
config CPU_S5PV210 config CPU_S5PV210
bool bool
select S3C_PL330_DMA select SAMSUNG_DMADEV
select S5P_EXT_INT select S5P_EXT_INT
select S5P_HRT select S5P_HRT
select S5PV210_PM if PM select S5PV210_PM if PM
......
...@@ -203,6 +203,11 @@ static struct clk clk_pcmcdclk2 = { ...@@ -203,6 +203,11 @@ static struct clk clk_pcmcdclk2 = {
.name = "pcmcdclk", .name = "pcmcdclk",
}; };
static struct clk dummy_apb_pclk = {
.name = "apb_pclk",
.id = -1,
};
static struct clk *clkset_vpllsrc_list[] = { static struct clk *clkset_vpllsrc_list[] = {
[0] = &clk_fin_vpll, [0] = &clk_fin_vpll,
[1] = &clk_sclk_hdmi27m, [1] = &clk_sclk_hdmi27m,
...@@ -289,13 +294,13 @@ static struct clk_ops clk_fout_apll_ops = { ...@@ -289,13 +294,13 @@ static struct clk_ops clk_fout_apll_ops = {
static struct clk init_clocks_off[] = { static struct clk init_clocks_off[] = {
{ {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.0", .devname = "s3c-pl330.0",
.parent = &clk_hclk_psys.clk, .parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip0_ctrl, .enable = s5pv210_clk_ip0_ctrl,
.ctrlbit = (1 << 3), .ctrlbit = (1 << 3),
}, { }, {
.name = "pdma", .name = "dma",
.devname = "s3c-pl330.1", .devname = "s3c-pl330.1",
.parent = &clk_hclk_psys.clk, .parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip0_ctrl, .enable = s5pv210_clk_ip0_ctrl,
...@@ -1161,5 +1166,6 @@ void __init s5pv210_register_clocks(void) ...@@ -1161,5 +1166,6 @@ void __init s5pv210_register_clocks(void)
s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clock(&dummy_apb_pclk);
s3c_pwmclk_init(); s3c_pwmclk_init();
} }
/* /* linux/arch/arm/mach-s5pv210/dma.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd. * Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com> * Jaswinder Singh <jassi.brar@samsung.com>
* *
...@@ -17,151 +21,239 @@ ...@@ -17,151 +21,239 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
#include <asm/irq.h>
#include <plat/devs.h> #include <plat/devs.h>
#include <plat/irqs.h> #include <plat/irqs.h>
#include <mach/map.h> #include <mach/map.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/dma.h>
#include <plat/s3c-pl330-pdata.h>
static u64 dma_dmamask = DMA_BIT_MASK(32); static u64 dma_dmamask = DMA_BIT_MASK(32);
static struct resource s5pv210_pdma0_resource[] = { struct dma_pl330_peri pdma0_peri[28] = {
[0] = { {
.start = S5PV210_PA_PDMA0, .peri_id = (u8)DMACH_UART0_RX,
.end = S5PV210_PA_PDMA0 + SZ_4K, .rqtype = DEVTOMEM,
.flags = IORESOURCE_MEM, }, {
}, .peri_id = (u8)DMACH_UART0_TX,
[1] = { .rqtype = MEMTODEV,
.start = IRQ_PDMA0, }, {
.end = IRQ_PDMA0, .peri_id = (u8)DMACH_UART1_RX,
.flags = IORESOURCE_IRQ, .rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_UART3_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_UART3_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = DMACH_MAX,
}, {
.peri_id = (u8)DMACH_I2S0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_AC97_MICIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMIN,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_AC97_PCMOUT,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_PWM,
}, {
.peri_id = (u8)DMACH_SPDIF,
.rqtype = MEMTODEV,
}, },
}; };
static struct s3c_pl330_platdata s5pv210_pdma0_pdata = { struct dma_pl330_platdata s5pv210_pdma0_pdata = {
.peri = { .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
[0] = DMACH_UART0_RX, .peri = pdma0_peri,
[1] = DMACH_UART0_TX,
[2] = DMACH_UART1_RX,
[3] = DMACH_UART1_TX,
[4] = DMACH_UART2_RX,
[5] = DMACH_UART2_TX,
[6] = DMACH_UART3_RX,
[7] = DMACH_UART3_TX,
[8] = DMACH_MAX,
[9] = DMACH_I2S0_RX,
[10] = DMACH_I2S0_TX,
[11] = DMACH_I2S0S_TX,
[12] = DMACH_I2S1_RX,
[13] = DMACH_I2S1_TX,
[14] = DMACH_MAX,
[15] = DMACH_MAX,
[16] = DMACH_SPI0_RX,
[17] = DMACH_SPI0_TX,
[18] = DMACH_SPI1_RX,
[19] = DMACH_SPI1_TX,
[20] = DMACH_MAX,
[21] = DMACH_MAX,
[22] = DMACH_AC97_MICIN,
[23] = DMACH_AC97_PCMIN,
[24] = DMACH_AC97_PCMOUT,
[25] = DMACH_MAX,
[26] = DMACH_PWM,
[27] = DMACH_SPDIF,
[28] = DMACH_MAX,
[29] = DMACH_MAX,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
}; };
static struct platform_device s5pv210_device_pdma0 = { struct amba_device s5pv210_device_pdma0 = {
.name = "s3c-pl330", .dev = {
.id = 0, .init_name = "dma-pl330.0",
.num_resources = ARRAY_SIZE(s5pv210_pdma0_resource),
.resource = s5pv210_pdma0_resource,
.dev = {
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pv210_pdma0_pdata, .platform_data = &s5pv210_pdma0_pdata,
}, },
}; .res = {
.start = S5PV210_PA_PDMA0,
static struct resource s5pv210_pdma1_resource[] = { .end = S5PV210_PA_PDMA0 + SZ_4K,
[0] = {
.start = S5PV210_PA_PDMA1,
.end = S5PV210_PA_PDMA1 + SZ_4K,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { .irq = {IRQ_PDMA0, NO_IRQ},
.start = IRQ_PDMA1, .periphid = 0x00041330,
.end = IRQ_PDMA1,
.flags = IORESOURCE_IRQ,
},
}; };
static struct s3c_pl330_platdata s5pv210_pdma1_pdata = { struct dma_pl330_peri pdma1_peri[32] = {
.peri = { {
[0] = DMACH_UART0_RX, .peri_id = (u8)DMACH_UART0_RX,
[1] = DMACH_UART0_TX, .rqtype = DEVTOMEM,
[2] = DMACH_UART1_RX, }, {
[3] = DMACH_UART1_TX, .peri_id = (u8)DMACH_UART0_TX,
[4] = DMACH_UART2_RX, .rqtype = MEMTODEV,
[5] = DMACH_UART2_TX, }, {
[6] = DMACH_UART3_RX, .peri_id = (u8)DMACH_UART1_RX,
[7] = DMACH_UART3_TX, .rqtype = DEVTOMEM,
[8] = DMACH_MAX, }, {
[9] = DMACH_I2S0_RX, .peri_id = (u8)DMACH_UART1_TX,
[10] = DMACH_I2S0_TX, .rqtype = MEMTODEV,
[11] = DMACH_I2S0S_TX, }, {
[12] = DMACH_I2S1_RX, .peri_id = (u8)DMACH_UART2_RX,
[13] = DMACH_I2S1_TX, .rqtype = DEVTOMEM,
[14] = DMACH_I2S2_RX, }, {
[15] = DMACH_I2S2_TX, .peri_id = (u8)DMACH_UART2_TX,
[16] = DMACH_SPI0_RX, .rqtype = MEMTODEV,
[17] = DMACH_SPI0_TX, }, {
[18] = DMACH_SPI1_RX, .peri_id = (u8)DMACH_UART3_RX,
[19] = DMACH_SPI1_TX, .rqtype = DEVTOMEM,
[20] = DMACH_MAX, }, {
[21] = DMACH_MAX, .peri_id = (u8)DMACH_UART3_TX,
[22] = DMACH_PCM0_RX, .rqtype = MEMTODEV,
[23] = DMACH_PCM0_TX, }, {
[24] = DMACH_PCM1_RX, .peri_id = DMACH_MAX,
[25] = DMACH_PCM1_TX, }, {
[26] = DMACH_MSM_REQ0, .peri_id = (u8)DMACH_I2S0_RX,
[27] = DMACH_MSM_REQ1, .rqtype = DEVTOMEM,
[28] = DMACH_MSM_REQ2, }, {
[29] = DMACH_MSM_REQ3, .peri_id = (u8)DMACH_I2S0_TX,
[30] = DMACH_PCM2_RX, .rqtype = MEMTODEV,
[31] = DMACH_PCM2_TX, }, {
.peri_id = (u8)DMACH_I2S0S_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_I2S2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_I2S2_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_SPI1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_SPI1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_MAX,
}, {
.peri_id = (u8)DMACH_PCM0_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM0_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_PCM1_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM1_TX,
.rqtype = MEMTODEV,
}, {
.peri_id = (u8)DMACH_MSM_REQ0,
}, {
.peri_id = (u8)DMACH_MSM_REQ1,
}, {
.peri_id = (u8)DMACH_MSM_REQ2,
}, {
.peri_id = (u8)DMACH_MSM_REQ3,
}, {
.peri_id = (u8)DMACH_PCM2_RX,
.rqtype = DEVTOMEM,
}, {
.peri_id = (u8)DMACH_PCM2_TX,
.rqtype = MEMTODEV,
}, },
}; };
static struct platform_device s5pv210_device_pdma1 = { struct dma_pl330_platdata s5pv210_pdma1_pdata = {
.name = "s3c-pl330", .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
.id = 1, .peri = pdma1_peri,
.num_resources = ARRAY_SIZE(s5pv210_pdma1_resource), };
.resource = s5pv210_pdma1_resource,
.dev = { struct amba_device s5pv210_device_pdma1 = {
.dev = {
.init_name = "dma-pl330.1",
.dma_mask = &dma_dmamask, .dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32), .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pv210_pdma1_pdata, .platform_data = &s5pv210_pdma1_pdata,
}, },
}; .res = {
.start = S5PV210_PA_PDMA1,
static struct platform_device *s5pv210_dmacs[] __initdata = { .end = S5PV210_PA_PDMA1 + SZ_4K,
&s5pv210_device_pdma0, .flags = IORESOURCE_MEM,
&s5pv210_device_pdma1, },
.irq = {IRQ_PDMA1, NO_IRQ},
.periphid = 0x00041330,
}; };
static int __init s5pv210_dma_init(void) static int __init s5pv210_dma_init(void)
{ {
platform_add_devices(s5pv210_dmacs, ARRAY_SIZE(s5pv210_dmacs)); amba_device_register(&s5pv210_device_pdma0, &iomem_resource);
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H #ifndef __MACH_DMA_H
#define __MACH_DMA_H #define __MACH_DMA_H
/* This platform uses the common S3C DMA API driver for PL330 */ /* This platform uses the common DMA API driver for PL330 */
#include <plat/s3c-dma-pl330.h> #include <plat/dma-pl330.h>
#endif /* __MACH_DMA_H */ #endif /* __MACH_DMA_H */
...@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config); ...@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config);
* *
* configure the dma source/destination hardware type and address * configure the dma source/destination hardware type and address
* *
* source: S3C2410_DMASRC_HW: source is hardware * source: DMA_FROM_DEVICE: source is hardware
* S3C2410_DMASRC_MEM: source is memory * DMA_TO_DEVICE: source is memory
* *
* devaddr: physical address of the source * devaddr: physical address of the source
*/ */
int s3c2410_dma_devconfig(enum dma_ch channel, int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source, enum dma_data_direction source,
unsigned long devaddr) unsigned long devaddr)
{ {
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
...@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel, ...@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
hwcfg |= S3C2410_DISRCC_INC; hwcfg |= S3C2410_DISRCC_INC;
switch (source) { switch (source) {
case S3C2410_DMASRC_HW: case DMA_FROM_DEVICE:
/* source is hardware */ /* source is hardware */
pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
__func__, devaddr, hwcfg); __func__, devaddr, hwcfg);
...@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel, ...@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
break; break;
case S3C2410_DMASRC_MEM: case DMA_TO_DEVICE:
/* source is memory */ /* source is memory */
pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n", pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
__func__, devaddr, hwcfg); __func__, devaddr, hwcfg);
......
...@@ -300,11 +300,14 @@ config S3C_DMA ...@@ -300,11 +300,14 @@ config S3C_DMA
help help
Internal configuration for S3C DMA core Internal configuration for S3C DMA core
config S3C_PL330_DMA config SAMSUNG_DMADEV
bool bool
select PL330 select DMADEVICES
select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \
CPU_S5P6450 || CPU_S5P6440)
select ARM_AMBA
help help
S3C DMA API Driver for PL330 DMAC. Use DMA device engine for PL330 DMAC.
comment "Power management" comment "Power management"
......
...@@ -63,9 +63,9 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o ...@@ -63,9 +63,9 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
# DMA support # DMA support
obj-$(CONFIG_S3C_DMA) += dma.o obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o
obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o
# PM support # PM support
......
/* linux/arch/arm/plat-samsung/dma-ops.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Samsung DMA Operations
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/amba/pl330.h>
#include <linux/scatterlist.h>
#include <mach/dma.h>
static inline bool pl330_filter(struct dma_chan *chan, void *param)
{
struct dma_pl330_peri *peri = chan->private;
return peri->peri_id == (unsigned)param;
}
static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
struct samsung_dma_info *info)
{
struct dma_chan *chan;
dma_cap_mask_t mask;
struct dma_slave_config slave_config;
dma_cap_zero(mask);
dma_cap_set(info->cap, mask);
chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
if (info->direction == DMA_FROM_DEVICE) {
memset(&slave_config, 0, sizeof(struct dma_slave_config));
slave_config.direction = info->direction;
slave_config.src_addr = info->fifo;
slave_config.src_addr_width = info->width;
slave_config.src_maxburst = 1;
dmaengine_slave_config(chan, &slave_config);
} else if (info->direction == DMA_TO_DEVICE) {
memset(&slave_config, 0, sizeof(struct dma_slave_config));
slave_config.direction = info->direction;
slave_config.dst_addr = info->fifo;
slave_config.dst_addr_width = info->width;
slave_config.dst_maxburst = 1;
dmaengine_slave_config(chan, &slave_config);
}
return (unsigned)chan;
}
static int samsung_dmadev_release(unsigned ch,
struct s3c2410_dma_client *client)
{
dma_release_channel((struct dma_chan *)ch);
return 0;
}
static int samsung_dmadev_prepare(unsigned ch,
struct samsung_dma_prep_info *info)
{
struct scatterlist sg;
struct dma_chan *chan = (struct dma_chan *)ch;
struct dma_async_tx_descriptor *desc;
switch (info->cap) {
case DMA_SLAVE:
sg_init_table(&sg, 1);
sg_dma_len(&sg) = info->len;
sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
info->len, offset_in_page(info->buf));
sg_dma_address(&sg) = info->buf;
desc = chan->device->device_prep_slave_sg(chan,
&sg, 1, info->direction, DMA_PREP_INTERRUPT);
break;
case DMA_CYCLIC:
desc = chan->device->device_prep_dma_cyclic(chan,
info->buf, info->len, info->period, info->direction);
break;
default:
dev_err(&chan->dev->device, "unsupported format\n");
return -EFAULT;
}
if (!desc) {
dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
return -EFAULT;
}
desc->callback = info->fp;
desc->callback_param = info->fp_param;
dmaengine_submit((struct dma_async_tx_descriptor *)desc);
return 0;
}
static inline int samsung_dmadev_trigger(unsigned ch)
{
dma_async_issue_pending((struct dma_chan *)ch);
return 0;
}
static inline int samsung_dmadev_flush(unsigned ch)
{
return dmaengine_terminate_all((struct dma_chan *)ch);
}
struct samsung_dma_ops dmadev_ops = {
.request = samsung_dmadev_request,
.release = samsung_dmadev_release,
.prepare = samsung_dmadev_prepare,
.trigger = samsung_dmadev_trigger,
.started = NULL,
.flush = samsung_dmadev_flush,
.stop = samsung_dmadev_flush,
};
void *samsung_dmadev_get_ops(void)
{
return &dmadev_ops;
}
EXPORT_SYMBOL(samsung_dmadev_get_ops);
/* arch/arm/plat-samsung/include/plat/dma-ops.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Samsung DMA support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __SAMSUNG_DMA_OPS_H_
#define __SAMSUNG_DMA_OPS_H_ __FILE__
#include <linux/dmaengine.h>
struct samsung_dma_prep_info {
enum dma_transaction_type cap;
enum dma_data_direction direction;
dma_addr_t buf;
unsigned long period;
unsigned long len;
void (*fp)(void *data);
void *fp_param;
};
struct samsung_dma_info {
enum dma_transaction_type cap;
enum dma_data_direction direction;
enum dma_slave_buswidth width;
dma_addr_t fifo;
struct s3c2410_dma_client *client;
};
struct samsung_dma_ops {
unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
int (*release)(unsigned ch, struct s3c2410_dma_client *client);
int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
int (*trigger)(unsigned ch);
int (*started)(unsigned ch);
int (*flush)(unsigned ch);
int (*stop)(unsigned ch);
};
extern void *samsung_dmadev_get_ops(void);
extern void *s3c_dma_get_ops(void);
static inline void *__samsung_dma_get_ops(void)
{
if (samsung_dma_is_dmadev())
return samsung_dmadev_get_ops();
else
return s3c_dma_get_ops();
}
/*
* samsung_dma_get_ops
* get the set of samsung dma operations
*/
#define samsung_dma_get_ops() __samsung_dma_get_ops()
#endif /* __SAMSUNG_DMA_OPS_H_ */
...@@ -8,11 +8,8 @@ ...@@ -8,11 +8,8 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#ifndef __S3C_DMA_PL330_H_ #ifndef __DMA_PL330_H_
#define __S3C_DMA_PL330_H_ #define __DMA_PL330_H_ __FILE__
#define S3C2410_DMAF_AUTOSTART (1 << 0)
#define S3C2410_DMAF_CIRCULAR (1 << 1)
/* /*
* PL330 can assign any channel to communicate with * PL330 can assign any channel to communicate with
...@@ -20,7 +17,7 @@ ...@@ -20,7 +17,7 @@
* For the sake of consistency across client drivers, * For the sake of consistency across client drivers,
* We keep the channel names unchanged and only add * We keep the channel names unchanged and only add
* missing peripherals are added. * missing peripherals are added.
* Order is not important since S3C PL330 API driver * Order is not important since DMA PL330 API driver
* use these just as IDs. * use these just as IDs.
*/ */
enum dma_ch { enum dma_ch {
...@@ -88,11 +85,20 @@ enum dma_ch { ...@@ -88,11 +85,20 @@ enum dma_ch {
DMACH_MAX, DMACH_MAX,
}; };
static inline bool s3c_dma_has_circular(void) struct s3c2410_dma_client {
char *name;
};
static inline bool samsung_dma_has_circular(void)
{
return true;
}
static inline bool samsung_dma_is_dmadev(void)
{ {
return true; return true;
} }
#include <plat/dma.h> #include <plat/dma-ops.h>
#endif /* __S3C_DMA_PL330_H_ */ #endif /* __DMA_PL330_H_ */
...@@ -47,7 +47,7 @@ struct s3c24xx_dma_selection { ...@@ -47,7 +47,7 @@ struct s3c24xx_dma_selection {
void (*direction)(struct s3c2410_dma_chan *chan, void (*direction)(struct s3c2410_dma_chan *chan,
struct s3c24xx_dma_map *map, struct s3c24xx_dma_map *map,
enum s3c2410_dmasrc dir); enum dma_data_direction dir);
}; };
extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
......
...@@ -10,17 +10,14 @@ ...@@ -10,17 +10,14 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/dma-mapping.h>
enum s3c2410_dma_buffresult { enum s3c2410_dma_buffresult {
S3C2410_RES_OK, S3C2410_RES_OK,
S3C2410_RES_ERR, S3C2410_RES_ERR,
S3C2410_RES_ABORT S3C2410_RES_ABORT
}; };
enum s3c2410_dmasrc {
S3C2410_DMASRC_HW, /* source is memory */
S3C2410_DMASRC_MEM /* source is hardware */
};
/* enum s3c2410_chan_op /* enum s3c2410_chan_op
* *
* operation codes passed to the DMA code by the user, and also used * 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,7 +109,7 @@ extern int s3c2410_dma_config(enum dma_ch channel, int xferunit);
*/ */
extern int s3c2410_dma_devconfig(enum dma_ch channel, extern int s3c2410_dma_devconfig(enum dma_ch channel,
enum s3c2410_dmasrc source, unsigned long devaddr); enum dma_data_direction source, unsigned long devaddr);
/* s3c2410_dma_getposition /* s3c2410_dma_getposition
* *
...@@ -126,3 +123,4 @@ extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); ...@@ -126,3 +123,4 @@ extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn);
extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn);
#include <plat/dma-ops.h>
/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __S3C_PL330_PDATA_H
#define __S3C_PL330_PDATA_H
#include <plat/s3c-dma-pl330.h>
/*
* Every PL330 DMAC has max 32 peripheral interfaces,
* of which some may be not be really used in your
* DMAC's configuration.
* Populate this array of 32 peri i/fs with relevant
* channel IDs for used peri i/f and DMACH_MAX for
* those unused.
*
* The platforms just need to provide this info
* to the S3C DMA API driver for PL330.
*/
struct s3c_pl330_platdata {
enum dma_ch peri[32];
};
#endif /* __S3C_PL330_PDATA_H */
/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Samsung S3C-DMA Operations
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <mach/dma.h>
struct cb_data {
void (*fp) (void *);
void *fp_param;
unsigned ch;
struct list_head node;
};
static LIST_HEAD(dma_list);
static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
int size, enum s3c2410_dma_buffresult res)
{
struct cb_data *data = param;
data->fp(data->fp_param);
}
static unsigned s3c_dma_request(enum dma_ch dma_ch,
struct samsung_dma_info *info)
{
struct cb_data *data;
if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
s3c2410_dma_free(dma_ch, info->client);
return 0;
}
data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
data->ch = dma_ch;
list_add_tail(&data->node, &dma_list);
s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
if (info->cap == DMA_CYCLIC)
s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
s3c2410_dma_config(dma_ch, info->width);
return (unsigned)dma_ch;
}
static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
{
struct cb_data *data;
list_for_each_entry(data, &dma_list, node)
if (data->ch == ch)
break;
list_del(&data->node);
s3c2410_dma_free(ch, client);
kfree(data);
return 0;
}
static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
{
struct cb_data *data;
int len = (info->cap == DMA_CYCLIC) ? info->period : info->len;
list_for_each_entry(data, &dma_list, node)
if (data->ch == ch)
break;
if (!data->fp) {
s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
data->fp = info->fp;
data->fp_param = info->fp_param;
}
s3c2410_dma_enqueue(ch, (void *)data, info->buf, len);
return 0;
}
static inline int s3c_dma_trigger(unsigned ch)
{
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
}
static inline int s3c_dma_started(unsigned ch)
{
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
}
static inline int s3c_dma_flush(unsigned ch)
{
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
}
static inline int s3c_dma_stop(unsigned ch)
{
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
}
static struct samsung_dma_ops s3c_dma_ops = {
.request = s3c_dma_request,
.release = s3c_dma_release,
.prepare = s3c_dma_prepare,
.trigger = s3c_dma_trigger,
.started = s3c_dma_started,
.flush = s3c_dma_flush,
.stop = s3c_dma_stop,
};
void *s3c_dma_get_ops(void)
{
return &s3c_dma_ops;
}
EXPORT_SYMBOL(s3c_dma_get_ops);
This diff is collapsed.
...@@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL ...@@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
config PL330_DMA config PL330_DMA
tristate "DMA API Driver for PL330" tristate "DMA API Driver for PL330"
select DMA_ENGINE select DMA_ENGINE
depends on PL330 depends on ARM_AMBA
select PL330
help help
Select if your platform has one or more PL330 DMACs. Select if your platform has one or more PL330 DMACs.
You need to provide platform specific settings via You need to provide platform specific settings via
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/pl330.h> #include <linux/amba/pl330.h>
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#define NR_DEFAULT_DESC 16 #define NR_DEFAULT_DESC 16
...@@ -68,6 +70,14 @@ struct dma_pl330_chan { ...@@ -68,6 +70,14 @@ struct dma_pl330_chan {
* NULL if the channel is available to be acquired. * NULL if the channel is available to be acquired.
*/ */
void *pl330_chid; void *pl330_chid;
/* For D-to-M and M-to-D channels */
int burst_sz; /* the peripheral fifo width */
int burst_len; /* the number of burst */
dma_addr_t fifo_addr;
/* for cyclic capability */
bool cyclic;
}; };
struct dma_pl330_dmac { struct dma_pl330_dmac {
...@@ -83,6 +93,8 @@ struct dma_pl330_dmac { ...@@ -83,6 +93,8 @@ struct dma_pl330_dmac {
/* Peripheral channels connected to this DMAC */ /* Peripheral channels connected to this DMAC */
struct dma_pl330_chan *peripherals; /* keep at end */ struct dma_pl330_chan *peripherals; /* keep at end */
struct clk *clk;
}; };
struct dma_pl330_desc { struct dma_pl330_desc {
...@@ -152,6 +164,31 @@ static inline void free_desc_list(struct list_head *list) ...@@ -152,6 +164,31 @@ static inline void free_desc_list(struct list_head *list)
spin_unlock_irqrestore(&pdmac->pool_lock, flags); spin_unlock_irqrestore(&pdmac->pool_lock, flags);
} }
static inline void handle_cyclic_desc_list(struct list_head *list)
{
struct dma_pl330_desc *desc;
struct dma_pl330_chan *pch;
unsigned long flags;
if (list_empty(list))
return;
list_for_each_entry(desc, list, node) {
dma_async_tx_callback callback;
/* Change status to reload it */
desc->status = PREP;
pch = desc->pchan;
callback = desc->txd.callback;
if (callback)
callback(desc->txd.callback_param);
}
spin_lock_irqsave(&pch->lock, flags);
list_splice_tail_init(list, &pch->work_list);
spin_unlock_irqrestore(&pch->lock, flags);
}
static inline void fill_queue(struct dma_pl330_chan *pch) static inline void fill_queue(struct dma_pl330_chan *pch)
{ {
struct dma_pl330_desc *desc; struct dma_pl330_desc *desc;
...@@ -205,7 +242,10 @@ static void pl330_tasklet(unsigned long data) ...@@ -205,7 +242,10 @@ static void pl330_tasklet(unsigned long data)
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pch->lock, flags);
free_desc_list(&list); if (pch->cyclic)
handle_cyclic_desc_list(&list);
else
free_desc_list(&list);
} }
static void dma_pl330_rqcb(void *token, enum pl330_op_err err) static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
...@@ -236,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) ...@@ -236,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&pch->lock, flags); spin_lock_irqsave(&pch->lock, flags);
pch->completed = chan->cookie = 1; pch->completed = chan->cookie = 1;
pch->cyclic = false;
pch->pl330_chid = pl330_request_channel(&pdmac->pif); pch->pl330_chid = pl330_request_channel(&pdmac->pif);
if (!pch->pl330_chid) { if (!pch->pl330_chid) {
...@@ -253,25 +294,52 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) ...@@ -253,25 +294,52 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
{ {
struct dma_pl330_chan *pch = to_pchan(chan); struct dma_pl330_chan *pch = to_pchan(chan);
struct dma_pl330_desc *desc; struct dma_pl330_desc *desc, *_dt;
unsigned long flags; unsigned long flags;
struct dma_pl330_dmac *pdmac = pch->dmac;
struct dma_slave_config *slave_config;
LIST_HEAD(list);
/* Only supports DMA_TERMINATE_ALL */ switch (cmd) {
if (cmd != DMA_TERMINATE_ALL) case DMA_TERMINATE_ALL:
return -ENXIO; spin_lock_irqsave(&pch->lock, flags);
spin_lock_irqsave(&pch->lock, flags);
/* FLUSH the PL330 Channel thread */
pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
/* Mark all desc done */ /* FLUSH the PL330 Channel thread */
list_for_each_entry(desc, &pch->work_list, node) pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
desc->status = DONE;
spin_unlock_irqrestore(&pch->lock, flags); /* Mark all desc done */
list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
desc->status = DONE;
pch->completed = desc->txd.cookie;
list_move_tail(&desc->node, &list);
}
pl330_tasklet((unsigned long) pch); list_splice_tail_init(&list, &pdmac->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags);
break;
case DMA_SLAVE_CONFIG:
slave_config = (struct dma_slave_config *)arg;
if (slave_config->direction == DMA_TO_DEVICE) {
if (slave_config->dst_addr)
pch->fifo_addr = slave_config->dst_addr;
if (slave_config->dst_addr_width)
pch->burst_sz = __ffs(slave_config->dst_addr_width);
if (slave_config->dst_maxburst)
pch->burst_len = slave_config->dst_maxburst;
} else if (slave_config->direction == DMA_FROM_DEVICE) {
if (slave_config->src_addr)
pch->fifo_addr = slave_config->src_addr;
if (slave_config->src_addr_width)
pch->burst_sz = __ffs(slave_config->src_addr_width);
if (slave_config->src_maxburst)
pch->burst_len = slave_config->src_maxburst;
}
break;
default:
dev_err(pch->dmac->pif.dev, "Not supported command.\n");
return -ENXIO;
}
return 0; return 0;
} }
...@@ -288,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan) ...@@ -288,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
pl330_release_channel(pch->pl330_chid); pl330_release_channel(pch->pl330_chid);
pch->pl330_chid = NULL; pch->pl330_chid = NULL;
if (pch->cyclic)
list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pch->lock, flags);
} }
...@@ -453,7 +524,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) ...@@ -453,7 +524,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
if (peri) { if (peri) {
desc->req.rqtype = peri->rqtype; desc->req.rqtype = peri->rqtype;
desc->req.peri = peri->peri_id; desc->req.peri = pch->chan.chan_id;
} else { } else {
desc->req.rqtype = MEMTOMEM; desc->req.rqtype = MEMTOMEM;
desc->req.peri = 0; desc->req.peri = 0;
...@@ -524,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) ...@@ -524,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
return burst_len; return burst_len;
} }
static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
size_t period_len, enum dma_data_direction direction)
{
struct dma_pl330_desc *desc;
struct dma_pl330_chan *pch = to_pchan(chan);
dma_addr_t dst;
dma_addr_t src;
desc = pl330_get_desc(pch);
if (!desc) {
dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
__func__, __LINE__);
return NULL;
}
switch (direction) {
case DMA_TO_DEVICE:
desc->rqcfg.src_inc = 1;
desc->rqcfg.dst_inc = 0;
src = dma_addr;
dst = pch->fifo_addr;
break;
case DMA_FROM_DEVICE:
desc->rqcfg.src_inc = 0;
desc->rqcfg.dst_inc = 1;
src = pch->fifo_addr;
dst = dma_addr;
break;
default:
dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
__func__, __LINE__);
return NULL;
}
desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1;
pch->cyclic = true;
fill_px(&desc->px, dst, src, period_len);
return &desc->txd;
}
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
dma_addr_t src, size_t len, unsigned long flags) dma_addr_t src, size_t len, unsigned long flags)
...@@ -579,7 +695,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -579,7 +695,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct dma_pl330_peri *peri = chan->private; struct dma_pl330_peri *peri = chan->private;
struct scatterlist *sg; struct scatterlist *sg;
unsigned long flags; unsigned long flags;
int i, burst_size; int i;
dma_addr_t addr; dma_addr_t addr;
if (unlikely(!pch || !sgl || !sg_len || !peri)) if (unlikely(!pch || !sgl || !sg_len || !peri))
...@@ -595,8 +711,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -595,8 +711,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return NULL; return NULL;
} }
addr = peri->fifo_addr; addr = pch->fifo_addr;
burst_size = peri->burst_sz;
first = NULL; first = NULL;
...@@ -644,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -644,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
sg_dma_address(sg), addr, sg_dma_len(sg)); sg_dma_address(sg), addr, sg_dma_len(sg));
} }
desc->rqcfg.brst_size = burst_size; desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1; desc->rqcfg.brst_len = 1;
} }
...@@ -696,6 +811,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -696,6 +811,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
goto probe_err1; goto probe_err1;
} }
pdmac->clk = clk_get(&adev->dev, "dma");
if (IS_ERR(pdmac->clk)) {
dev_err(&adev->dev, "Cannot get operation clock.\n");
ret = -EINVAL;
goto probe_err1;
}
amba_set_drvdata(adev, pdmac);
#ifdef CONFIG_PM_RUNTIME
/* to use the runtime PM helper functions */
pm_runtime_enable(&adev->dev);
/* enable the power domain */
if (pm_runtime_get_sync(&adev->dev)) {
dev_err(&adev->dev, "failed to get runtime pm\n");
ret = -ENODEV;
goto probe_err1;
}
#else
/* enable dma clk */
clk_enable(pdmac->clk);
#endif
irq = adev->irq[0]; irq = adev->irq[0];
ret = request_irq(irq, pl330_irq_handler, 0, ret = request_irq(irq, pl330_irq_handler, 0,
dev_name(&adev->dev), pi); dev_name(&adev->dev), pi);
...@@ -732,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -732,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
case MEMTODEV: case MEMTODEV:
case DEVTOMEM: case DEVTOMEM:
dma_cap_set(DMA_SLAVE, pd->cap_mask); dma_cap_set(DMA_SLAVE, pd->cap_mask);
dma_cap_set(DMA_CYCLIC, pd->cap_mask);
break; break;
default: default:
dev_err(&adev->dev, "DEVTODEV Not Supported\n"); dev_err(&adev->dev, "DEVTODEV Not Supported\n");
...@@ -758,6 +898,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -758,6 +898,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pd->device_alloc_chan_resources = pl330_alloc_chan_resources; pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
pd->device_free_chan_resources = pl330_free_chan_resources; pd->device_free_chan_resources = pl330_free_chan_resources;
pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy; pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
pd->device_tx_status = pl330_tx_status; pd->device_tx_status = pl330_tx_status;
pd->device_prep_slave_sg = pl330_prep_slave_sg; pd->device_prep_slave_sg = pl330_prep_slave_sg;
pd->device_control = pl330_control; pd->device_control = pl330_control;
...@@ -769,8 +910,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -769,8 +910,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
goto probe_err4; goto probe_err4;
} }
amba_set_drvdata(adev, pdmac);
dev_info(&adev->dev, dev_info(&adev->dev,
"Loaded driver for PL330 DMAC-%d\n", adev->periphid); "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
dev_info(&adev->dev, dev_info(&adev->dev,
...@@ -831,6 +970,13 @@ static int __devexit pl330_remove(struct amba_device *adev) ...@@ -831,6 +970,13 @@ static int __devexit pl330_remove(struct amba_device *adev)
res = &adev->res; res = &adev->res;
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
#ifdef CONFIG_PM_RUNTIME
pm_runtime_put(&adev->dev);
pm_runtime_disable(&adev->dev);
#else
clk_disable(pdmac->clk);
#endif
kfree(pdmac); kfree(pdmac);
return 0; return 0;
...@@ -844,10 +990,49 @@ static struct amba_id pl330_ids[] = { ...@@ -844,10 +990,49 @@ static struct amba_id pl330_ids[] = {
{ 0, 0 }, { 0, 0 },
}; };
#ifdef CONFIG_PM_RUNTIME
static int pl330_runtime_suspend(struct device *dev)
{
struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
if (!pdmac) {
dev_err(dev, "failed to get dmac\n");
return -ENODEV;
}
clk_disable(pdmac->clk);
return 0;
}
static int pl330_runtime_resume(struct device *dev)
{
struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
if (!pdmac) {
dev_err(dev, "failed to get dmac\n");
return -ENODEV;
}
clk_enable(pdmac->clk);
return 0;
}
#else
#define pl330_runtime_suspend NULL
#define pl330_runtime_resume NULL
#endif /* CONFIG_PM_RUNTIME */
static const struct dev_pm_ops pl330_pm_ops = {
.runtime_suspend = pl330_runtime_suspend,
.runtime_resume = pl330_runtime_resume,
};
static struct amba_driver pl330_driver = { static struct amba_driver pl330_driver = {
.drv = { .drv = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "dma-pl330", .name = "dma-pl330",
.pm = &pl330_pm_ops,
}, },
.id_table = pl330_ids, .id_table = pl330_ids,
.probe = pl330_probe, .probe = pl330_probe,
......
...@@ -913,9 +913,9 @@ static void finalize_request(struct s3cmci_host *host) ...@@ -913,9 +913,9 @@ static void finalize_request(struct s3cmci_host *host)
} }
static void s3cmci_dma_setup(struct s3cmci_host *host, static void s3cmci_dma_setup(struct s3cmci_host *host,
enum s3c2410_dmasrc source) enum dma_data_direction source)
{ {
static enum s3c2410_dmasrc last_source = -1; static enum dma_data_direction last_source = -1;
static int setup_ok; static int setup_ok;
if (last_source == source) if (last_source == source)
...@@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) ...@@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
......
...@@ -131,6 +131,12 @@ ...@@ -131,6 +131,12 @@
#define RXBUSY (1<<2) #define RXBUSY (1<<2)
#define TXBUSY (1<<3) #define TXBUSY (1<<3)
struct s3c64xx_spi_dma_data {
unsigned ch;
enum dma_data_direction direction;
enum dma_ch dmach;
};
/** /**
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
* @clk: Pointer to the spi clock. * @clk: Pointer to the spi clock.
...@@ -164,13 +170,14 @@ struct s3c64xx_spi_driver_data { ...@@ -164,13 +170,14 @@ struct s3c64xx_spi_driver_data {
struct work_struct work; struct work_struct work;
struct list_head queue; struct list_head queue;
spinlock_t lock; spinlock_t lock;
enum dma_ch rx_dmach;
enum dma_ch tx_dmach;
unsigned long sfr_start; unsigned long sfr_start;
struct completion xfer_completion; struct completion xfer_completion;
unsigned state; unsigned state;
unsigned cur_mode, cur_bpw; unsigned cur_mode, cur_bpw;
unsigned cur_speed; unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
struct samsung_dma_ops *ops;
}; };
static struct s3c2410_dma_client s3c64xx_spi_dma_client = { static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
...@@ -226,6 +233,78 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) ...@@ -226,6 +233,78 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
writel(val, regs + S3C64XX_SPI_CH_CFG); writel(val, regs + S3C64XX_SPI_CH_CFG);
} }
static void s3c64xx_spi_dmacb(void *data)
{
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_dma_data *dma = data;
unsigned long flags;
if (dma->direction == DMA_FROM_DEVICE)
sdd = container_of(data,
struct s3c64xx_spi_driver_data, rx_dma);
else
sdd = container_of(data,
struct s3c64xx_spi_driver_data, tx_dma);
spin_lock_irqsave(&sdd->lock, flags);
if (dma->direction == DMA_FROM_DEVICE) {
sdd->state &= ~RXBUSY;
if (!(sdd->state & TXBUSY))
complete(&sdd->xfer_completion);
} else {
sdd->state &= ~TXBUSY;
if (!(sdd->state & RXBUSY))
complete(&sdd->xfer_completion);
}
spin_unlock_irqrestore(&sdd->lock, flags);
}
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
unsigned len, dma_addr_t buf)
{
struct s3c64xx_spi_driver_data *sdd;
struct samsung_dma_prep_info info;
if (dma->direction == DMA_FROM_DEVICE)
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, rx_dma);
else
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, tx_dma);
info.cap = DMA_SLAVE;
info.len = len;
info.fp = s3c64xx_spi_dmacb;
info.fp_param = dma;
info.direction = dma->direction;
info.buf = buf;
sdd->ops->prepare(dma->ch, &info);
sdd->ops->trigger(dma->ch);
}
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
struct samsung_dma_info info;
sdd->ops = samsung_dma_get_ops();
info.cap = DMA_SLAVE;
info.client = &s3c64xx_spi_dma_client;
info.width = sdd->cur_bpw / 8;
info.direction = sdd->rx_dma.direction;
info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
info.direction = sdd->tx_dma.direction;
info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
return 1;
}
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer, int dma_mode) struct spi_transfer *xfer, int dma_mode)
...@@ -258,10 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, ...@@ -258,10 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON; chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) { if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
xfer->tx_dma, xfer->len);
s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
} else { } else {
switch (sdd->cur_bpw) { switch (sdd->cur_bpw) {
case 32: case 32:
...@@ -293,10 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, ...@@ -293,10 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN, | S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT); regs + S3C64XX_SPI_PACKET_CNT);
s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
xfer->rx_dma, xfer->len);
s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
} }
} }
...@@ -482,46 +555,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) ...@@ -482,46 +555,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
} }
} }
static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
int size, enum s3c2410_dma_buffresult res)
{
struct s3c64xx_spi_driver_data *sdd = buf_id;
unsigned long flags;
spin_lock_irqsave(&sdd->lock, flags);
if (res == S3C2410_RES_OK)
sdd->state &= ~RXBUSY;
else
dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
/* If the other done */
if (!(sdd->state & TXBUSY))
complete(&sdd->xfer_completion);
spin_unlock_irqrestore(&sdd->lock, flags);
}
static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
int size, enum s3c2410_dma_buffresult res)
{
struct s3c64xx_spi_driver_data *sdd = buf_id;
unsigned long flags;
spin_lock_irqsave(&sdd->lock, flags);
if (res == S3C2410_RES_OK)
sdd->state &= ~TXBUSY;
else
dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
/* If the other done */
if (!(sdd->state & RXBUSY))
complete(&sdd->xfer_completion);
spin_unlock_irqrestore(&sdd->lock, flags);
}
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
...@@ -696,12 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, ...@@ -696,12 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
if (use_dma) { if (use_dma) {
if (xfer->tx_buf != NULL if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY)) && (sdd->state & TXBUSY))
s3c2410_dma_ctrl(sdd->tx_dmach, sdd->ops->stop(sdd->tx_dma.ch);
S3C2410_DMAOP_FLUSH);
if (xfer->rx_buf != NULL if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY)) && (sdd->state & RXBUSY))
s3c2410_dma_ctrl(sdd->rx_dmach, sdd->ops->stop(sdd->rx_dma.ch);
S3C2410_DMAOP_FLUSH);
} }
goto out; goto out;
...@@ -739,30 +770,6 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, ...@@ -739,30 +770,6 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
msg->complete(msg->context); msg->complete(msg->context);
} }
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
if (s3c2410_dma_request(sdd->rx_dmach,
&s3c64xx_spi_dma_client, NULL) < 0) {
dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
return 0;
}
s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
sdd->sfr_start + S3C64XX_SPI_RX_DATA);
if (s3c2410_dma_request(sdd->tx_dmach,
&s3c64xx_spi_dma_client, NULL) < 0) {
dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
return 0;
}
s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
sdd->sfr_start + S3C64XX_SPI_TX_DATA);
return 1;
}
static void s3c64xx_spi_work(struct work_struct *work) static void s3c64xx_spi_work(struct work_struct *work)
{ {
struct s3c64xx_spi_driver_data *sdd = container_of(work, struct s3c64xx_spi_driver_data *sdd = container_of(work,
...@@ -799,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work) ...@@ -799,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
spin_unlock_irqrestore(&sdd->lock, flags); spin_unlock_irqrestore(&sdd->lock, flags);
/* Free DMA channels */ /* Free DMA channels */
s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client); sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
} }
static int s3c64xx_spi_transfer(struct spi_device *spi, static int s3c64xx_spi_transfer(struct spi_device *spi,
...@@ -1017,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1017,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
sdd->cntrlr_info = sci; sdd->cntrlr_info = sci;
sdd->pdev = pdev; sdd->pdev = pdev;
sdd->sfr_start = mem_res->start; sdd->sfr_start = mem_res->start;
sdd->tx_dmach = dmatx_res->start; sdd->tx_dma.dmach = dmatx_res->start;
sdd->rx_dmach = dmarx_res->start; sdd->tx_dma.direction = DMA_TO_DEVICE;
sdd->rx_dma.dmach = dmarx_res->start;
sdd->rx_dma.direction = DMA_FROM_DEVICE;
sdd->cur_bpw = 8; sdd->cur_bpw = 8;
...@@ -1106,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1106,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
pdev->id, master->num_chipselect); pdev->id, master->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
mem_res->end, mem_res->start, mem_res->end, mem_res->start,
sdd->rx_dmach, sdd->tx_dmach); sdd->rx_dma.dmach, sdd->tx_dma.dmach);
return 0; return 0;
......
...@@ -19,12 +19,8 @@ struct dma_pl330_peri { ...@@ -19,12 +19,8 @@ struct dma_pl330_peri {
* Peri_Req i/f of the DMAC that is * Peri_Req i/f of the DMAC that is
* peripheral could be reached from. * peripheral could be reached from.
*/ */
u8 peri_id; /* {0, 31} */ u8 peri_id; /* specific dma id */
enum pl330_reqtype rqtype; enum pl330_reqtype rqtype;
/* For M->D and D->M Channels */
int burst_sz; /* in power of 2 */
dma_addr_t fifo_addr;
}; };
struct dma_pl330_platdata { struct dma_pl330_platdata {
......
...@@ -271,7 +271,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -271,7 +271,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); if (!dma_data->ops)
dma_data->ops = samsung_dma_get_ops();
dma_data->ops->started(dma_data->channel);
return 0; return 0;
} }
...@@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, ...@@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); if (!dma_data->ops)
dma_data->ops = samsung_dma_get_ops();
dma_data->ops->started(dma_data->channel);
return 0; return 0;
} }
......
...@@ -54,7 +54,6 @@ struct runtime_data { ...@@ -54,7 +54,6 @@ struct runtime_data {
spinlock_t lock; spinlock_t lock;
int state; int state;
unsigned int dma_loaded; unsigned int dma_loaded;
unsigned int dma_limit;
unsigned int dma_period; unsigned int dma_period;
dma_addr_t dma_start; dma_addr_t dma_start;
dma_addr_t dma_pos; dma_addr_t dma_pos;
...@@ -62,77 +61,79 @@ struct runtime_data { ...@@ -62,77 +61,79 @@ struct runtime_data {
struct s3c_dma_params *params; struct s3c_dma_params *params;
}; };
static void audio_buffdone(void *data);
/* dma_enqueue /* dma_enqueue
* *
* place a dma buffer onto the queue for the dma system * place a dma buffer onto the queue for the dma system
* to handle. * to handle.
*/ */
static void dma_enqueue(struct snd_pcm_substream *substream) static void dma_enqueue(struct snd_pcm_substream *substream)
{ {
struct runtime_data *prtd = substream->runtime->private_data; struct runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos; dma_addr_t pos = prtd->dma_pos;
unsigned int limit; unsigned int limit;
int ret; struct samsung_dma_prep_info dma_info;
pr_debug("Entered %s\n", __func__); pr_debug("Entered %s\n", __func__);
if (s3c_dma_has_circular()) limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
else
limit = prtd->dma_limit;
pr_debug("%s: loaded %d, limit %d\n", pr_debug("%s: loaded %d, limit %d\n",
__func__, prtd->dma_loaded, limit); __func__, prtd->dma_loaded, limit);
while (prtd->dma_loaded < limit) { dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
unsigned long len = prtd->dma_period; dma_info.direction =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
dma_info.fp = audio_buffdone;
dma_info.fp_param = substream;
dma_info.period = prtd->dma_period;
dma_info.len = prtd->dma_period*limit;
while (prtd->dma_loaded < limit) {
pr_debug("dma_loaded: %d\n", prtd->dma_loaded); pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
if ((pos + len) > prtd->dma_end) { if ((pos + dma_info.period) > prtd->dma_end) {
len = prtd->dma_end - pos; dma_info.period = prtd->dma_end - pos;
pr_debug("%s: corrected dma len %ld\n", __func__, len); pr_debug("%s: corrected dma len %ld\n",
__func__, dma_info.period);
} }
ret = s3c2410_dma_enqueue(prtd->params->channel, dma_info.buf = pos;
substream, pos, len); prtd->params->ops->prepare(prtd->params->ch, &dma_info);
if (ret == 0) { prtd->dma_loaded++;
prtd->dma_loaded++; pos += prtd->dma_period;
pos += prtd->dma_period; if (pos >= prtd->dma_end)
if (pos >= prtd->dma_end) pos = prtd->dma_start;
pos = prtd->dma_start;
} else
break;
} }
prtd->dma_pos = pos; prtd->dma_pos = pos;
} }
static void audio_buffdone(struct s3c2410_dma_chan *channel, static void audio_buffdone(void *data)
void *dev_id, int size,
enum s3c2410_dma_buffresult result)
{ {
struct snd_pcm_substream *substream = dev_id; struct snd_pcm_substream *substream = data;
struct runtime_data *prtd; struct runtime_data *prtd = substream->runtime->private_data;
pr_debug("Entered %s\n", __func__); pr_debug("Entered %s\n", __func__);
if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) if (prtd->state & ST_RUNNING) {
return; prtd->dma_pos += prtd->dma_period;
if (prtd->dma_pos >= prtd->dma_end)
prtd = substream->runtime->private_data; prtd->dma_pos = prtd->dma_start;
if (substream) if (substream)
snd_pcm_period_elapsed(substream); snd_pcm_period_elapsed(substream);
spin_lock(&prtd->lock); spin_lock(&prtd->lock);
if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { if (!samsung_dma_has_circular()) {
prtd->dma_loaded--; prtd->dma_loaded--;
dma_enqueue(substream); dma_enqueue(substream);
}
spin_unlock(&prtd->lock);
} }
spin_unlock(&prtd->lock);
} }
static int dma_hw_params(struct snd_pcm_substream *substream, static int dma_hw_params(struct snd_pcm_substream *substream,
...@@ -144,8 +145,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream, ...@@ -144,8 +145,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
unsigned long totbytes = params_buffer_bytes(params); unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma = struct s3c_dma_params *dma =
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
int ret = 0; struct samsung_dma_info dma_info;
pr_debug("Entered %s\n", __func__); pr_debug("Entered %s\n", __func__);
...@@ -163,30 +163,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream, ...@@ -163,30 +163,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
pr_debug("params %p, client %p, channel %d\n", prtd->params, pr_debug("params %p, client %p, channel %d\n", prtd->params,
prtd->params->client, prtd->params->channel); prtd->params->client, prtd->params->channel);
ret = s3c2410_dma_request(prtd->params->channel, prtd->params->ops = samsung_dma_get_ops();
prtd->params->client, NULL);
dma_info.cap = (samsung_dma_has_circular() ?
if (ret < 0) { DMA_CYCLIC : DMA_SLAVE);
printk(KERN_ERR "failed to get dma channel\n"); dma_info.client = prtd->params->client;
return ret; dma_info.direction =
} (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
/* use the circular buffering if we have it available. */ dma_info.width = prtd->params->dma_size;
if (s3c_dma_has_circular()) dma_info.fifo = prtd->params->dma_addr;
s3c2410_dma_setflags(prtd->params->channel, prtd->params->ch = prtd->params->ops->request(
S3C2410_DMAF_CIRCULAR); prtd->params->channel, &dma_info);
} }
s3c2410_dma_set_buffdone_fn(prtd->params->channel,
audio_buffdone);
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = totbytes; runtime->dma_bytes = totbytes;
spin_lock_irq(&prtd->lock); spin_lock_irq(&prtd->lock);
prtd->dma_loaded = 0; prtd->dma_loaded = 0;
prtd->dma_limit = runtime->hw.periods_min;
prtd->dma_period = params_period_bytes(params); prtd->dma_period = params_period_bytes(params);
prtd->dma_start = runtime->dma_addr; prtd->dma_start = runtime->dma_addr;
prtd->dma_pos = prtd->dma_start; prtd->dma_pos = prtd->dma_start;
...@@ -206,7 +202,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream) ...@@ -206,7 +202,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream)
snd_pcm_set_runtime_buffer(substream, NULL); snd_pcm_set_runtime_buffer(substream, NULL);
if (prtd->params) { if (prtd->params) {
s3c2410_dma_free(prtd->params->channel, prtd->params->client); prtd->params->ops->release(prtd->params->ch,
prtd->params->client);
prtd->params = NULL; prtd->params = NULL;
} }
...@@ -225,23 +222,9 @@ static int dma_prepare(struct snd_pcm_substream *substream) ...@@ -225,23 +222,9 @@ static int dma_prepare(struct snd_pcm_substream *substream)
if (!prtd->params) if (!prtd->params)
return 0; return 0;
/* channel needs configuring for mem=>device, increment memory addr,
* sync to pclk, half-word transfers to the IIS-FIFO. */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
s3c2410_dma_devconfig(prtd->params->channel,
S3C2410_DMASRC_MEM,
prtd->params->dma_addr);
} else {
s3c2410_dma_devconfig(prtd->params->channel,
S3C2410_DMASRC_HW,
prtd->params->dma_addr);
}
s3c2410_dma_config(prtd->params->channel,
prtd->params->dma_size);
/* flush the DMA channel */ /* flush the DMA channel */
s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); prtd->params->ops->flush(prtd->params->ch);
prtd->dma_loaded = 0; prtd->dma_loaded = 0;
prtd->dma_pos = prtd->dma_start; prtd->dma_pos = prtd->dma_start;
...@@ -265,14 +248,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -265,14 +248,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
prtd->state |= ST_RUNNING; prtd->state |= ST_RUNNING;
s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); prtd->params->ops->trigger(prtd->params->ch);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
prtd->state &= ~ST_RUNNING; prtd->state &= ~ST_RUNNING;
s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); prtd->params->ops->stop(prtd->params->ch);
break; break;
default: default:
...@@ -291,21 +274,12 @@ dma_pointer(struct snd_pcm_substream *substream) ...@@ -291,21 +274,12 @@ dma_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct runtime_data *prtd = runtime->private_data; struct runtime_data *prtd = runtime->private_data;
unsigned long res; unsigned long res;
dma_addr_t src, dst;
pr_debug("Entered %s\n", __func__); pr_debug("Entered %s\n", __func__);
spin_lock(&prtd->lock); res = prtd->dma_pos - prtd->dma_start;
s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
res = dst - prtd->dma_start;
else
res = src - prtd->dma_start;
spin_unlock(&prtd->lock);
pr_debug("Pointer %x %x\n", src, dst); pr_debug("Pointer offset: %lu\n", res);
/* we seem to be getting the odd error from the pcm library due /* we seem to be getting the odd error from the pcm library due
* to out-of-bounds pointers. this is maybe due to the dma engine * to out-of-bounds pointers. this is maybe due to the dma engine
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
* *
* ALSA PCM interface for the Samsung S3C24xx CPU * ALSA PCM interface for the Samsung SoC
*/ */
#ifndef _S3C_AUDIO_H #ifndef _S3C_AUDIO_H
...@@ -17,6 +17,8 @@ struct s3c_dma_params { ...@@ -17,6 +17,8 @@ struct s3c_dma_params {
int channel; /* Channel ID */ int channel; /* Channel ID */
dma_addr_t dma_addr; dma_addr_t dma_addr;
int dma_size; /* Size of the DMA transfer */ int dma_size; /* Size of the DMA transfer */
unsigned ch;
struct samsung_dma_ops *ops;
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment