Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0745c9a5
Commit
0745c9a5
authored
Sep 21, 2011
by
Vinod Koul
Committed by
Vinod Koul
Sep 21, 2011
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'samsung_dma' into next
parents
f8de8f4c
51ddf31d
Changes
40
Hide whitespace changes
Inline
Side-by-side
Showing
40 changed files
with
1599 additions
and
1968 deletions
+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
No files found.
arch/arm/mach-exynos4/Kconfig
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
deleted
100644 → 0
View file @
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
View file @
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
deleted
100644 → 0
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment