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
nexedi
linux
Commits
d2045ba3
Commit
d2045ba3
authored
Nov 14, 2017
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/sun' into for-linus
parents
135ab7f5
464aa6f5
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
221 additions
and
62 deletions
+221
-62
Documentation/devicetree/bindings/dma/sun6i-dma.txt
Documentation/devicetree/bindings/dma/sun6i-dma.txt
+26
-0
drivers/dma/sun6i-dma.c
drivers/dma/sun6i-dma.c
+195
-62
No files found.
Documentation/devicetree/bindings/dma/sun6i-dma.txt
View file @
d2045ba3
...
...
@@ -27,6 +27,32 @@ Example:
#dma-cells = <1>;
};
------------------------------------------------------------------------------
For A64 DMA controller:
Required properties:
- compatible: "allwinner,sun50i-a64-dma"
- dma-channels: Number of DMA channels supported by the controller.
Refer to Documentation/devicetree/bindings/dma/dma.txt
- all properties above, i.e. reg, interrupts, clocks, resets and #dma-cells
Optional properties:
- dma-requests: Number of DMA request signals supported by the controller.
Refer to Documentation/devicetree/bindings/dma/dma.txt
Example:
dma: dma-controller@1c02000 {
compatible = "allwinner,sun50i-a64-dma";
reg = <0x01c02000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_DMA>;
dma-channels = <8>;
dma-requests = <27>;
resets = <&ccu RST_BUS_DMA>;
#dma-cells = <1>;
};
------------------------------------------------------------------------------
Clients:
DMA clients connected to the A31 DMA controller must use the format
...
...
drivers/dma/sun6i-dma.c
View file @
d2045ba3
...
...
@@ -42,12 +42,18 @@
#define DMA_STAT 0x30
/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */
#define DMA_MAX_CHANNELS (DMA_IRQ_CHAN_NR * 0x10 / 4)
/*
* sun8i specific registers
*/
#define SUN8I_DMA_GATE 0x20
#define SUN8I_DMA_GATE_ENABLE 0x4
#define SUNXI_H3_SECURE_REG 0x20
#define SUNXI_H3_DMA_GATE 0x28
#define SUNXI_H3_DMA_GATE_ENABLE 0x4
/*
* Channels specific registers
*/
...
...
@@ -62,16 +68,19 @@
#define DMA_CHAN_LLI_ADDR 0x08
#define DMA_CHAN_CUR_CFG 0x0c
#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & 0x1f)
#define DMA_CHAN_MAX_DRQ 0x1f
#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & DMA_CHAN_MAX_DRQ)
#define DMA_CHAN_CFG_SRC_IO_MODE BIT(5)
#define DMA_CHAN_CFG_SRC_LINEAR_MODE (0 << 5)
#define DMA_CHAN_CFG_SRC_BURST(x) (((x) & 0x3) << 7)
#define DMA_CHAN_CFG_SRC_BURST_A31(x) (((x) & 0x3) << 7)
#define DMA_CHAN_CFG_SRC_BURST_H3(x) (((x) & 0x3) << 6)
#define DMA_CHAN_CFG_SRC_WIDTH(x) (((x) & 0x3) << 9)
#define DMA_CHAN_CFG_DST_DRQ(x) (DMA_CHAN_CFG_SRC_DRQ(x) << 16)
#define DMA_CHAN_CFG_DST_IO_MODE (DMA_CHAN_CFG_SRC_IO_MODE << 16)
#define DMA_CHAN_CFG_DST_LINEAR_MODE (DMA_CHAN_CFG_SRC_LINEAR_MODE << 16)
#define DMA_CHAN_CFG_DST_BURST(x) (DMA_CHAN_CFG_SRC_BURST(x) << 16)
#define DMA_CHAN_CFG_DST_BURST_A31(x) (DMA_CHAN_CFG_SRC_BURST_A31(x) << 16)
#define DMA_CHAN_CFG_DST_BURST_H3(x) (DMA_CHAN_CFG_SRC_BURST_H3(x) << 16)
#define DMA_CHAN_CFG_DST_WIDTH(x) (DMA_CHAN_CFG_SRC_WIDTH(x) << 16)
#define DMA_CHAN_CUR_SRC 0x10
...
...
@@ -90,6 +99,9 @@
#define NORMAL_WAIT 8
#define DRQ_SDRAM 1
/* forward declaration */
struct
sun6i_dma_dev
;
/*
* Hardware channels / ports representation
*
...
...
@@ -111,7 +123,12 @@ struct sun6i_dma_config {
* however these SoCs really have and need this bit, as seen in the
* BSP kernel source code.
*/
bool
gate_needed
;
void
(
*
clock_autogate_enable
)(
struct
sun6i_dma_dev
*
);
void
(
*
set_burst_length
)(
u32
*
p_cfg
,
s8
src_burst
,
s8
dst_burst
);
u32
src_burst_lengths
;
u32
dst_burst_lengths
;
u32
src_addr_widths
;
u32
dst_addr_widths
;
};
/*
...
...
@@ -175,6 +192,9 @@ struct sun6i_dma_dev {
struct
sun6i_pchan
*
pchans
;
struct
sun6i_vchan
*
vchans
;
const
struct
sun6i_dma_config
*
cfg
;
u32
num_pchans
;
u32
num_vchans
;
u32
max_request
;
};
static
struct
device
*
chan2dev
(
struct
dma_chan
*
chan
)
...
...
@@ -251,8 +271,12 @@ static inline s8 convert_burst(u32 maxburst)
switch
(
maxburst
)
{
case
1
:
return
0
;
case
4
:
return
1
;
case
8
:
return
2
;
case
16
:
return
3
;
default:
return
-
EINVAL
;
}
...
...
@@ -260,11 +284,29 @@ static inline s8 convert_burst(u32 maxburst)
static
inline
s8
convert_buswidth
(
enum
dma_slave_buswidth
addr_width
)
{
if
((
addr_width
<
DMA_SLAVE_BUSWIDTH_1_BYTE
)
||
(
addr_width
>
DMA_SLAVE_BUSWIDTH_4_BYTES
))
return
-
EINVAL
;
return
ilog2
(
addr_width
);
}
static
void
sun6i_enable_clock_autogate_a23
(
struct
sun6i_dma_dev
*
sdev
)
{
writel
(
SUN8I_DMA_GATE_ENABLE
,
sdev
->
base
+
SUN8I_DMA_GATE
);
}
static
void
sun6i_enable_clock_autogate_h3
(
struct
sun6i_dma_dev
*
sdev
)
{
writel
(
SUNXI_H3_DMA_GATE_ENABLE
,
sdev
->
base
+
SUNXI_H3_DMA_GATE
);
}
return
addr_width
>>
1
;
static
void
sun6i_set_burst_length_a31
(
u32
*
p_cfg
,
s8
src_burst
,
s8
dst_burst
)
{
*
p_cfg
|=
DMA_CHAN_CFG_SRC_BURST_A31
(
src_burst
)
|
DMA_CHAN_CFG_DST_BURST_A31
(
dst_burst
);
}
static
void
sun6i_set_burst_length_h3
(
u32
*
p_cfg
,
s8
src_burst
,
s8
dst_burst
)
{
*
p_cfg
|=
DMA_CHAN_CFG_SRC_BURST_H3
(
src_burst
)
|
DMA_CHAN_CFG_DST_BURST_H3
(
dst_burst
);
}
static
size_t
sun6i_get_chan_size
(
struct
sun6i_pchan
*
pchan
)
...
...
@@ -399,7 +441,6 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
static
void
sun6i_dma_tasklet
(
unsigned
long
data
)
{
struct
sun6i_dma_dev
*
sdev
=
(
struct
sun6i_dma_dev
*
)
data
;
const
struct
sun6i_dma_config
*
cfg
=
sdev
->
cfg
;
struct
sun6i_vchan
*
vchan
;
struct
sun6i_pchan
*
pchan
;
unsigned
int
pchan_alloc
=
0
;
...
...
@@ -427,7 +468,7 @@ static void sun6i_dma_tasklet(unsigned long data)
}
spin_lock_irq
(
&
sdev
->
lock
);
for
(
pchan_idx
=
0
;
pchan_idx
<
cfg
->
nr_max_channel
s
;
pchan_idx
++
)
{
for
(
pchan_idx
=
0
;
pchan_idx
<
sdev
->
num_pchan
s
;
pchan_idx
++
)
{
pchan
=
&
sdev
->
pchans
[
pchan_idx
];
if
(
pchan
->
vchan
||
list_empty
(
&
sdev
->
pending
))
...
...
@@ -448,7 +489,7 @@ static void sun6i_dma_tasklet(unsigned long data)
}
spin_unlock_irq
(
&
sdev
->
lock
);
for
(
pchan_idx
=
0
;
pchan_idx
<
cfg
->
nr_max_channel
s
;
pchan_idx
++
)
{
for
(
pchan_idx
=
0
;
pchan_idx
<
sdev
->
num_pchan
s
;
pchan_idx
++
)
{
if
(
!
(
pchan_alloc
&
BIT
(
pchan_idx
)))
continue
;
...
...
@@ -470,7 +511,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
int
i
,
j
,
ret
=
IRQ_NONE
;
u32
status
;
for
(
i
=
0
;
i
<
sdev
->
cfg
->
nr_max_channel
s
/
DMA_IRQ_CHAN_NR
;
i
++
)
{
for
(
i
=
0
;
i
<
sdev
->
num_pchan
s
/
DMA_IRQ_CHAN_NR
;
i
++
)
{
status
=
readl
(
sdev
->
base
+
DMA_IRQ_STAT
(
i
));
if
(
!
status
)
continue
;
...
...
@@ -510,47 +551,49 @@ static int set_config(struct sun6i_dma_dev *sdev,
enum
dma_transfer_direction
direction
,
u32
*
p_cfg
)
{
enum
dma_slave_buswidth
src_addr_width
,
dst_addr_width
;
u32
src_maxburst
,
dst_maxburst
;
s8
src_width
,
dst_width
,
src_burst
,
dst_burst
;
src_addr_width
=
sconfig
->
src_addr_width
;
dst_addr_width
=
sconfig
->
dst_addr_width
;
src_maxburst
=
sconfig
->
src_maxburst
;
dst_maxburst
=
sconfig
->
dst_maxburst
;
switch
(
direction
)
{
case
DMA_MEM_TO_DEV
:
src_burst
=
convert_burst
(
sconfig
->
src_maxburst
?
sconfig
->
src_maxburst
:
8
);
src_width
=
convert_buswidth
(
sconfig
->
src_addr_width
!=
DMA_SLAVE_BUSWIDTH_UNDEFINED
?
sconfig
->
src_addr_width
:
DMA_SLAVE_BUSWIDTH_4_BYTES
);
dst_burst
=
convert_burst
(
sconfig
->
dst_maxburst
);
dst_width
=
convert_buswidth
(
sconfig
->
dst_addr_width
);
if
(
src_addr_width
==
DMA_SLAVE_BUSWIDTH_UNDEFINED
)
src_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
src_maxburst
=
src_maxburst
?
src_maxburst
:
8
;
break
;
case
DMA_DEV_TO_MEM
:
src_burst
=
convert_burst
(
sconfig
->
src_maxburst
);
src_width
=
convert_buswidth
(
sconfig
->
src_addr_width
);
dst_burst
=
convert_burst
(
sconfig
->
dst_maxburst
?
sconfig
->
dst_maxburst
:
8
);
dst_width
=
convert_buswidth
(
sconfig
->
dst_addr_width
!=
DMA_SLAVE_BUSWIDTH_UNDEFINED
?
sconfig
->
dst_addr_width
:
DMA_SLAVE_BUSWIDTH_4_BYTES
);
if
(
dst_addr_width
==
DMA_SLAVE_BUSWIDTH_UNDEFINED
)
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
dst_maxburst
=
dst_maxburst
?
dst_maxburst
:
8
;
break
;
default:
return
-
EINVAL
;
}
if
(
src_burst
<
0
)
return
src_burst
;
if
(
src_width
<
0
)
return
src_width
;
if
(
dst_burst
<
0
)
return
dst_burst
;
if
(
dst_width
<
0
)
return
dst_width
;
*
p_cfg
=
DMA_CHAN_CFG_SRC_BURST
(
src_burst
)
|
DMA_CHAN_CFG_SRC_WIDTH
(
src_width
)
|
DMA_CHAN_CFG_DST_BURST
(
dst_burst
)
|
if
(
!
(
BIT
(
src_addr_width
)
&
sdev
->
slave
.
src_addr_widths
))
return
-
EINVAL
;
if
(
!
(
BIT
(
dst_addr_width
)
&
sdev
->
slave
.
dst_addr_widths
))
return
-
EINVAL
;
if
(
!
(
BIT
(
src_maxburst
)
&
sdev
->
cfg
->
src_burst_lengths
))
return
-
EINVAL
;
if
(
!
(
BIT
(
dst_maxburst
)
&
sdev
->
cfg
->
dst_burst_lengths
))
return
-
EINVAL
;
src_width
=
convert_buswidth
(
src_addr_width
);
dst_width
=
convert_buswidth
(
dst_addr_width
);
dst_burst
=
convert_burst
(
dst_maxburst
);
src_burst
=
convert_burst
(
src_maxburst
);
*
p_cfg
=
DMA_CHAN_CFG_SRC_WIDTH
(
src_width
)
|
DMA_CHAN_CFG_DST_WIDTH
(
dst_width
);
sdev
->
cfg
->
set_burst_length
(
p_cfg
,
src_burst
,
dst_burst
);
return
0
;
}
...
...
@@ -593,11 +636,11 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
DMA_CHAN_CFG_DST_DRQ
(
DRQ_SDRAM
)
|
DMA_CHAN_CFG_DST_LINEAR_MODE
|
DMA_CHAN_CFG_SRC_LINEAR_MODE
|
DMA_CHAN_CFG_SRC_BURST
(
burst
)
|
DMA_CHAN_CFG_SRC_WIDTH
(
width
)
|
DMA_CHAN_CFG_DST_BURST
(
burst
)
|
DMA_CHAN_CFG_DST_WIDTH
(
width
);
sdev
->
cfg
->
set_burst_length
(
&
v_lli
->
cfg
,
burst
,
burst
);
sun6i_dma_lli_add
(
NULL
,
v_lli
,
p_lli
,
txd
);
sun6i_dma_dump_lli
(
vchan
,
v_lli
);
...
...
@@ -948,7 +991,7 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
struct
dma_chan
*
chan
;
u8
port
=
dma_spec
->
args
[
0
];
if
(
port
>
sdev
->
cfg
->
nr_max_requests
)
if
(
port
>
sdev
->
max_request
)
return
NULL
;
chan
=
dma_get_any_slave_channel
(
&
sdev
->
slave
);
...
...
@@ -981,7 +1024,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
{
int
i
;
for
(
i
=
0
;
i
<
sdev
->
cfg
->
nr_max
_vchans
;
i
++
)
{
for
(
i
=
0
;
i
<
sdev
->
num
_vchans
;
i
++
)
{
struct
sun6i_vchan
*
vchan
=
&
sdev
->
vchans
[
i
];
list_del
(
&
vchan
->
vc
.
chan
.
device_node
);
...
...
@@ -1009,6 +1052,15 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
.
nr_max_channels
=
16
,
.
nr_max_requests
=
30
,
.
nr_max_vchans
=
53
,
.
set_burst_length
=
sun6i_set_burst_length_a31
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
};
/*
...
...
@@ -1020,24 +1072,76 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
.
nr_max_channels
=
8
,
.
nr_max_requests
=
24
,
.
nr_max_vchans
=
37
,
.
gate_needed
=
true
,
.
clock_autogate_enable
=
sun6i_enable_clock_autogate_a23
,
.
set_burst_length
=
sun6i_set_burst_length_a31
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
};
static
struct
sun6i_dma_config
sun8i_a83t_dma_cfg
=
{
.
nr_max_channels
=
8
,
.
nr_max_requests
=
28
,
.
nr_max_vchans
=
39
,
.
clock_autogate_enable
=
sun6i_enable_clock_autogate_a23
,
.
set_burst_length
=
sun6i_set_burst_length_a31
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
};
/*
* The H3 has 12 physical channels, a maximum DRQ port id of 27,
* and a total of 34 usable source and destination endpoints.
* It also supports additional burst lengths and bus widths,
* and the burst length fields have different offsets.
*/
static
struct
sun6i_dma_config
sun8i_h3_dma_cfg
=
{
.
nr_max_channels
=
12
,
.
nr_max_requests
=
27
,
.
nr_max_vchans
=
34
,
.
clock_autogate_enable
=
sun6i_enable_clock_autogate_h3
,
.
set_burst_length
=
sun6i_set_burst_length_h3
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
4
)
|
BIT
(
8
)
|
BIT
(
16
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
4
)
|
BIT
(
8
)
|
BIT
(
16
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_8_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_8_BYTES
),
};
/*
* The A64 binding uses the number of dma channels from the
* device tree node.
*/
static
struct
sun6i_dma_config
sun50i_a64_dma_cfg
=
{
.
clock_autogate_enable
=
sun6i_enable_clock_autogate_h3
,
.
set_burst_length
=
sun6i_set_burst_length_h3
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
4
)
|
BIT
(
8
)
|
BIT
(
16
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
4
)
|
BIT
(
8
)
|
BIT
(
16
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_8_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_8_BYTES
),
};
/*
...
...
@@ -1049,7 +1153,16 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
.
nr_max_channels
=
8
,
.
nr_max_requests
=
23
,
.
nr_max_vchans
=
24
,
.
gate_needed
=
true
,
.
clock_autogate_enable
=
sun6i_enable_clock_autogate_a23
,
.
set_burst_length
=
sun6i_set_burst_length_a31
,
.
src_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
dst_burst_lengths
=
BIT
(
1
)
|
BIT
(
8
),
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
),
};
static
const
struct
of_device_id
sun6i_dma_match
[]
=
{
...
...
@@ -1058,13 +1171,14 @@ static const struct of_device_id sun6i_dma_match[] = {
{
.
compatible
=
"allwinner,sun8i-a83t-dma"
,
.
data
=
&
sun8i_a83t_dma_cfg
},
{
.
compatible
=
"allwinner,sun8i-h3-dma"
,
.
data
=
&
sun8i_h3_dma_cfg
},
{
.
compatible
=
"allwinner,sun8i-v3s-dma"
,
.
data
=
&
sun8i_v3s_dma_cfg
},
{
.
compatible
=
"allwinner,sun50i-a64-dma"
,
.
data
=
&
sun50i_a64_dma_cfg
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
of
,
sun6i_dma_match
);
static
int
sun6i_dma_probe
(
struct
platform_device
*
pdev
)
{
const
struct
of_device_id
*
devic
e
;
struct
device_node
*
np
=
pdev
->
dev
.
of_nod
e
;
struct
sun6i_dma_dev
*
sdc
;
struct
resource
*
res
;
int
ret
,
i
;
...
...
@@ -1073,10 +1187,9 @@ static int sun6i_dma_probe(struct platform_device *pdev)
if
(
!
sdc
)
return
-
ENOMEM
;
device
=
of_match_device
(
sun6i_dma_match
,
&
pdev
->
dev
);
if
(
!
device
)
sdc
->
cfg
=
of_device_get_match_data
(
&
pdev
->
dev
);
if
(
!
sdc
->
cfg
)
return
-
ENODEV
;
sdc
->
cfg
=
device
->
data
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
sdc
->
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
...
...
@@ -1129,37 +1242,57 @@ static int sun6i_dma_probe(struct platform_device *pdev)
sdc
->
slave
.
device_pause
=
sun6i_dma_pause
;
sdc
->
slave
.
device_resume
=
sun6i_dma_resume
;
sdc
->
slave
.
device_terminate_all
=
sun6i_dma_terminate_all
;
sdc
->
slave
.
src_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
);
sdc
->
slave
.
dst_addr_widths
=
BIT
(
DMA_SLAVE_BUSWIDTH_1_BYTE
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_2_BYTES
)
|
BIT
(
DMA_SLAVE_BUSWIDTH_4_BYTES
);
sdc
->
slave
.
src_addr_widths
=
sdc
->
cfg
->
src_addr_widths
;
sdc
->
slave
.
dst_addr_widths
=
sdc
->
cfg
->
dst_addr_widths
;
sdc
->
slave
.
directions
=
BIT
(
DMA_DEV_TO_MEM
)
|
BIT
(
DMA_MEM_TO_DEV
);
sdc
->
slave
.
residue_granularity
=
DMA_RESIDUE_GRANULARITY_BURST
;
sdc
->
slave
.
dev
=
&
pdev
->
dev
;
sdc
->
pchans
=
devm_kcalloc
(
&
pdev
->
dev
,
sdc
->
cfg
->
nr_max_channels
,
sdc
->
num_pchans
=
sdc
->
cfg
->
nr_max_channels
;
sdc
->
num_vchans
=
sdc
->
cfg
->
nr_max_vchans
;
sdc
->
max_request
=
sdc
->
cfg
->
nr_max_requests
;
ret
=
of_property_read_u32
(
np
,
"dma-channels"
,
&
sdc
->
num_pchans
);
if
(
ret
&&
!
sdc
->
num_pchans
)
{
dev_err
(
&
pdev
->
dev
,
"Can't get dma-channels.
\n
"
);
return
ret
;
}
ret
=
of_property_read_u32
(
np
,
"dma-requests"
,
&
sdc
->
max_request
);
if
(
ret
&&
!
sdc
->
max_request
)
{
dev_info
(
&
pdev
->
dev
,
"Missing dma-requests, using %u.
\n
"
,
DMA_CHAN_MAX_DRQ
);
sdc
->
max_request
=
DMA_CHAN_MAX_DRQ
;
}
/*
* If the number of vchans is not specified, derive it from the
* highest port number, at most one channel per port and direction.
*/
if
(
!
sdc
->
num_vchans
)
sdc
->
num_vchans
=
2
*
(
sdc
->
max_request
+
1
);
sdc
->
pchans
=
devm_kcalloc
(
&
pdev
->
dev
,
sdc
->
num_pchans
,
sizeof
(
struct
sun6i_pchan
),
GFP_KERNEL
);
if
(
!
sdc
->
pchans
)
return
-
ENOMEM
;
sdc
->
vchans
=
devm_kcalloc
(
&
pdev
->
dev
,
sdc
->
cfg
->
nr_max
_vchans
,
sdc
->
vchans
=
devm_kcalloc
(
&
pdev
->
dev
,
sdc
->
num
_vchans
,
sizeof
(
struct
sun6i_vchan
),
GFP_KERNEL
);
if
(
!
sdc
->
vchans
)
return
-
ENOMEM
;
tasklet_init
(
&
sdc
->
task
,
sun6i_dma_tasklet
,
(
unsigned
long
)
sdc
);
for
(
i
=
0
;
i
<
sdc
->
cfg
->
nr_max_channel
s
;
i
++
)
{
for
(
i
=
0
;
i
<
sdc
->
num_pchan
s
;
i
++
)
{
struct
sun6i_pchan
*
pchan
=
&
sdc
->
pchans
[
i
];
pchan
->
idx
=
i
;
pchan
->
base
=
sdc
->
base
+
0x100
+
i
*
0x40
;
}
for
(
i
=
0
;
i
<
sdc
->
cfg
->
nr_max
_vchans
;
i
++
)
{
for
(
i
=
0
;
i
<
sdc
->
num
_vchans
;
i
++
)
{
struct
sun6i_vchan
*
vchan
=
&
sdc
->
vchans
[
i
];
INIT_LIST_HEAD
(
&
vchan
->
node
);
...
...
@@ -1199,8 +1332,8 @@ static int sun6i_dma_probe(struct platform_device *pdev)
goto
err_dma_unregister
;
}
if
(
sdc
->
cfg
->
gate_needed
)
writel
(
SUN8I_DMA_GATE_ENABLE
,
sdc
->
base
+
SUN8I_DMA_GATE
);
if
(
sdc
->
cfg
->
clock_autogate_enable
)
sdc
->
cfg
->
clock_autogate_enable
(
sdc
);
return
0
;
...
...
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