Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
0745c9a5
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
0745c9a5
编写于
9月 21, 2011
作者:
V
Vinod Koul
提交者:
Vinod Koul
9月 21, 2011
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'samsung_dma' into next
上级
f8de8f4c
51ddf31d
变更
40
隐藏空白更改
内联
并排
Showing
40 changed file
with
1599 addition
and
1968 deletion
+1599
-1968
arch/arm/mach-exynos4/Kconfig
arch/arm/mach-exynos4/Kconfig
+1
-1
arch/arm/mach-exynos4/clock.c
arch/arm/mach-exynos4/clock.c
+9
-2
arch/arm/mach-exynos4/dma.c
arch/arm/mach-exynos4/dma.c
+188
-111
arch/arm/mach-exynos4/include/mach/dma.h
arch/arm/mach-exynos4/include/mach/dma.h
+2
-2
arch/arm/mach-s3c2410/include/mach/dma.h
arch/arm/mach-s3c2410/include/mach/dma.h
+13
-7
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2412/dma.c
+2
-2
arch/arm/mach-s3c64xx/dma.c
arch/arm/mach-s3c64xx/dma.c
+5
-5
arch/arm/mach-s3c64xx/include/mach/dma.h
arch/arm/mach-s3c64xx/include/mach/dma.h
+6
-2
arch/arm/mach-s5p64x0/Kconfig
arch/arm/mach-s5p64x0/Kconfig
+2
-2
arch/arm/mach-s5p64x0/clock-s5p6440.c
arch/arm/mach-s5p64x0/clock-s5p6440.c
+8
-1
arch/arm/mach-s5p64x0/clock-s5p6450.c
arch/arm/mach-s5p64x0/clock-s5p6450.c
+8
-1
arch/arm/mach-s5p64x0/dma.c
arch/arm/mach-s5p64x0/dma.c
+182
-91
arch/arm/mach-s5p64x0/include/mach/dma.h
arch/arm/mach-s5p64x0/include/mach/dma.h
+2
-2
arch/arm/mach-s5pc100/Kconfig
arch/arm/mach-s5pc100/Kconfig
+1
-1
arch/arm/mach-s5pc100/clock.c
arch/arm/mach-s5pc100/clock.c
+9
-2
arch/arm/mach-s5pc100/dma.c
arch/arm/mach-s5pc100/dma.c
+211
-112
arch/arm/mach-s5pc100/include/mach/dma.h
arch/arm/mach-s5pc100/include/mach/dma.h
+2
-2
arch/arm/mach-s5pv210/Kconfig
arch/arm/mach-s5pv210/Kconfig
+1
-1
arch/arm/mach-s5pv210/clock.c
arch/arm/mach-s5pv210/clock.c
+8
-2
arch/arm/mach-s5pv210/dma.c
arch/arm/mach-s5pv210/dma.c
+204
-112
arch/arm/mach-s5pv210/include/mach/dma.h
arch/arm/mach-s5pv210/include/mach/dma.h
+2
-2
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/dma.c
+5
-5
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Kconfig
+6
-3
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/Makefile
+2
-2
arch/arm/plat-samsung/dma-ops.c
arch/arm/plat-samsung/dma-ops.c
+131
-0
arch/arm/plat-samsung/include/plat/dma-ops.h
arch/arm/plat-samsung/include/plat/dma-ops.h
+63
-0
arch/arm/plat-samsung/include/plat/dma-pl330.h
arch/arm/plat-samsung/include/plat/dma-pl330.h
+15
-9
arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
+1
-1
arch/arm/plat-samsung/include/plat/dma.h
arch/arm/plat-samsung/include/plat/dma.h
+4
-6
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
+0
-32
arch/arm/plat-samsung/s3c-dma-ops.c
arch/arm/plat-samsung/s3c-dma-ops.c
+130
-0
arch/arm/plat-samsung/s3c-pl330.c
arch/arm/plat-samsung/s3c-pl330.c
+0
-1244
drivers/dma/Kconfig
drivers/dma/Kconfig
+2
-1
drivers/dma/pl330.c
drivers/dma/pl330.c
+207
-22
drivers/mmc/host/s3cmci.c
drivers/mmc/host/s3cmci.c
+3
-3
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-s3c64xx.c
+92
-83
include/linux/amba/pl330.h
include/linux/amba/pl330.h
+1
-5
sound/soc/samsung/ac97.c
sound/soc/samsung/ac97.c
+8
-2
sound/soc/samsung/dma.c
sound/soc/samsung/dma.c
+60
-86
sound/soc/samsung/dma.h
sound/soc/samsung/dma.h
+3
-1
未找到文件。
arch/arm/mach-exynos4/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
config CPU_EXYNOS4210
bool
select S
3C_PL330_DMA
select S
AMSUNG_DMADEV
help
Enable EXYNOS4210 CPU support
...
...
arch/arm/mach-exynos4/clock.c
浏览文件 @
0745c9a5
...
...
@@ -43,6 +43,11 @@ static struct clk clk_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
)
{
return
s5p_gatectrl
(
S5P_CLKSRC_MASK_TOP
,
clk
,
enable
);
...
...
@@ -454,12 +459,12 @@ static struct clk init_clocks_off[] = {
.
enable
=
exynos4_clk_ip_fsys_ctrl
,
.
ctrlbit
=
(
1
<<
10
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.0"
,
.
enable
=
exynos4_clk_ip_fsys_ctrl
,
.
ctrlbit
=
(
1
<<
0
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.1"
,
.
enable
=
exynos4_clk_ip_fsys_ctrl
,
.
ctrlbit
=
(
1
<<
1
),
...
...
@@ -1210,5 +1215,7 @@ void __init exynos4_register_clocks(void)
s3c_register_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
();
}
arch/arm/mach-exynos4/dma.c
浏览文件 @
0745c9a5
...
...
@@ -21,151 +21,228 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/platform_device.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/irqs.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/s3c-pl330-pdata.h>
#include <mach/dma.h>
static
u64
dma_dmamask
=
DMA_BIT_MASK
(
32
);
static
struct
resource
exynos4_pdma0_resource
[]
=
{
[
0
]
=
{
.
start
=
EXYNOS4_PA_PDMA0
,
.
end
=
EXYNOS4_PA_PDMA0
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA0
,
.
end
=
IRQ_PDMA0
,
.
flags
=
IORESOURCE_IRQ
,
struct
dma_pl330_peri
pdma0_peri
[
28
]
=
{
{
.
peri_id
=
(
u8
)
DMACH_PCM0_RX
,
.
rqtype
=
DEVTOMEM
,
},
{
.
peri_id
=
(
u8
)
DMACH_PCM0_TX
,
.
rqtype
=
MEMTODEV
,
},
{
.
peri_id
=
(
u8
)
DMACH_PCM2_RX
,
.
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
=
{
.
peri
=
{
[
0
]
=
DMACH_PCM0_RX
,
[
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
,
},
struct
dma_pl330_platdata
exynos4_pdma0_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma0_peri
),
.
peri
=
pdma0_peri
,
};
static
struct
platform_device
exynos4_device_pdma0
=
{
.
name
=
"s3c-pl330"
,
.
id
=
0
,
.
num_resources
=
ARRAY_SIZE
(
exynos4_pdma0_resource
),
.
resource
=
exynos4_pdma0_resource
,
.
dev
=
{
struct
amba_device
exynos4_device_pdma0
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.0"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
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
[]
=
{
[
0
]
=
{
.
start
=
EXYNOS4_PA_PDMA1
,
.
end
=
EXYNOS4_PA_PDMA1
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA1
,
.
end
=
IRQ_PDMA1
,
.
flags
=
IORESOURCE_IRQ
,
struct
dma_pl330_peri
pdma1_peri
[
25
]
=
{
{
.
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_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
=
{
.
peri
=
{
[
0
]
=
DMACH_PCM0_RX
,
[
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
,
},
struct
dma_pl330_platdata
exynos4_pdma1_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma1_peri
),
.
peri
=
pdma1_peri
,
};
static
struct
platform_device
exynos4_device_pdma1
=
{
.
name
=
"s3c-pl330"
,
.
id
=
1
,
.
num_resources
=
ARRAY_SIZE
(
exynos4_pdma1_resource
),
.
resource
=
exynos4_pdma1_resource
,
.
dev
=
{
struct
amba_device
exynos4_device_pdma1
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.1"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
platform_data
=
&
exynos4_pdma1_pdata
,
},
};
static
struct
platform_device
*
exynos4_dmacs
[]
__initdata
=
{
&
exynos4_device_pdma0
,
&
exynos4_device_pdma1
,
.
res
=
{
.
start
=
EXYNOS4_PA_PDMA1
,
.
end
=
EXYNOS4_PA_PDMA1
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
.
irq
=
{
IRQ_PDMA1
,
NO_IRQ
},
.
periphid
=
0x00041330
,
};
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
;
}
...
...
arch/arm/mach-exynos4/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H
#define __MACH_DMA_H
/* This platform uses the common
S3C
DMA API driver for PL330 */
#include <plat/
s3c-
dma-pl330.h>
/* This platform uses the common DMA API driver for PL330 */
#include <plat/dma-pl330.h>
#endif
/* __MACH_DMA_H */
arch/arm/mach-s3c2410/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -13,7 +13,6 @@
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__
#include <plat/dma.h>
#include <linux/sysdev.h>
#define MAX_DMA_TRANSFER_SIZE 0x100000
/* Data Unit is half word */
...
...
@@ -51,6 +50,18 @@ enum dma_ch {
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 */
/* we have 4 dma channels */
...
...
@@ -163,7 +174,7 @@ struct s3c2410_dma_chan {
struct
s3c2410_dma_client
*
client
;
/* channel configuration */
enum
s3c2410_dmasrc
source
;
enum
dma_data_direction
source
;
enum
dma_ch
req_ch
;
unsigned
long
dev_addr
;
unsigned
long
load_timeout
;
...
...
@@ -196,9 +207,4 @@ struct s3c2410_dma_chan {
typedef
unsigned
long
dma_device_t
;
static
inline
bool
s3c_dma_has_circular
(
void
)
{
return
false
;
}
#endif
/* __ASM_ARCH_DMA_H */
arch/arm/mach-s3c2412/dma.c
浏览文件 @
0745c9a5
...
...
@@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
static
void
s3c2412_dma_direction
(
struct
s3c2410_dma_chan
*
chan
,
struct
s3c24xx_dma_map
*
map
,
enum
s3c2410_dmasrc
dir
)
enum
dma_data_direction
dir
)
{
unsigned
long
chsel
;
if
(
dir
==
S3C2410_DMASRC_HW
)
if
(
dir
==
DMA_FROM_DEVICE
)
chsel
=
map
->
channels_rx
[
0
];
else
chsel
=
map
->
channels
[
0
];
...
...
arch/arm/mach-s3c64xx/dma.c
浏览文件 @
0745c9a5
...
...
@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
u32
control0
,
control1
;
switch
(
chan
->
source
)
{
case
S3C2410_DMASRC_HW
:
case
DMA_FROM_DEVICE
:
src
=
chan
->
dev_addr
;
dst
=
data
;
control0
=
PL080_CONTROL_SRC_AHB2
;
control0
|=
PL080_CONTROL_DST_INCR
;
break
;
case
S3C2410_DMASRC_MEM
:
case
DMA_TO_DEVICE
:
src
=
data
;
dst
=
chan
->
dev_addr
;
control0
=
PL080_CONTROL_DST_AHB2
;
...
...
@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue);
int
s3c2410_dma_devconfig
(
enum
dma_ch
channel
,
enum
s3c2410_dmasrc
source
,
enum
dma_data_direction
source
,
unsigned
long
devaddr
)
{
struct
s3c2410_dma_chan
*
chan
=
s3c_dma_lookup_channel
(
channel
);
...
...
@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
pr_debug
(
"%s: peripheral %d
\n
"
,
__func__
,
peripheral
);
switch
(
source
)
{
case
S3C2410_DMASRC_HW
:
case
DMA_FROM_DEVICE
:
config
=
2
<<
PL080_CONFIG_FLOW_CONTROL_SHIFT
;
config
|=
peripheral
<<
PL080_CONFIG_SRC_SEL_SHIFT
;
break
;
case
S3C2410_DMASRC_MEM
:
case
DMA_TO_DEVICE
:
config
=
1
<<
PL080_CONFIG_FLOW_CONTROL_SHIFT
;
config
|=
peripheral
<<
PL080_CONFIG_DST_SEL_SHIFT
;
break
;
...
...
arch/arm/mach-s3c64xx/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -58,11 +58,15 @@ enum dma_ch {
DMACH_MAX
/* the end */
};
static
__inline__
bool
s3c
_dma_has_circular
(
void
)
static
inline
bool
samsung
_dma_has_circular
(
void
)
{
return
true
;
}
static
inline
bool
samsung_dma_is_dmadev
(
void
)
{
return
false
;
}
#define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h>
...
...
@@ -95,7 +99,7 @@ struct s3c2410_dma_chan {
unsigned
char
peripheral
;
unsigned
int
flags
;
enum
s3c2410_dmasrc
source
;
enum
dma_data_direction
source
;
dma_addr_t
dev_addr
;
...
...
arch/arm/mach-s5p64x0/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -9,14 +9,14 @@ if ARCH_S5P64X0
config CPU_S5P6440
bool
select S
3C_PL330_DMA
select S
AMSUNG_DMADEV
select S5P_HRT
help
Enable S5P6440 CPU support
config CPU_S5P6450
bool
select S
3C_PL330_DMA
select S
AMSUNG_DMADEV
select S5P_HRT
help
Enable S5P6450 CPU support
...
...
arch/arm/mach-s5p64x0/clock-s5p6440.c
浏览文件 @
0745c9a5
...
...
@@ -146,7 +146,7 @@ static struct clk init_clocks_off[] = {
.
enable
=
s5p64x0_hclk0_ctrl
,
.
ctrlbit
=
(
1
<<
8
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
parent
=
&
clk_hclk_low
.
clk
,
.
enable
=
s5p64x0_hclk0_ctrl
,
.
ctrlbit
=
(
1
<<
12
),
...
...
@@ -499,6 +499,11 @@ static struct clksrc_clk *sysclks[] = {
&
clk_pclk_low
,
};
static
struct
clk
dummy_apb_pclk
=
{
.
name
=
"apb_pclk"
,
.
id
=
-
1
,
};
void
__init_or_cpufreq
s5p6440_setup_clocks
(
void
)
{
struct
clk
*
xtal_clk
;
...
...
@@ -581,5 +586,7 @@ void __init s5p6440_register_clocks(void)
s3c_register_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
();
}
arch/arm/mach-s5p64x0/clock-s5p6450.c
浏览文件 @
0745c9a5
...
...
@@ -179,7 +179,7 @@ static struct clk init_clocks_off[] = {
.
enable
=
s5p64x0_hclk0_ctrl
,
.
ctrlbit
=
(
1
<<
3
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
parent
=
&
clk_hclk_low
.
clk
,
.
enable
=
s5p64x0_hclk0_ctrl
,
.
ctrlbit
=
(
1
<<
12
),
...
...
@@ -553,6 +553,11 @@ static struct clksrc_clk *sysclks[] = {
&
clk_sclk_audio0
,
};
static
struct
clk
dummy_apb_pclk
=
{
.
name
=
"apb_pclk"
,
.
id
=
-
1
,
};
void
__init_or_cpufreq
s5p6450_setup_clocks
(
void
)
{
struct
clk
*
xtal_clk
;
...
...
@@ -632,5 +637,7 @@ void __init s5p6450_register_clocks(void)
s3c_register_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
();
}
arch/arm/mach-s5p64x0/dma.c
浏览文件 @
0745c9a5
...
...
@@ -21,128 +21,219 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/platform_device.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/irqs.h>
#include <mach/regs-clock.h>
#include <mach/dma.h>
#include <plat/devs.h>
#include <plat/
s3c-pl330-pdata
.h>
#include <plat/
irqs
.h>
static
u64
dma_dmamask
=
DMA_BIT_MASK
(
32
);
static
struct
resource
s5p64x0_pdma_resource
[]
=
{
[
0
]
=
{
.
start
=
S5P64X0_PA_PDMA
,
.
end
=
S5P64X0_PA_PDMA
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_DMA0
,
.
end
=
IRQ_DMA0
,
.
flags
=
IORESOURCE_IRQ
,
struct
dma_pl330_peri
s5p6440_pdma_peri
[
22
]
=
{
{
.
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_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
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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
,
},
struct
dma_pl330_platdata
s5p6440_pdma_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
s5p6440_pdma_peri
),
.
peri
=
s5p6440_pdma_peri
,
};
static
struct
s3c_pl330_platdata
s5p6450_pdma_pdata
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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_UART4_RX
,
[
9
]
=
DMACH_UART4_TX
,
[
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_PCM1_TX
,
[
17
]
=
DMACH_PCM1_RX
,
[
18
]
=
DMACH_PCM2_TX
,
[
19
]
=
DMACH_PCM2_RX
,
[
20
]
=
DMACH_SPI1_TX
,
[
21
]
=
DMACH_SPI1_RX
,
[
22
]
=
DMACH_USI_TX
,
[
23
]
=
DMACH_USI_RX
,
[
24
]
=
DMACH_MAX
,
[
25
]
=
DMACH_I2S1_TX
,
[
26
]
=
DMACH_I2S1_RX
,
[
27
]
=
DMACH_I2S2_TX
,
[
28
]
=
DMACH_I2S2_RX
,
[
29
]
=
DMACH_PWM
,
[
30
]
=
DMACH_UART5_RX
,
[
31
]
=
DMACH_UART5_TX
,
struct
dma_pl330_peri
s5p6450_pdma_peri
[
32
]
=
{
{
.
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_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
=
(
u8
)
DMACH_UART4_RX
,
.
rqtype
=
DEVTOMEM
,
},
{
.
peri_id
=
(
u8
)
DMACH_UART4_TX
,
.
rqtype
=
MEMTODEV
,
},
{
.
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_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
=
{
.
name
=
"s3c-pl330"
,
.
id
=
-
1
,
.
num_resources
=
ARRAY_SIZE
(
s5p64x0_pdma_resource
),
.
resource
=
s5p64x0_pdma_resource
,
.
dev
=
{
struct
dma_pl330_platdata
s5p6450_pdma_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
s5p6450_pdma_peri
),
.
peri
=
s5p6450_pdma_peri
,
};
struct
amba_device
s5p64x0_device_pdma
=
{
.
dev
=
{
.
init_name
=
"dma-pl330"
,
.
dma_mask
=
&
dma_dmamask
,
.
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
)
{
unsigned
int
id
;
id
=
__raw_readl
(
S5P64X0_SYS_ID
)
&
0xFF000
;
unsigned
int
id
=
__raw_readl
(
S5P64X0_SYS_ID
)
&
0xFF000
;
if
(
id
==
0x50000
)
s5p64x0_device_pdma
.
dev
.
platform_data
=
&
s5p6450_pdma_pdata
;
else
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
;
}
...
...
arch/arm/mach-s5p64x0/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H
#define __MACH_DMA_H
/* This platform uses the common
S3C
DMA API driver for PL330 */
#include <plat/
s3c-
dma-pl330.h>
/* This platform uses the common
common
DMA API driver for PL330 */
#include <plat/dma-pl330.h>
#endif
/* __MACH_DMA_H */
arch/arm/mach-s5pc100/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -10,7 +10,7 @@ if ARCH_S5PC100
config CPU_S5PC100
bool
select S5P_EXT_INT
select S
3C_PL330_DMA
select S
AMSUNG_DMADEV
help
Enable S5PC100 CPU support
...
...
arch/arm/mach-s5pc100/clock.c
浏览文件 @
0745c9a5
...
...
@@ -33,6 +33,11 @@ static struct clk s5p_clk_otgphy = {
.
name
=
"otg_phy"
,
};
static
struct
clk
dummy_apb_pclk
=
{
.
name
=
"apb_pclk"
,
.
id
=
-
1
,
};
static
struct
clk
*
clk_src_mout_href_list
[]
=
{
[
0
]
=
&
s5p_clk_27m
,
[
1
]
=
&
clk_fin_hpll
,
...
...
@@ -454,13 +459,13 @@ static struct clk init_clocks_off[] = {
.
enable
=
s5pc100_d1_0_ctrl
,
.
ctrlbit
=
(
1
<<
2
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.1"
,
.
parent
=
&
clk_div_d1_bus
.
clk
,
.
enable
=
s5pc100_d1_0_ctrl
,
.
ctrlbit
=
(
1
<<
1
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.0"
,
.
parent
=
&
clk_div_d1_bus
.
clk
,
.
enable
=
s5pc100_d1_0_ctrl
,
...
...
@@ -1276,5 +1281,7 @@ void __init s5pc100_register_clocks(void)
s3c_register_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
();
}
arch/arm/mach-s5pc100/dma.c
浏览文件 @
0745c9a5
/*
/* 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.
* Jaswinder Singh <jassi.brar@samsung.com>
*
...
...
@@ -17,150 +21,245 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/platform_device.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/irqs.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/s3c-pl330-pdata.h>
#include <mach/dma.h>
static
u64
dma_dmamask
=
DMA_BIT_MASK
(
32
);
static
struct
resource
s5pc100_pdma0_resource
[]
=
{
[
0
]
=
{
.
start
=
S5PC100_PA_PDMA0
,
.
end
=
S5PC100_PA_PDMA0
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA0
,
.
end
=
IRQ_PDMA0
,
.
flags
=
IORESOURCE_IRQ
,
struct
dma_pl330_peri
pdma0_peri
[
30
]
=
{
{
.
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_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
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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
,
},
struct
dma_pl330_platdata
s5pc100_pdma0_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma0_peri
),
.
peri
=
pdma0_peri
,
};
static
struct
platform_device
s5pc100_device_pdma0
=
{
.
name
=
"s3c-pl330"
,
.
id
=
0
,
.
num_resources
=
ARRAY_SIZE
(
s5pc100_pdma0_resource
),
.
resource
=
s5pc100_pdma0_resource
,
.
dev
=
{
struct
amba_device
s5pc100_device_pdma0
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.0"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
platform_data
=
&
s5pc100_pdma0_pdata
,
},
};
static
struct
resource
s5pc100_pdma1_resource
[]
=
{
[
0
]
=
{
.
start
=
S5PC100_PA_PDMA1
,
.
end
=
S5PC100_PA_PDMA1
+
SZ_4K
,
.
res
=
{
.
start
=
S5PC100_PA_PDMA0
,
.
end
=
S5PC100_PA_PDMA0
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA1
,
.
end
=
IRQ_PDMA1
,
.
flags
=
IORESOURCE_IRQ
,
},
.
irq
=
{
IRQ_PDMA0
,
NO_IRQ
},
.
periphid
=
0x00041330
,
};
static
struct
s3c_pl330_platdata
s5pc100_pdma1_pdata
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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_PCM0_RX
,
[
23
]
=
DMACH_PCM0_TX
,
[
24
]
=
DMACH_PCM1_RX
,
[
25
]
=
DMACH_PCM1_TX
,
[
26
]
=
DMACH_MSM_REQ0
,
[
27
]
=
DMACH_MSM_REQ1
,
[
28
]
=
DMACH_MSM_REQ2
,
[
29
]
=
DMACH_MSM_REQ3
,
[
30
]
=
DMACH_MAX
,
[
31
]
=
DMACH_MAX
,
struct
dma_pl330_peri
pdma1_peri
[
30
]
=
{
{
.
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_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_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
=
{
.
name
=
"s3c-pl330"
,
.
id
=
1
,
.
num_resources
=
ARRAY_SIZE
(
s5pc100_pdma1_resource
),
.
resource
=
s5pc100_pdma1_resource
,
.
dev
=
{
struct
dma_pl330_platdata
s5pc100_pdma1_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma1_peri
),
.
peri
=
pdma1_peri
,
};
struct
amba_device
s5pc100_device_pdma1
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.1"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
platform_data
=
&
s5pc100_pdma1_pdata
,
},
};
static
struct
platform_device
*
s5pc100_dmacs
[]
__initdata
=
{
&
s5pc100_device_pdma0
,
&
s5pc100_device_pdma1
,
.
res
=
{
.
start
=
S5PC100_PA_PDMA1
,
.
end
=
S5PC100_PA_PDMA1
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
.
irq
=
{
IRQ_PDMA1
,
NO_IRQ
},
.
periphid
=
0x00041330
,
};
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
;
}
...
...
arch/arm/mach-s5pc100/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H
#define __MACH_DMA_H
/* This platform uses the common
S3C
DMA API driver for PL330 */
#include <plat/
s3c-
dma-pl330.h>
/* This platform uses the common DMA API driver for PL330 */
#include <plat/dma-pl330.h>
#endif
/* __MACH_DMA_H */
arch/arm/mach-s5pv210/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -11,7 +11,7 @@ if ARCH_S5PV210
config CPU_S5PV210
bool
select S
3C_PL330_DMA
select S
AMSUNG_DMADEV
select S5P_EXT_INT
select S5P_HRT
select S5PV210_PM if PM
...
...
arch/arm/mach-s5pv210/clock.c
浏览文件 @
0745c9a5
...
...
@@ -203,6 +203,11 @@ static struct clk clk_pcmcdclk2 = {
.
name
=
"pcmcdclk"
,
};
static
struct
clk
dummy_apb_pclk
=
{
.
name
=
"apb_pclk"
,
.
id
=
-
1
,
};
static
struct
clk
*
clkset_vpllsrc_list
[]
=
{
[
0
]
=
&
clk_fin_vpll
,
[
1
]
=
&
clk_sclk_hdmi27m
,
...
...
@@ -289,13 +294,13 @@ static struct clk_ops clk_fout_apll_ops = {
static
struct
clk
init_clocks_off
[]
=
{
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.0"
,
.
parent
=
&
clk_hclk_psys
.
clk
,
.
enable
=
s5pv210_clk_ip0_ctrl
,
.
ctrlbit
=
(
1
<<
3
),
},
{
.
name
=
"
p
dma"
,
.
name
=
"dma"
,
.
devname
=
"s3c-pl330.1"
,
.
parent
=
&
clk_hclk_psys
.
clk
,
.
enable
=
s5pv210_clk_ip0_ctrl
,
...
...
@@ -1161,5 +1166,6 @@ void __init s5pv210_register_clocks(void)
s3c_register_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
();
}
arch/arm/mach-s5pv210/dma.c
浏览文件 @
0745c9a5
/*
/* 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.
* Jaswinder Singh <jassi.brar@samsung.com>
*
...
...
@@ -17,151 +21,239 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/platform_device.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/irqs.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/s3c-pl330-pdata.h>
#include <mach/dma.h>
static
u64
dma_dmamask
=
DMA_BIT_MASK
(
32
);
static
struct
resource
s5pv210_pdma0_resource
[]
=
{
[
0
]
=
{
.
start
=
S5PV210_PA_PDMA0
,
.
end
=
S5PV210_PA_PDMA0
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA0
,
.
end
=
IRQ_PDMA0
,
.
flags
=
IORESOURCE_IRQ
,
struct
dma_pl330_peri
pdma0_peri
[
28
]
=
{
{
.
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_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
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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
,
},
struct
dma_pl330_platdata
s5pv210_pdma0_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma0_peri
),
.
peri
=
pdma0_peri
,
};
static
struct
platform_device
s5pv210_device_pdma0
=
{
.
name
=
"s3c-pl330"
,
.
id
=
0
,
.
num_resources
=
ARRAY_SIZE
(
s5pv210_pdma0_resource
),
.
resource
=
s5pv210_pdma0_resource
,
.
dev
=
{
struct
amba_device
s5pv210_device_pdma0
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.0"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
platform_data
=
&
s5pv210_pdma0_pdata
,
},
};
static
struct
resource
s5pv210_pdma1_resource
[]
=
{
[
0
]
=
{
.
start
=
S5PV210_PA_PDMA1
,
.
end
=
S5PV210_PA_PDMA1
+
SZ_4K
,
.
res
=
{
.
start
=
S5PV210_PA_PDMA0
,
.
end
=
S5PV210_PA_PDMA0
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
[
1
]
=
{
.
start
=
IRQ_PDMA1
,
.
end
=
IRQ_PDMA1
,
.
flags
=
IORESOURCE_IRQ
,
},
.
irq
=
{
IRQ_PDMA0
,
NO_IRQ
},
.
periphid
=
0x00041330
,
};
static
struct
s3c_pl330_platdata
s5pv210_pdma1_pdata
=
{
.
peri
=
{
[
0
]
=
DMACH_UART0_RX
,
[
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_I2S2_RX
,
[
15
]
=
DMACH_I2S2_TX
,
[
16
]
=
DMACH_SPI0_RX
,
[
17
]
=
DMACH_SPI0_TX
,
[
18
]
=
DMACH_SPI1_RX
,
[
19
]
=
DMACH_SPI1_TX
,
[
20
]
=
DMACH_MAX
,
[
21
]
=
DMACH_MAX
,
[
22
]
=
DMACH_PCM0_RX
,
[
23
]
=
DMACH_PCM0_TX
,
[
24
]
=
DMACH_PCM1_RX
,
[
25
]
=
DMACH_PCM1_TX
,
[
26
]
=
DMACH_MSM_REQ0
,
[
27
]
=
DMACH_MSM_REQ1
,
[
28
]
=
DMACH_MSM_REQ2
,
[
29
]
=
DMACH_MSM_REQ3
,
[
30
]
=
DMACH_PCM2_RX
,
[
31
]
=
DMACH_PCM2_TX
,
struct
dma_pl330_peri
pdma1_peri
[
32
]
=
{
{
.
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_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_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
=
{
.
name
=
"s3c-pl330"
,
.
id
=
1
,
.
num_resources
=
ARRAY_SIZE
(
s5pv210_pdma1_resource
),
.
resource
=
s5pv210_pdma1_resource
,
.
dev
=
{
struct
dma_pl330_platdata
s5pv210_pdma1_pdata
=
{
.
nr_valid_peri
=
ARRAY_SIZE
(
pdma1_peri
),
.
peri
=
pdma1_peri
,
};
struct
amba_device
s5pv210_device_pdma1
=
{
.
dev
=
{
.
init_name
=
"dma-pl330.1"
,
.
dma_mask
=
&
dma_dmamask
,
.
coherent_dma_mask
=
DMA_BIT_MASK
(
32
),
.
platform_data
=
&
s5pv210_pdma1_pdata
,
},
};
static
struct
platform_device
*
s5pv210_dmacs
[]
__initdata
=
{
&
s5pv210_device_pdma0
,
&
s5pv210_device_pdma1
,
.
res
=
{
.
start
=
S5PV210_PA_PDMA1
,
.
end
=
S5PV210_PA_PDMA1
+
SZ_4K
,
.
flags
=
IORESOURCE_MEM
,
},
.
irq
=
{
IRQ_PDMA1
,
NO_IRQ
},
.
periphid
=
0x00041330
,
};
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
;
}
...
...
arch/arm/mach-s5pv210/include/mach/dma.h
浏览文件 @
0745c9a5
...
...
@@ -20,7 +20,7 @@
#ifndef __MACH_DMA_H
#define __MACH_DMA_H
/* This platform uses the common
S3C
DMA API driver for PL330 */
#include <plat/
s3c-
dma-pl330.h>
/* This platform uses the common DMA API driver for PL330 */
#include <plat/dma-pl330.h>
#endif
/* __MACH_DMA_H */
arch/arm/plat-s3c24xx/dma.c
浏览文件 @
0745c9a5
...
...
@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config);
*
* configure the dma source/destination hardware type and address
*
* source:
S3C2410_DMASRC_HW
: source is hardware
*
S3C2410_DMASRC_MEM
: source is memory
* source:
DMA_FROM_DEVICE
: source is hardware
*
DMA_TO_DEVICE
: source is memory
*
* devaddr: physical address of the source
*/
int
s3c2410_dma_devconfig
(
enum
dma_ch
channel
,
enum
s3c2410_dmasrc
source
,
enum
dma_data_direction
source
,
unsigned
long
devaddr
)
{
struct
s3c2410_dma_chan
*
chan
=
s3c_dma_lookup_channel
(
channel
);
...
...
@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
hwcfg
|=
S3C2410_DISRCC_INC
;
switch
(
source
)
{
case
S3C2410_DMASRC_HW
:
case
DMA_FROM_DEVICE
:
/* source is hardware */
pr_debug
(
"%s: hw source, devaddr=%08lx, hwcfg=%d
\n
"
,
__func__
,
devaddr
,
hwcfg
);
...
...
@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(enum dma_ch channel,
chan
->
addr_reg
=
dma_regaddr
(
chan
,
S3C2410_DMA_DIDST
);
break
;
case
S3C2410_DMASRC_MEM
:
case
DMA_TO_DEVICE
:
/* source is memory */
pr_debug
(
"%s: mem source, devaddr=%08lx, hwcfg=%d
\n
"
,
__func__
,
devaddr
,
hwcfg
);
...
...
arch/arm/plat-samsung/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -300,11 +300,14 @@ config S3C_DMA
help
Internal configuration for S3C DMA core
config S
3C_PL330_DMA
config S
AMSUNG_DMADEV
bool
select PL330
select DMADEVICES
select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \
CPU_S5P6450 || CPU_S5P6440)
select ARM_AMBA
help
S3C DMA API Driver
for PL330 DMAC.
Use DMA device engine
for PL330 DMAC.
comment "Power management"
...
...
arch/arm/plat-samsung/Makefile
浏览文件 @
0745c9a5
...
...
@@ -63,9 +63,9 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
# DMA support
obj-$(CONFIG_S3C_DMA)
+=
dma.o
obj-$(CONFIG_S3C_DMA)
+=
dma.o
s3c-dma-ops.o
obj-$(CONFIG_S
3C_PL330_DMA)
+=
s3c-pl330
.o
obj-$(CONFIG_S
AMSUNG_DMADEV)
+=
dma-ops
.o
# PM support
...
...
arch/arm/plat-samsung/dma-ops.c
0 → 100644
浏览文件 @
0745c9a5
/* 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
0 → 100644
浏览文件 @
0745c9a5
/* 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_ */
arch/arm/plat-samsung/include/plat/
s3c-
dma-pl330.h
→
arch/arm/plat-samsung/include/plat/dma-pl330.h
浏览文件 @
0745c9a5
...
...
@@ -8,11 +8,8 @@
* (at your option) any later version.
*/
#ifndef __S3C_DMA_PL330_H_
#define __S3C_DMA_PL330_H_
#define S3C2410_DMAF_AUTOSTART (1 << 0)
#define S3C2410_DMAF_CIRCULAR (1 << 1)
#ifndef __DMA_PL330_H_
#define __DMA_PL330_H_ __FILE__
/*
* PL330 can assign any channel to communicate with
...
...
@@ -20,7 +17,7 @@
* For the sake of consistency across client drivers,
* We keep the channel names unchanged and only add
* 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.
*/
enum
dma_ch
{
...
...
@@ -88,11 +85,20 @@ enum dma_ch {
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
;
}
#include <plat/dma.h>
#include <plat/dma
-ops
.h>
#endif
/* __
S3C_
DMA_PL330_H_ */
#endif
/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
浏览文件 @
0745c9a5
...
...
@@ -47,7 +47,7 @@ struct s3c24xx_dma_selection {
void
(
*
direction
)(
struct
s3c2410_dma_chan
*
chan
,
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
);
...
...
arch/arm/plat-samsung/include/plat/dma.h
浏览文件 @
0745c9a5
...
...
@@ -10,17 +10,14 @@
* published by the Free Software Foundation.
*/
#include <linux/dma-mapping.h>
enum
s3c2410_dma_buffresult
{
S3C2410_RES_OK
,
S3C2410_RES_ERR
,
S3C2410_RES_ABORT
};
enum
s3c2410_dmasrc
{
S3C2410_DMASRC_HW
,
/* source is memory */
S3C2410_DMASRC_MEM
/* source is hardware */
};
/* enum s3c2410_chan_op
*
* 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);
*/
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
*
...
...
@@ -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
);
#include <plat/dma-ops.h>
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
已删除
100644 → 0
浏览文件 @
f8de8f4c
/* 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 */
arch/arm/plat-samsung/s3c-dma-ops.c
0 → 100644
浏览文件 @
0745c9a5
/* 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
);
arch/arm/plat-samsung/s3c-pl330.c
已删除
100644 → 0
浏览文件 @
f8de8f4c
/* linux/arch/arm/plat-samsung/s3c-pl330.c
*
* 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/hardware/pl330.h>
#include <plat/s3c-pl330-pdata.h>
/**
* struct s3c_pl330_dmac - Logical representation of a PL330 DMAC.
* @busy_chan: Number of channels currently busy.
* @peri: List of IDs of peripherals this DMAC can work with.
* @node: To attach to the global list of DMACs.
* @pi: PL330 configuration info for the DMAC.
* @kmcache: Pool to quickly allocate xfers for all channels in the dmac.
* @clk: Pointer of DMAC operation clock.
*/
struct
s3c_pl330_dmac
{
unsigned
busy_chan
;
enum
dma_ch
*
peri
;
struct
list_head
node
;
struct
pl330_info
*
pi
;
struct
kmem_cache
*
kmcache
;
struct
clk
*
clk
;
};
/**
* struct s3c_pl330_xfer - A request submitted by S3C DMA clients.
* @token: Xfer ID provided by the client.
* @node: To attach to the list of xfers on a channel.
* @px: Xfer for PL330 core.
* @chan: Owner channel of this xfer.
*/
struct
s3c_pl330_xfer
{
void
*
token
;
struct
list_head
node
;
struct
pl330_xfer
px
;
struct
s3c_pl330_chan
*
chan
;
};
/**
* struct s3c_pl330_chan - Logical channel to communicate with
* a Physical peripheral.
* @pl330_chan_id: Token of a hardware channel thread of PL330 DMAC.
* NULL if the channel is available to be acquired.
* @id: ID of the peripheral that this channel can communicate with.
* @options: Options specified by the client.
* @sdaddr: Address provided via s3c2410_dma_devconfig.
* @node: To attach to the global list of channels.
* @lrq: Pointer to the last submitted pl330_req to PL330 core.
* @xfer_list: To manage list of xfers enqueued.
* @req: Two requests to communicate with the PL330 engine.
* @callback_fn: Callback function to the client.
* @rqcfg: Channel configuration for the xfers.
* @xfer_head: Pointer to the xfer to be next executed.
* @dmac: Pointer to the DMAC that manages this channel, NULL if the
* channel is available to be acquired.
* @client: Client of this channel. NULL if the
* channel is available to be acquired.
*/
struct
s3c_pl330_chan
{
void
*
pl330_chan_id
;
enum
dma_ch
id
;
unsigned
int
options
;
unsigned
long
sdaddr
;
struct
list_head
node
;
struct
pl330_req
*
lrq
;
struct
list_head
xfer_list
;
struct
pl330_req
req
[
2
];
s3c2410_dma_cbfn_t
callback_fn
;
struct
pl330_reqcfg
rqcfg
;
struct
s3c_pl330_xfer
*
xfer_head
;
struct
s3c_pl330_dmac
*
dmac
;
struct
s3c2410_dma_client
*
client
;
};
/* All DMACs in the platform */
static
LIST_HEAD
(
dmac_list
);
/* All channels to peripherals in the platform */
static
LIST_HEAD
(
chan_list
);
/*
* Since we add resources(DMACs and Channels) to the global pool,
* we need to guard access to the resources using a global lock
*/
static
DEFINE_SPINLOCK
(
res_lock
);
/* Returns the channel with ID 'id' in the chan_list */
static
struct
s3c_pl330_chan
*
id_to_chan
(
const
enum
dma_ch
id
)
{
struct
s3c_pl330_chan
*
ch
;
list_for_each_entry
(
ch
,
&
chan_list
,
node
)
if
(
ch
->
id
==
id
)
return
ch
;
return
NULL
;
}
/* Allocate a new channel with ID 'id' and add to chan_list */
static
void
chan_add
(
const
enum
dma_ch
id
)
{
struct
s3c_pl330_chan
*
ch
=
id_to_chan
(
id
);
/* Return if the channel already exists */
if
(
ch
)
return
;
ch
=
kmalloc
(
sizeof
(
*
ch
),
GFP_KERNEL
);
/* Return silently to work with other channels */
if
(
!
ch
)
return
;
ch
->
id
=
id
;
ch
->
dmac
=
NULL
;
list_add_tail
(
&
ch
->
node
,
&
chan_list
);
}
/* If the channel is not yet acquired by any client */
static
bool
chan_free
(
struct
s3c_pl330_chan
*
ch
)
{
if
(
!
ch
)
return
false
;
/* Channel points to some DMAC only when it's acquired */
return
ch
->
dmac
?
false
:
true
;
}
/*
* Returns 0 is peripheral i/f is invalid or not present on the dmac.
* Index + 1, otherwise.
*/
static
unsigned
iface_of_dmac
(
struct
s3c_pl330_dmac
*
dmac
,
enum
dma_ch
ch_id
)
{
enum
dma_ch
*
id
=
dmac
->
peri
;
int
i
;
/* Discount invalid markers */
if
(
ch_id
==
DMACH_MAX
)
return
0
;
for
(
i
=
0
;
i
<
PL330_MAX_PERI
;
i
++
)
if
(
id
[
i
]
==
ch_id
)
return
i
+
1
;
return
0
;
}
/* If all channel threads of the DMAC are busy */
static
inline
bool
dmac_busy
(
struct
s3c_pl330_dmac
*
dmac
)
{
struct
pl330_info
*
pi
=
dmac
->
pi
;
return
(
dmac
->
busy_chan
<
pi
->
pcfg
.
num_chan
)
?
false
:
true
;
}
/*
* Returns the number of free channels that
* can be handled by this dmac only.
*/
static
unsigned
ch_onlyby_dmac
(
struct
s3c_pl330_dmac
*
dmac
)
{
enum
dma_ch
*
id
=
dmac
->
peri
;
struct
s3c_pl330_dmac
*
d
;
struct
s3c_pl330_chan
*
ch
;
unsigned
found
,
count
=
0
;
enum
dma_ch
p
;
int
i
;
for
(
i
=
0
;
i
<
PL330_MAX_PERI
;
i
++
)
{
p
=
id
[
i
];
ch
=
id_to_chan
(
p
);
if
(
p
==
DMACH_MAX
||
!
chan_free
(
ch
))
continue
;
found
=
0
;
list_for_each_entry
(
d
,
&
dmac_list
,
node
)
{
if
(
d
!=
dmac
&&
iface_of_dmac
(
d
,
ch
->
id
))
{
found
=
1
;
break
;
}
}
if
(
!
found
)
count
++
;
}
return
count
;
}
/*
* Measure of suitability of 'dmac' handling 'ch'
*
* 0 indicates 'dmac' can not handle 'ch' either
* because it is not supported by the hardware or
* because all dmac channels are currently busy.
*
* >0 vlaue indicates 'dmac' has the capability.
* The bigger the value the more suitable the dmac.
*/
#define MAX_SUIT UINT_MAX
#define MIN_SUIT 0
static
unsigned
suitablility
(
struct
s3c_pl330_dmac
*
dmac
,
struct
s3c_pl330_chan
*
ch
)
{
struct
pl330_info
*
pi
=
dmac
->
pi
;
enum
dma_ch
*
id
=
dmac
->
peri
;
struct
s3c_pl330_dmac
*
d
;
unsigned
s
;
int
i
;
s
=
MIN_SUIT
;
/* If all the DMAC channel threads are busy */
if
(
dmac_busy
(
dmac
))
return
s
;
for
(
i
=
0
;
i
<
PL330_MAX_PERI
;
i
++
)
if
(
id
[
i
]
==
ch
->
id
)
break
;
/* If the 'dmac' can't talk to 'ch' */
if
(
i
==
PL330_MAX_PERI
)
return
s
;
s
=
MAX_SUIT
;
list_for_each_entry
(
d
,
&
dmac_list
,
node
)
{
/*
* If some other dmac can talk to this
* peri and has some channel free.
*/
if
(
d
!=
dmac
&&
iface_of_dmac
(
d
,
ch
->
id
)
&&
!
dmac_busy
(
d
))
{
s
=
0
;
break
;
}
}
if
(
s
)
return
s
;
s
=
100
;
/* Good if free chans are more, bad otherwise */
s
+=
(
pi
->
pcfg
.
num_chan
-
dmac
->
busy_chan
)
-
ch_onlyby_dmac
(
dmac
);
return
s
;
}
/* More than one DMAC may have capability to transfer data with the
* peripheral. This function assigns most suitable DMAC to manage the
* channel and hence communicate with the peripheral.
*/
static
struct
s3c_pl330_dmac
*
map_chan_to_dmac
(
struct
s3c_pl330_chan
*
ch
)
{
struct
s3c_pl330_dmac
*
d
,
*
dmac
=
NULL
;
unsigned
sn
,
sl
=
MIN_SUIT
;
list_for_each_entry
(
d
,
&
dmac_list
,
node
)
{
sn
=
suitablility
(
d
,
ch
);
if
(
sn
==
MAX_SUIT
)
return
d
;
if
(
sn
>
sl
)
dmac
=
d
;
}
return
dmac
;
}
/* Acquire the channel for peripheral 'id' */
static
struct
s3c_pl330_chan
*
chan_acquire
(
const
enum
dma_ch
id
)
{
struct
s3c_pl330_chan
*
ch
=
id_to_chan
(
id
);
struct
s3c_pl330_dmac
*
dmac
;
/* If the channel doesn't exist or is already acquired */
if
(
!
ch
||
!
chan_free
(
ch
))
{
ch
=
NULL
;
goto
acq_exit
;
}
dmac
=
map_chan_to_dmac
(
ch
);
/* If couldn't map */
if
(
!
dmac
)
{
ch
=
NULL
;
goto
acq_exit
;
}
dmac
->
busy_chan
++
;
ch
->
dmac
=
dmac
;
acq_exit:
return
ch
;
}
/* Delete xfer from the queue */
static
inline
void
del_from_queue
(
struct
s3c_pl330_xfer
*
xfer
)
{
struct
s3c_pl330_xfer
*
t
;
struct
s3c_pl330_chan
*
ch
;
int
found
;
if
(
!
xfer
)
return
;
ch
=
xfer
->
chan
;
/* Make sure xfer is in the queue */
found
=
0
;
list_for_each_entry
(
t
,
&
ch
->
xfer_list
,
node
)
if
(
t
==
xfer
)
{
found
=
1
;
break
;
}
if
(
!
found
)
return
;
/* If xfer is last entry in the queue */
if
(
xfer
->
node
.
next
==
&
ch
->
xfer_list
)
t
=
list_entry
(
ch
->
xfer_list
.
next
,
struct
s3c_pl330_xfer
,
node
);
else
t
=
list_entry
(
xfer
->
node
.
next
,
struct
s3c_pl330_xfer
,
node
);
/* If there was only one node left */
if
(
t
==
xfer
)
ch
->
xfer_head
=
NULL
;
else
if
(
ch
->
xfer_head
==
xfer
)
ch
->
xfer_head
=
t
;
list_del
(
&
xfer
->
node
);
}
/* Provides pointer to the next xfer in the queue.
* If CIRCULAR option is set, the list is left intact,
* otherwise the xfer is removed from the list.
* Forced delete 'pluck' can be set to override the CIRCULAR option.
*/
static
struct
s3c_pl330_xfer
*
get_from_queue
(
struct
s3c_pl330_chan
*
ch
,
int
pluck
)
{
struct
s3c_pl330_xfer
*
xfer
=
ch
->
xfer_head
;
if
(
!
xfer
)
return
NULL
;
/* If xfer is last entry in the queue */
if
(
xfer
->
node
.
next
==
&
ch
->
xfer_list
)
ch
->
xfer_head
=
list_entry
(
ch
->
xfer_list
.
next
,
struct
s3c_pl330_xfer
,
node
);
else
ch
->
xfer_head
=
list_entry
(
xfer
->
node
.
next
,
struct
s3c_pl330_xfer
,
node
);
if
(
pluck
||
!
(
ch
->
options
&
S3C2410_DMAF_CIRCULAR
))
del_from_queue
(
xfer
);
return
xfer
;
}
static
inline
void
add_to_queue
(
struct
s3c_pl330_chan
*
ch
,
struct
s3c_pl330_xfer
*
xfer
,
int
front
)
{
struct
pl330_xfer
*
xt
;
/* If queue empty */
if
(
ch
->
xfer_head
==
NULL
)
ch
->
xfer_head
=
xfer
;
xt
=
&
ch
->
xfer_head
->
px
;
/* If the head already submitted (CIRCULAR head) */
if
(
ch
->
options
&
S3C2410_DMAF_CIRCULAR
&&
(
xt
==
ch
->
req
[
0
].
x
||
xt
==
ch
->
req
[
1
].
x
))
ch
->
xfer_head
=
xfer
;
/* If this is a resubmission, it should go at the head */
if
(
front
)
{
ch
->
xfer_head
=
xfer
;
list_add
(
&
xfer
->
node
,
&
ch
->
xfer_list
);
}
else
{
list_add_tail
(
&
xfer
->
node
,
&
ch
->
xfer_list
);
}
}
static
inline
void
_finish_off
(
struct
s3c_pl330_xfer
*
xfer
,
enum
s3c2410_dma_buffresult
res
,
int
ffree
)
{
struct
s3c_pl330_chan
*
ch
;
if
(
!
xfer
)
return
;
ch
=
xfer
->
chan
;
/* Do callback */
if
(
ch
->
callback_fn
)
ch
->
callback_fn
(
NULL
,
xfer
->
token
,
xfer
->
px
.
bytes
,
res
);
/* Force Free or if buffer is not needed anymore */
if
(
ffree
||
!
(
ch
->
options
&
S3C2410_DMAF_CIRCULAR
))
kmem_cache_free
(
ch
->
dmac
->
kmcache
,
xfer
);
}
static
inline
int
s3c_pl330_submit
(
struct
s3c_pl330_chan
*
ch
,
struct
pl330_req
*
r
)
{
struct
s3c_pl330_xfer
*
xfer
;
int
ret
=
0
;
/* If already submitted */
if
(
r
->
x
)
return
0
;
xfer
=
get_from_queue
(
ch
,
0
);
if
(
xfer
)
{
r
->
x
=
&
xfer
->
px
;
/* Use max bandwidth for M<->M xfers */
if
(
r
->
rqtype
==
MEMTOMEM
)
{
struct
pl330_info
*
pi
=
xfer
->
chan
->
dmac
->
pi
;
int
burst
=
1
<<
ch
->
rqcfg
.
brst_size
;
u32
bytes
=
r
->
x
->
bytes
;
int
bl
;
bl
=
pi
->
pcfg
.
data_bus_width
/
8
;
bl
*=
pi
->
pcfg
.
data_buf_dep
;
bl
/=
burst
;
/* src/dst_burst_len can't be more than 16 */
if
(
bl
>
16
)
bl
=
16
;
while
(
bl
>
1
)
{
if
(
!
(
bytes
%
(
bl
*
burst
)))
break
;
bl
--
;
}
ch
->
rqcfg
.
brst_len
=
bl
;
}
else
{
ch
->
rqcfg
.
brst_len
=
1
;
}
ret
=
pl330_submit_req
(
ch
->
pl330_chan_id
,
r
);
/* If submission was successful */
if
(
!
ret
)
{
ch
->
lrq
=
r
;
/* latest submitted req */
return
0
;
}
r
->
x
=
NULL
;
/* If both of the PL330 ping-pong buffers filled */
if
(
ret
==
-
EAGAIN
)
{
dev_err
(
ch
->
dmac
->
pi
->
dev
,
"%s:%d!
\n
"
,
__func__
,
__LINE__
);
/* Queue back again */
add_to_queue
(
ch
,
xfer
,
1
);
ret
=
0
;
}
else
{
dev_err
(
ch
->
dmac
->
pi
->
dev
,
"%s:%d!
\n
"
,
__func__
,
__LINE__
);
_finish_off
(
xfer
,
S3C2410_RES_ERR
,
0
);
}
}
return
ret
;
}
static
void
s3c_pl330_rq
(
struct
s3c_pl330_chan
*
ch
,
struct
pl330_req
*
r
,
enum
pl330_op_err
err
)
{
unsigned
long
flags
;
struct
s3c_pl330_xfer
*
xfer
;
struct
pl330_xfer
*
xl
=
r
->
x
;
enum
s3c2410_dma_buffresult
res
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
r
->
x
=
NULL
;
s3c_pl330_submit
(
ch
,
r
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
/* Map result to S3C DMA API */
if
(
err
==
PL330_ERR_NONE
)
res
=
S3C2410_RES_OK
;
else
if
(
err
==
PL330_ERR_ABORT
)
res
=
S3C2410_RES_ABORT
;
else
res
=
S3C2410_RES_ERR
;
/* If last request had some xfer */
if
(
xl
)
{
xfer
=
container_of
(
xl
,
struct
s3c_pl330_xfer
,
px
);
_finish_off
(
xfer
,
res
,
0
);
}
else
{
dev_info
(
ch
->
dmac
->
pi
->
dev
,
"%s:%d No Xfer?!
\n
"
,
__func__
,
__LINE__
);
}
}
static
void
s3c_pl330_rq0
(
void
*
token
,
enum
pl330_op_err
err
)
{
struct
pl330_req
*
r
=
token
;
struct
s3c_pl330_chan
*
ch
=
container_of
(
r
,
struct
s3c_pl330_chan
,
req
[
0
]);
s3c_pl330_rq
(
ch
,
r
,
err
);
}
static
void
s3c_pl330_rq1
(
void
*
token
,
enum
pl330_op_err
err
)
{
struct
pl330_req
*
r
=
token
;
struct
s3c_pl330_chan
*
ch
=
container_of
(
r
,
struct
s3c_pl330_chan
,
req
[
1
]);
s3c_pl330_rq
(
ch
,
r
,
err
);
}
/* Release an acquired channel */
static
void
chan_release
(
struct
s3c_pl330_chan
*
ch
)
{
struct
s3c_pl330_dmac
*
dmac
;
if
(
chan_free
(
ch
))
return
;
dmac
=
ch
->
dmac
;
ch
->
dmac
=
NULL
;
dmac
->
busy_chan
--
;
}
int
s3c2410_dma_ctrl
(
enum
dma_ch
id
,
enum
s3c2410_chan_op
op
)
{
struct
s3c_pl330_xfer
*
xfer
;
enum
pl330_chan_op
pl330op
;
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
idx
,
ret
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
))
{
ret
=
-
EINVAL
;
goto
ctrl_exit
;
}
switch
(
op
)
{
case
S3C2410_DMAOP_START
:
/* Make sure both reqs are enqueued */
idx
=
(
ch
->
lrq
==
&
ch
->
req
[
0
])
?
1
:
0
;
s3c_pl330_submit
(
ch
,
&
ch
->
req
[
idx
]);
s3c_pl330_submit
(
ch
,
&
ch
->
req
[
1
-
idx
]);
pl330op
=
PL330_OP_START
;
break
;
case
S3C2410_DMAOP_STOP
:
pl330op
=
PL330_OP_ABORT
;
break
;
case
S3C2410_DMAOP_FLUSH
:
pl330op
=
PL330_OP_FLUSH
;
break
;
case
S3C2410_DMAOP_PAUSE
:
case
S3C2410_DMAOP_RESUME
:
case
S3C2410_DMAOP_TIMEOUT
:
case
S3C2410_DMAOP_STARTED
:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
0
;
default:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
-
EINVAL
;
}
ret
=
pl330_chan_ctrl
(
ch
->
pl330_chan_id
,
pl330op
);
if
(
pl330op
==
PL330_OP_START
)
{
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
idx
=
(
ch
->
lrq
==
&
ch
->
req
[
0
])
?
1
:
0
;
/* Abort the current xfer */
if
(
ch
->
req
[
idx
].
x
)
{
xfer
=
container_of
(
ch
->
req
[
idx
].
x
,
struct
s3c_pl330_xfer
,
px
);
/* Drop xfer during FLUSH */
if
(
pl330op
==
PL330_OP_FLUSH
)
del_from_queue
(
xfer
);
ch
->
req
[
idx
].
x
=
NULL
;
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
pl330op
==
PL330_OP_FLUSH
?
1
:
0
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
}
/* Flush the whole queue */
if
(
pl330op
==
PL330_OP_FLUSH
)
{
if
(
ch
->
req
[
1
-
idx
].
x
)
{
xfer
=
container_of
(
ch
->
req
[
1
-
idx
].
x
,
struct
s3c_pl330_xfer
,
px
);
del_from_queue
(
xfer
);
ch
->
req
[
1
-
idx
].
x
=
NULL
;
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
1
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
}
/* Finish off the remaining in the queue */
xfer
=
ch
->
xfer_head
;
while
(
xfer
)
{
del_from_queue
(
xfer
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
1
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
xfer
=
ch
->
xfer_head
;
}
}
ctrl_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_ctrl
);
int
s3c2410_dma_enqueue
(
enum
dma_ch
id
,
void
*
token
,
dma_addr_t
addr
,
int
size
)
{
struct
s3c_pl330_chan
*
ch
;
struct
s3c_pl330_xfer
*
xfer
;
unsigned
long
flags
;
int
idx
,
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
/* Error if invalid or free channel */
if
(
!
ch
||
chan_free
(
ch
))
{
ret
=
-
EINVAL
;
goto
enq_exit
;
}
/* Error if size is unaligned */
if
(
ch
->
rqcfg
.
brst_size
&&
size
%
(
1
<<
ch
->
rqcfg
.
brst_size
))
{
ret
=
-
EINVAL
;
goto
enq_exit
;
}
xfer
=
kmem_cache_alloc
(
ch
->
dmac
->
kmcache
,
GFP_ATOMIC
);
if
(
!
xfer
)
{
ret
=
-
ENOMEM
;
goto
enq_exit
;
}
xfer
->
token
=
token
;
xfer
->
chan
=
ch
;
xfer
->
px
.
bytes
=
size
;
xfer
->
px
.
next
=
NULL
;
/* Single request */
/* For S3C DMA API, direction is always fixed for all xfers */
if
(
ch
->
req
[
0
].
rqtype
==
MEMTODEV
)
{
xfer
->
px
.
src_addr
=
addr
;
xfer
->
px
.
dst_addr
=
ch
->
sdaddr
;
}
else
{
xfer
->
px
.
src_addr
=
ch
->
sdaddr
;
xfer
->
px
.
dst_addr
=
addr
;
}
add_to_queue
(
ch
,
xfer
,
0
);
/* Try submitting on either request */
idx
=
(
ch
->
lrq
==
&
ch
->
req
[
0
])
?
1
:
0
;
if
(
!
ch
->
req
[
idx
].
x
)
s3c_pl330_submit
(
ch
,
&
ch
->
req
[
idx
]);
else
s3c_pl330_submit
(
ch
,
&
ch
->
req
[
1
-
idx
]);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
if
(
ch
->
options
&
S3C2410_DMAF_AUTOSTART
)
s3c2410_dma_ctrl
(
id
,
S3C2410_DMAOP_START
);
return
0
;
enq_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_enqueue
);
int
s3c2410_dma_request
(
enum
dma_ch
id
,
struct
s3c2410_dma_client
*
client
,
void
*
dev
)
{
struct
s3c_pl330_dmac
*
dmac
;
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
chan_acquire
(
id
);
if
(
!
ch
)
{
ret
=
-
EBUSY
;
goto
req_exit
;
}
dmac
=
ch
->
dmac
;
ch
->
pl330_chan_id
=
pl330_request_channel
(
dmac
->
pi
);
if
(
!
ch
->
pl330_chan_id
)
{
chan_release
(
ch
);
ret
=
-
EBUSY
;
goto
req_exit
;
}
ch
->
client
=
client
;
ch
->
options
=
0
;
/* Clear any option */
ch
->
callback_fn
=
NULL
;
/* Clear any callback */
ch
->
lrq
=
NULL
;
ch
->
rqcfg
.
brst_size
=
2
;
/* Default word size */
ch
->
rqcfg
.
swap
=
SWAP_NO
;
ch
->
rqcfg
.
scctl
=
SCCTRL0
;
/* Noncacheable and nonbufferable */
ch
->
rqcfg
.
dcctl
=
DCCTRL0
;
/* Noncacheable and nonbufferable */
ch
->
rqcfg
.
privileged
=
0
;
ch
->
rqcfg
.
insnaccess
=
0
;
/* Set invalid direction */
ch
->
req
[
0
].
rqtype
=
DEVTODEV
;
ch
->
req
[
1
].
rqtype
=
ch
->
req
[
0
].
rqtype
;
ch
->
req
[
0
].
cfg
=
&
ch
->
rqcfg
;
ch
->
req
[
1
].
cfg
=
ch
->
req
[
0
].
cfg
;
ch
->
req
[
0
].
peri
=
iface_of_dmac
(
dmac
,
id
)
-
1
;
/* Original index */
ch
->
req
[
1
].
peri
=
ch
->
req
[
0
].
peri
;
ch
->
req
[
0
].
token
=
&
ch
->
req
[
0
];
ch
->
req
[
0
].
xfer_cb
=
s3c_pl330_rq0
;
ch
->
req
[
1
].
token
=
&
ch
->
req
[
1
];
ch
->
req
[
1
].
xfer_cb
=
s3c_pl330_rq1
;
ch
->
req
[
0
].
x
=
NULL
;
ch
->
req
[
1
].
x
=
NULL
;
/* Reset xfer list */
INIT_LIST_HEAD
(
&
ch
->
xfer_list
);
ch
->
xfer_head
=
NULL
;
req_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_request
);
int
s3c2410_dma_free
(
enum
dma_ch
id
,
struct
s3c2410_dma_client
*
client
)
{
struct
s3c_pl330_chan
*
ch
;
struct
s3c_pl330_xfer
*
xfer
;
unsigned
long
flags
;
int
ret
=
0
;
unsigned
idx
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
))
goto
free_exit
;
/* Refuse if someone else wanted to free the channel */
if
(
ch
->
client
!=
client
)
{
ret
=
-
EBUSY
;
goto
free_exit
;
}
/* Stop any active xfer, Flushe the queue and do callbacks */
pl330_chan_ctrl
(
ch
->
pl330_chan_id
,
PL330_OP_FLUSH
);
/* Abort the submitted requests */
idx
=
(
ch
->
lrq
==
&
ch
->
req
[
0
])
?
1
:
0
;
if
(
ch
->
req
[
idx
].
x
)
{
xfer
=
container_of
(
ch
->
req
[
idx
].
x
,
struct
s3c_pl330_xfer
,
px
);
ch
->
req
[
idx
].
x
=
NULL
;
del_from_queue
(
xfer
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
1
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
}
if
(
ch
->
req
[
1
-
idx
].
x
)
{
xfer
=
container_of
(
ch
->
req
[
1
-
idx
].
x
,
struct
s3c_pl330_xfer
,
px
);
ch
->
req
[
1
-
idx
].
x
=
NULL
;
del_from_queue
(
xfer
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
1
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
}
/* Pluck and Abort the queued requests in order */
do
{
xfer
=
get_from_queue
(
ch
,
1
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
_finish_off
(
xfer
,
S3C2410_RES_ABORT
,
1
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
}
while
(
xfer
);
ch
->
client
=
NULL
;
pl330_release_channel
(
ch
->
pl330_chan_id
);
ch
->
pl330_chan_id
=
NULL
;
chan_release
(
ch
);
free_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_free
);
int
s3c2410_dma_config
(
enum
dma_ch
id
,
int
xferunit
)
{
struct
s3c_pl330_chan
*
ch
;
struct
pl330_info
*
pi
;
unsigned
long
flags
;
int
i
,
dbwidth
,
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
))
{
ret
=
-
EINVAL
;
goto
cfg_exit
;
}
pi
=
ch
->
dmac
->
pi
;
dbwidth
=
pi
->
pcfg
.
data_bus_width
/
8
;
/* Max size of xfer can be pcfg.data_bus_width */
if
(
xferunit
>
dbwidth
)
{
ret
=
-
EINVAL
;
goto
cfg_exit
;
}
i
=
0
;
while
(
xferunit
!=
(
1
<<
i
))
i
++
;
/* If valid value */
if
(
xferunit
==
(
1
<<
i
))
ch
->
rqcfg
.
brst_size
=
i
;
else
ret
=
-
EINVAL
;
cfg_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_config
);
/* Options that are supported by this driver */
#define S3C_PL330_FLAGS (S3C2410_DMAF_CIRCULAR | S3C2410_DMAF_AUTOSTART)
int
s3c2410_dma_setflags
(
enum
dma_ch
id
,
unsigned
int
options
)
{
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
)
||
options
&
~
(
S3C_PL330_FLAGS
))
ret
=
-
EINVAL
;
else
ch
->
options
=
options
;
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
s3c2410_dma_setflags
);
int
s3c2410_dma_set_buffdone_fn
(
enum
dma_ch
id
,
s3c2410_dma_cbfn_t
rtn
)
{
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
))
ret
=
-
EINVAL
;
else
ch
->
callback_fn
=
rtn
;
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_set_buffdone_fn
);
int
s3c2410_dma_devconfig
(
enum
dma_ch
id
,
enum
s3c2410_dmasrc
source
,
unsigned
long
address
)
{
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
ret
=
0
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
ch
=
id_to_chan
(
id
);
if
(
!
ch
||
chan_free
(
ch
))
{
ret
=
-
EINVAL
;
goto
devcfg_exit
;
}
switch
(
source
)
{
case
S3C2410_DMASRC_HW
:
/* P->M */
ch
->
req
[
0
].
rqtype
=
DEVTOMEM
;
ch
->
req
[
1
].
rqtype
=
DEVTOMEM
;
ch
->
rqcfg
.
src_inc
=
0
;
ch
->
rqcfg
.
dst_inc
=
1
;
break
;
case
S3C2410_DMASRC_MEM
:
/* M->P */
ch
->
req
[
0
].
rqtype
=
MEMTODEV
;
ch
->
req
[
1
].
rqtype
=
MEMTODEV
;
ch
->
rqcfg
.
src_inc
=
1
;
ch
->
rqcfg
.
dst_inc
=
0
;
break
;
default:
ret
=
-
EINVAL
;
goto
devcfg_exit
;
}
ch
->
sdaddr
=
address
;
devcfg_exit:
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
s3c2410_dma_devconfig
);
int
s3c2410_dma_getposition
(
enum
dma_ch
id
,
dma_addr_t
*
src
,
dma_addr_t
*
dst
)
{
struct
s3c_pl330_chan
*
ch
=
id_to_chan
(
id
);
struct
pl330_chanstatus
status
;
int
ret
;
if
(
!
ch
||
chan_free
(
ch
))
return
-
EINVAL
;
ret
=
pl330_chan_status
(
ch
->
pl330_chan_id
,
&
status
);
if
(
ret
<
0
)
return
ret
;
*
src
=
status
.
src_addr
;
*
dst
=
status
.
dst_addr
;
return
0
;
}
EXPORT_SYMBOL
(
s3c2410_dma_getposition
);
static
irqreturn_t
pl330_irq_handler
(
int
irq
,
void
*
data
)
{
if
(
pl330_update
(
data
))
return
IRQ_HANDLED
;
else
return
IRQ_NONE
;
}
static
int
pl330_probe
(
struct
platform_device
*
pdev
)
{
struct
s3c_pl330_dmac
*
s3c_pl330_dmac
;
struct
s3c_pl330_platdata
*
pl330pd
;
struct
pl330_info
*
pl330_info
;
struct
resource
*
res
;
int
i
,
ret
,
irq
;
pl330pd
=
pdev
->
dev
.
platform_data
;
/* Can't do without the list of _32_ peripherals */
if
(
!
pl330pd
||
!
pl330pd
->
peri
)
{
dev_err
(
&
pdev
->
dev
,
"platform data missing!
\n
"
);
return
-
ENODEV
;
}
pl330_info
=
kzalloc
(
sizeof
(
*
pl330_info
),
GFP_KERNEL
);
if
(
!
pl330_info
)
return
-
ENOMEM
;
pl330_info
->
pl330_data
=
NULL
;
pl330_info
->
dev
=
&
pdev
->
dev
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
ret
=
-
ENODEV
;
goto
probe_err1
;
}
request_mem_region
(
res
->
start
,
resource_size
(
res
),
pdev
->
name
);
pl330_info
->
base
=
ioremap
(
res
->
start
,
resource_size
(
res
));
if
(
!
pl330_info
->
base
)
{
ret
=
-
ENXIO
;
goto
probe_err2
;
}
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
ret
=
irq
;
goto
probe_err3
;
}
ret
=
request_irq
(
irq
,
pl330_irq_handler
,
0
,
dev_name
(
&
pdev
->
dev
),
pl330_info
);
if
(
ret
)
goto
probe_err4
;
/* Allocate a new DMAC */
s3c_pl330_dmac
=
kmalloc
(
sizeof
(
*
s3c_pl330_dmac
),
GFP_KERNEL
);
if
(
!
s3c_pl330_dmac
)
{
ret
=
-
ENOMEM
;
goto
probe_err5
;
}
/* Get operation clock and enable it */
s3c_pl330_dmac
->
clk
=
clk_get
(
&
pdev
->
dev
,
"pdma"
);
if
(
IS_ERR
(
s3c_pl330_dmac
->
clk
))
{
dev_err
(
&
pdev
->
dev
,
"Cannot get operation clock.
\n
"
);
ret
=
-
EINVAL
;
goto
probe_err6
;
}
clk_enable
(
s3c_pl330_dmac
->
clk
);
ret
=
pl330_add
(
pl330_info
);
if
(
ret
)
goto
probe_err7
;
/* Hook the info */
s3c_pl330_dmac
->
pi
=
pl330_info
;
/* No busy channels */
s3c_pl330_dmac
->
busy_chan
=
0
;
s3c_pl330_dmac
->
kmcache
=
kmem_cache_create
(
dev_name
(
&
pdev
->
dev
),
sizeof
(
struct
s3c_pl330_xfer
),
0
,
0
,
NULL
);
if
(
!
s3c_pl330_dmac
->
kmcache
)
{
ret
=
-
ENOMEM
;
goto
probe_err8
;
}
/* Get the list of peripherals */
s3c_pl330_dmac
->
peri
=
pl330pd
->
peri
;
/* Attach to the list of DMACs */
list_add_tail
(
&
s3c_pl330_dmac
->
node
,
&
dmac_list
);
/* Create a channel for each peripheral in the DMAC
* that is, if it doesn't already exist
*/
for
(
i
=
0
;
i
<
PL330_MAX_PERI
;
i
++
)
if
(
s3c_pl330_dmac
->
peri
[
i
]
!=
DMACH_MAX
)
chan_add
(
s3c_pl330_dmac
->
peri
[
i
]);
printk
(
KERN_INFO
"Loaded driver for PL330 DMAC-%d %s
\n
"
,
pdev
->
id
,
pdev
->
name
);
printk
(
KERN_INFO
"
\t
DBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u
\n
"
,
pl330_info
->
pcfg
.
data_buf_dep
,
pl330_info
->
pcfg
.
data_bus_width
/
8
,
pl330_info
->
pcfg
.
num_chan
,
pl330_info
->
pcfg
.
num_peri
,
pl330_info
->
pcfg
.
num_events
);
return
0
;
probe_err8:
pl330_del
(
pl330_info
);
probe_err7:
clk_disable
(
s3c_pl330_dmac
->
clk
);
clk_put
(
s3c_pl330_dmac
->
clk
);
probe_err6:
kfree
(
s3c_pl330_dmac
);
probe_err5:
free_irq
(
irq
,
pl330_info
);
probe_err4:
probe_err3:
iounmap
(
pl330_info
->
base
);
probe_err2:
release_mem_region
(
res
->
start
,
resource_size
(
res
));
probe_err1:
kfree
(
pl330_info
);
return
ret
;
}
static
int
pl330_remove
(
struct
platform_device
*
pdev
)
{
struct
s3c_pl330_dmac
*
dmac
,
*
d
;
struct
s3c_pl330_chan
*
ch
;
unsigned
long
flags
;
int
del
,
found
;
if
(
!
pdev
->
dev
.
platform_data
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
res_lock
,
flags
);
found
=
0
;
list_for_each_entry
(
d
,
&
dmac_list
,
node
)
if
(
d
->
pi
->
dev
==
&
pdev
->
dev
)
{
found
=
1
;
break
;
}
if
(
!
found
)
{
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
0
;
}
dmac
=
d
;
/* Remove all Channels that are managed only by this DMAC */
list_for_each_entry
(
ch
,
&
chan_list
,
node
)
{
/* Only channels that are handled by this DMAC */
if
(
iface_of_dmac
(
dmac
,
ch
->
id
))
del
=
1
;
else
continue
;
/* Don't remove if some other DMAC has it too */
list_for_each_entry
(
d
,
&
dmac_list
,
node
)
if
(
d
!=
dmac
&&
iface_of_dmac
(
d
,
ch
->
id
))
{
del
=
0
;
break
;
}
if
(
del
)
{
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
s3c2410_dma_free
(
ch
->
id
,
ch
->
client
);
spin_lock_irqsave
(
&
res_lock
,
flags
);
list_del
(
&
ch
->
node
);
kfree
(
ch
);
}
}
/* Disable operation clock */
clk_disable
(
dmac
->
clk
);
clk_put
(
dmac
->
clk
);
/* Remove the DMAC */
list_del
(
&
dmac
->
node
);
kfree
(
dmac
);
spin_unlock_irqrestore
(
&
res_lock
,
flags
);
return
0
;
}
static
struct
platform_driver
pl330_driver
=
{
.
driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"s3c-pl330"
,
},
.
probe
=
pl330_probe
,
.
remove
=
pl330_remove
,
};
static
int
__init
pl330_init
(
void
)
{
return
platform_driver_register
(
&
pl330_driver
);
}
module_init
(
pl330_init
);
static
void
__exit
pl330_exit
(
void
)
{
platform_driver_unregister
(
&
pl330_driver
);
return
;
}
module_exit
(
pl330_exit
);
MODULE_AUTHOR
(
"Jaswinder Singh <jassi.brar@samsung.com>"
);
MODULE_DESCRIPTION
(
"Driver for PL330 DMA Controller"
);
MODULE_LICENSE
(
"GPL"
);
drivers/dma/Kconfig
浏览文件 @
0745c9a5
...
...
@@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
config PL330_DMA
tristate "DMA API Driver for PL330"
select DMA_ENGINE
depends on PL330
depends on ARM_AMBA
select PL330
help
Select if your platform has one or more PL330 DMACs.
You need to provide platform specific settings via
...
...
drivers/dma/pl330.c
浏览文件 @
0745c9a5
...
...
@@ -17,6 +17,8 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl330.h>
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#define NR_DEFAULT_DESC 16
...
...
@@ -68,6 +70,14 @@ struct dma_pl330_chan {
* NULL if the channel is available to be acquired.
*/
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
{
...
...
@@ -83,6 +93,8 @@ struct dma_pl330_dmac {
/* Peripheral channels connected to this DMAC */
struct
dma_pl330_chan
*
peripherals
;
/* keep at end */
struct
clk
*
clk
;
};
struct
dma_pl330_desc
{
...
...
@@ -152,6 +164,31 @@ static inline void free_desc_list(struct list_head *list)
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
)
{
struct
dma_pl330_desc
*
desc
;
...
...
@@ -205,7 +242,10 @@ static void pl330_tasklet(unsigned long data)
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
)
...
...
@@ -236,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave
(
&
pch
->
lock
,
flags
);
pch
->
completed
=
chan
->
cookie
=
1
;
pch
->
cyclic
=
false
;
pch
->
pl330_chid
=
pl330_request_channel
(
&
pdmac
->
pif
);
if
(
!
pch
->
pl330_chid
)
{
...
...
@@ -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
)
{
struct
dma_pl330_chan
*
pch
=
to_pchan
(
chan
);
struct
dma_pl330_desc
*
desc
;
struct
dma_pl330_desc
*
desc
,
*
_dt
;
unsigned
long
flags
;
struct
dma_pl330_dmac
*
pdmac
=
pch
->
dmac
;
struct
dma_slave_config
*
slave_config
;
LIST_HEAD
(
list
);
/* Only supports DMA_TERMINATE_ALL */
if
(
cmd
!=
DMA_TERMINATE_ALL
)
return
-
ENXIO
;
spin_lock_irqsave
(
&
pch
->
lock
,
flags
);
/* FLUSH the PL330 Channel thread */
pl330_chan_ctrl
(
pch
->
pl330_chid
,
PL330_OP_FLUSH
);
switch
(
cmd
)
{
case
DMA_TERMINATE_ALL
:
spin_lock_irqsave
(
&
pch
->
lock
,
flags
);
/* Mark all desc done */
list_for_each_entry
(
desc
,
&
pch
->
work_list
,
node
)
desc
->
status
=
DONE
;
/* FLUSH the PL330 Channel thread */
pl330_chan_ctrl
(
pch
->
pl330_chid
,
PL330_OP_FLUSH
);
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
;
}
...
...
@@ -288,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
pl330_release_channel
(
pch
->
pl330_chid
);
pch
->
pl330_chid
=
NULL
;
if
(
pch
->
cyclic
)
list_splice_tail_init
(
&
pch
->
work_list
,
&
pch
->
dmac
->
desc_pool
);
spin_unlock_irqrestore
(
&
pch
->
lock
,
flags
);
}
...
...
@@ -453,7 +524,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
if
(
peri
)
{
desc
->
req
.
rqtype
=
peri
->
rqtype
;
desc
->
req
.
peri
=
p
eri
->
peri
_id
;
desc
->
req
.
peri
=
p
ch
->
chan
.
chan
_id
;
}
else
{
desc
->
req
.
rqtype
=
MEMTOMEM
;
desc
->
req
.
peri
=
0
;
...
...
@@ -524,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t 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
*
pl330_prep_dma_memcpy
(
struct
dma_chan
*
chan
,
dma_addr_t
dst
,
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,
struct
dma_pl330_peri
*
peri
=
chan
->
private
;
struct
scatterlist
*
sg
;
unsigned
long
flags
;
int
i
,
burst_size
;
int
i
;
dma_addr_t
addr
;
if
(
unlikely
(
!
pch
||
!
sgl
||
!
sg_len
||
!
peri
))
...
...
@@ -595,8 +711,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return
NULL
;
}
addr
=
peri
->
fifo_addr
;
burst_size
=
peri
->
burst_sz
;
addr
=
pch
->
fifo_addr
;
first
=
NULL
;
...
...
@@ -644,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
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
;
}
...
...
@@ -696,6 +811,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
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
];
ret
=
request_irq
(
irq
,
pl330_irq_handler
,
0
,
dev_name
(
&
adev
->
dev
),
pi
);
...
...
@@ -732,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
case
MEMTODEV
:
case
DEVTOMEM
:
dma_cap_set
(
DMA_SLAVE
,
pd
->
cap_mask
);
dma_cap_set
(
DMA_CYCLIC
,
pd
->
cap_mask
);
break
;
default:
dev_err
(
&
adev
->
dev
,
"DEVTODEV Not Supported
\n
"
);
...
...
@@ -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_free_chan_resources
=
pl330_free_chan_resources
;
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_prep_slave_sg
=
pl330_prep_slave_sg
;
pd
->
device_control
=
pl330_control
;
...
...
@@ -769,8 +910,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
goto
probe_err4
;
}
amba_set_drvdata
(
adev
,
pdmac
);
dev_info
(
&
adev
->
dev
,
"Loaded driver for PL330 DMAC-%d
\n
"
,
adev
->
periphid
);
dev_info
(
&
adev
->
dev
,
...
...
@@ -831,6 +970,13 @@ static int __devexit pl330_remove(struct amba_device *adev)
res
=
&
adev
->
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
);
return
0
;
...
...
@@ -844,10 +990,49 @@ static struct amba_id pl330_ids[] = {
{
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
=
{
.
drv
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"dma-pl330"
,
.
pm
=
&
pl330_pm_ops
,
},
.
id_table
=
pl330_ids
,
.
probe
=
pl330_probe
,
...
...
drivers/mmc/host/s3cmci.c
浏览文件 @
0745c9a5
...
...
@@ -913,9 +913,9 @@ static void finalize_request(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
;
if
(
last_source
==
source
)
...
...
@@ -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
);
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
);
dma_len
=
dma_map_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
...
...
drivers/spi/spi-s3c64xx.c
浏览文件 @
0745c9a5
...
...
@@ -131,6 +131,12 @@
#define RXBUSY (1<<2)
#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.
* @clk: Pointer to the spi clock.
...
...
@@ -164,13 +170,14 @@ struct s3c64xx_spi_driver_data {
struct
work_struct
work
;
struct
list_head
queue
;
spinlock_t
lock
;
enum
dma_ch
rx_dmach
;
enum
dma_ch
tx_dmach
;
unsigned
long
sfr_start
;
struct
completion
xfer_completion
;
unsigned
state
;
unsigned
cur_mode
,
cur_bpw
;
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
=
{
...
...
@@ -226,6 +233,78 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
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
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
,
int
dma_mode
)
...
...
@@ -258,10 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg
|=
S3C64XX_SPI_CH_TXCH_ON
;
if
(
dma_mode
)
{
modecfg
|=
S3C64XX_SPI_MODE_TXDMA_ON
;
s3c2410_dma_config
(
sdd
->
tx_dmach
,
sdd
->
cur_bpw
/
8
);
s3c2410_dma_enqueue
(
sdd
->
tx_dmach
,
(
void
*
)
sdd
,
xfer
->
tx_dma
,
xfer
->
len
);
s3c2410_dma_ctrl
(
sdd
->
tx_dmach
,
S3C2410_DMAOP_START
);
prepare_dma
(
&
sdd
->
tx_dma
,
xfer
->
len
,
xfer
->
tx_dma
);
}
else
{
switch
(
sdd
->
cur_bpw
)
{
case
32
:
...
...
@@ -293,10 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel
(((
xfer
->
len
*
8
/
sdd
->
cur_bpw
)
&
0xffff
)
|
S3C64XX_SPI_PACKET_CNT_EN
,
regs
+
S3C64XX_SPI_PACKET_CNT
);
s3c2410_dma_config
(
sdd
->
rx_dmach
,
sdd
->
cur_bpw
/
8
);
s3c2410_dma_enqueue
(
sdd
->
rx_dmach
,
(
void
*
)
sdd
,
xfer
->
rx_dma
,
xfer
->
len
);
s3c2410_dma_ctrl
(
sdd
->
rx_dmach
,
S3C2410_DMAOP_START
);
prepare_dma
(
&
sdd
->
rx_dma
,
xfer
->
len
,
xfer
->
rx_dma
);
}
}
...
...
@@ -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)
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,
if
(
use_dma
)
{
if
(
xfer
->
tx_buf
!=
NULL
&&
(
sdd
->
state
&
TXBUSY
))
s3c2410_dma_ctrl
(
sdd
->
tx_dmach
,
S3C2410_DMAOP_FLUSH
);
sdd
->
ops
->
stop
(
sdd
->
tx_dma
.
ch
);
if
(
xfer
->
rx_buf
!=
NULL
&&
(
sdd
->
state
&
RXBUSY
))
s3c2410_dma_ctrl
(
sdd
->
rx_dmach
,
S3C2410_DMAOP_FLUSH
);
sdd
->
ops
->
stop
(
sdd
->
rx_dma
.
ch
);
}
goto
out
;
...
...
@@ -739,30 +770,6 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
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
)
{
struct
s3c64xx_spi_driver_data
*
sdd
=
container_of
(
work
,
...
...
@@ -799,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
spin_unlock_irqrestore
(
&
sdd
->
lock
,
flags
);
/* Free DMA channels */
s
3c2410_dma_free
(
sdd
->
tx_dma
ch
,
&
s3c64xx_spi_dma_client
);
s
3c2410_dma_free
(
sdd
->
rx_dma
ch
,
&
s3c64xx_spi_dma_client
);
s
dd
->
ops
->
release
(
sdd
->
rx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
s
dd
->
ops
->
release
(
sdd
->
tx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
}
static
int
s3c64xx_spi_transfer
(
struct
spi_device
*
spi
,
...
...
@@ -1017,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
sdd
->
cntrlr_info
=
sci
;
sdd
->
pdev
=
pdev
;
sdd
->
sfr_start
=
mem_res
->
start
;
sdd
->
tx_dmach
=
dmatx_res
->
start
;
sdd
->
rx_dmach
=
dmarx_res
->
start
;
sdd
->
tx_dma
.
dmach
=
dmatx_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
;
...
...
@@ -1106,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
pdev
->
id
,
master
->
num_chipselect
);
dev_dbg
(
&
pdev
->
dev
,
"
\t
IOmem=[0x%x-0x%x]
\t
DMA=[Rx-%d, Tx-%d]
\n
"
,
mem_res
->
end
,
mem_res
->
start
,
sdd
->
rx_dma
ch
,
sdd
->
tx_
dmach
);
sdd
->
rx_dma
.
dmach
,
sdd
->
tx_dma
.
dmach
);
return
0
;
...
...
include/linux/amba/pl330.h
浏览文件 @
0745c9a5
...
...
@@ -19,12 +19,8 @@ struct dma_pl330_peri {
* Peri_Req i/f of the DMAC that is
* peripheral could be reached from.
*/
u8
peri_id
;
/*
{0, 31}
*/
u8
peri_id
;
/*
specific dma id
*/
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
{
...
...
sound/soc/samsung/ac97.c
浏览文件 @
0745c9a5
...
...
@@ -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
);
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
;
}
...
...
@@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
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
;
}
...
...
sound/soc/samsung/dma.c
浏览文件 @
0745c9a5
...
...
@@ -54,7 +54,6 @@ struct runtime_data {
spinlock_t
lock
;
int
state
;
unsigned
int
dma_loaded
;
unsigned
int
dma_limit
;
unsigned
int
dma_period
;
dma_addr_t
dma_start
;
dma_addr_t
dma_pos
;
...
...
@@ -62,77 +61,79 @@ struct runtime_data {
struct
s3c_dma_params
*
params
;
};
static
void
audio_buffdone
(
void
*
data
);
/* dma_enqueue
*
* place a dma buffer onto the queue for the dma system
* to handle.
*/
*/
static
void
dma_enqueue
(
struct
snd_pcm_substream
*
substream
)
{
struct
runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
dma_addr_t
pos
=
prtd
->
dma_pos
;
unsigned
int
limit
;
int
ret
;
struct
samsung_dma_prep_info
dma_info
;
pr_debug
(
"Entered %s
\n
"
,
__func__
);
if
(
s3c_dma_has_circular
())
limit
=
(
prtd
->
dma_end
-
prtd
->
dma_start
)
/
prtd
->
dma_period
;
else
limit
=
prtd
->
dma_limit
;
limit
=
(
prtd
->
dma_end
-
prtd
->
dma_start
)
/
prtd
->
dma_period
;
pr_debug
(
"%s: loaded %d, limit %d
\n
"
,
__func__
,
prtd
->
dma_loaded
,
limit
);
while
(
prtd
->
dma_loaded
<
limit
)
{
unsigned
long
len
=
prtd
->
dma_period
;
dma_info
.
cap
=
(
samsung_dma_has_circular
()
?
DMA_CYCLIC
:
DMA_SLAVE
);
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
);
if
((
pos
+
len
)
>
prtd
->
dma_end
)
{
len
=
prtd
->
dma_end
-
pos
;
pr_debug
(
"%s: corrected dma len %ld
\n
"
,
__func__
,
len
);
if
((
pos
+
dma_info
.
period
)
>
prtd
->
dma_end
)
{
dma_info
.
period
=
prtd
->
dma_end
-
pos
;
pr_debug
(
"%s: corrected dma len %ld
\n
"
,
__func__
,
dma_info
.
period
);
}
ret
=
s3c2410_dma_enqueue
(
prtd
->
params
->
channel
,
substream
,
pos
,
len
);
dma_info
.
buf
=
pos
;
prtd
->
params
->
ops
->
prepare
(
prtd
->
params
->
ch
,
&
dma_info
);
if
(
ret
==
0
)
{
prtd
->
dma_loaded
++
;
pos
+=
prtd
->
dma_period
;
if
(
pos
>=
prtd
->
dma_end
)
pos
=
prtd
->
dma_start
;
}
else
break
;
prtd
->
dma_loaded
++
;
pos
+=
prtd
->
dma_period
;
if
(
pos
>=
prtd
->
dma_end
)
pos
=
prtd
->
dma_start
;
}
prtd
->
dma_pos
=
pos
;
}
static
void
audio_buffdone
(
struct
s3c2410_dma_chan
*
channel
,
void
*
dev_id
,
int
size
,
enum
s3c2410_dma_buffresult
result
)
static
void
audio_buffdone
(
void
*
data
)
{
struct
snd_pcm_substream
*
substream
=
d
ev_id
;
struct
runtime_data
*
prtd
;
struct
snd_pcm_substream
*
substream
=
d
ata
;
struct
runtime_data
*
prtd
=
substream
->
runtime
->
private_data
;
pr_debug
(
"Entered %s
\n
"
,
__func__
);
if
(
result
==
S3C2410_RES_ABORT
||
result
==
S3C2410_RES_ERR
)
return
;
prtd
=
substream
->
runtime
->
private_data
;
if
(
prtd
->
state
&
ST_RUNNING
)
{
prtd
->
dma_pos
+=
prtd
->
dma_period
;
if
(
prtd
->
dma_pos
>=
prtd
->
dma_end
)
prtd
->
dma_pos
=
prtd
->
dma_start
;
if
(
substream
)
snd_pcm_period_elapsed
(
substream
);
if
(
substream
)
snd_pcm_period_elapsed
(
substream
);
spin_lock
(
&
prtd
->
lock
);
if
(
prtd
->
state
&
ST_RUNNING
&&
!
s3c_dma_has_circular
())
{
prtd
->
dma_loaded
--
;
dma_enqueue
(
substream
);
spin_lock
(
&
prtd
->
lock
);
if
(
!
samsung_dma_has_circular
())
{
prtd
->
dma_loaded
--
;
dma_enqueue
(
substream
);
}
spin_unlock
(
&
prtd
->
lock
);
}
spin_unlock
(
&
prtd
->
lock
);
}
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
);
struct
s3c_dma_params
*
dma
=
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__
);
...
...
@@ -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
,
prtd
->
params
->
client
,
prtd
->
params
->
channel
);
ret
=
s3c2410_dma_request
(
prtd
->
params
->
channel
,
prtd
->
params
->
client
,
NULL
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"failed to get dma channel
\n
"
)
;
return
ret
;
}
/* use the circular buffering if we have it available. */
if
(
s3c_dma_has_circular
())
s3c2410_dma_setflags
(
prtd
->
params
->
channel
,
S3C2410_DMAF_CIRCULAR
);
prtd
->
params
->
ops
=
samsung_dma_get_ops
();
dma_info
.
cap
=
(
samsung_dma_has_circular
()
?
DMA_CYCLIC
:
DMA_SLAVE
);
dma_info
.
client
=
prtd
->
params
->
client
;
dma_info
.
direction
=
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
dma_info
.
width
=
prtd
->
params
->
dma_size
;
dma_info
.
fifo
=
prtd
->
params
->
dma_addr
;
prtd
->
params
->
ch
=
prtd
->
params
->
ops
->
request
(
prtd
->
params
->
channel
,
&
dma_info
);
}
s3c2410_dma_set_buffdone_fn
(
prtd
->
params
->
channel
,
audio_buffdone
);
snd_pcm_set_runtime_buffer
(
substream
,
&
substream
->
dma_buffer
);
runtime
->
dma_bytes
=
totbytes
;
spin_lock_irq
(
&
prtd
->
lock
);
prtd
->
dma_loaded
=
0
;
prtd
->
dma_limit
=
runtime
->
hw
.
periods_min
;
prtd
->
dma_period
=
params_period_bytes
(
params
);
prtd
->
dma_start
=
runtime
->
dma_addr
;
prtd
->
dma_pos
=
prtd
->
dma_start
;
...
...
@@ -206,7 +202,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream)
snd_pcm_set_runtime_buffer
(
substream
,
NULL
);
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
;
}
...
...
@@ -225,23 +222,9 @@ static int dma_prepare(struct snd_pcm_substream *substream)
if
(
!
prtd
->
params
)
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 */
s3c2410_dma_ctrl
(
prtd
->
params
->
channel
,
S3C2410_DMAOP_FLUSH
);
prtd
->
params
->
ops
->
flush
(
prtd
->
params
->
ch
);
prtd
->
dma_loaded
=
0
;
prtd
->
dma_pos
=
prtd
->
dma_start
;
...
...
@@ -265,14 +248,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
case
SNDRV_PCM_TRIGGER_RESUME
:
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
prtd
->
state
|=
ST_RUNNING
;
s3c2410_dma_ctrl
(
prtd
->
params
->
channel
,
S3C2410_DMAOP_START
);
prtd
->
params
->
ops
->
trigger
(
prtd
->
params
->
ch
);
break
;
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
prtd
->
state
&=
~
ST_RUNNING
;
s3c2410_dma_ctrl
(
prtd
->
params
->
channel
,
S3C2410_DMAOP_STOP
);
prtd
->
params
->
ops
->
stop
(
prtd
->
params
->
ch
);
break
;
default:
...
...
@@ -291,21 +274,12 @@ dma_pointer(struct snd_pcm_substream *substream)
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
runtime_data
*
prtd
=
runtime
->
private_data
;
unsigned
long
res
;
dma_addr_t
src
,
dst
;
pr_debug
(
"Entered %s
\n
"
,
__func__
);
spin_lock
(
&
prtd
->
lock
);
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
);
res
=
prtd
->
dma_pos
-
prtd
->
dma_start
;
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
* to out-of-bounds pointers. this is maybe due to the dma engine
...
...
sound/soc/samsung/dma.h
浏览文件 @
0745c9a5
...
...
@@ -6,7 +6,7 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* ALSA PCM interface for the Samsung S
3C24xx CPU
* ALSA PCM interface for the Samsung S
oC
*/
#ifndef _S3C_AUDIO_H
...
...
@@ -17,6 +17,8 @@ struct s3c_dma_params {
int
channel
;
/* Channel ID */
dma_addr_t
dma_addr
;
int
dma_size
;
/* Size of the DMA transfer */
unsigned
ch
;
struct
samsung_dma_ops
*
ops
;
};
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录