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
4b4447bf
Commit
4b4447bf
authored
Oct 24, 2018
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/sprd' into for-linus
parents
8e75ab9b
4ac69546
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
143 additions
and
7 deletions
+143
-7
drivers/dma/sprd-dma.c
drivers/dma/sprd-dma.c
+74
-7
include/linux/dma/sprd-dma.h
include/linux/dma/sprd-dma.h
+69
-0
No files found.
drivers/dma/sprd-dma.c
View file @
4b4447bf
...
...
@@ -68,6 +68,7 @@
/* SPRD_DMA_CHN_CFG register definition */
#define SPRD_DMA_CHN_EN BIT(0)
#define SPRD_DMA_LINKLIST_EN BIT(4)
#define SPRD_DMA_WAIT_BDONE_OFFSET 24
#define SPRD_DMA_DONOT_WAIT_BDONE 1
...
...
@@ -103,7 +104,7 @@
#define SPRD_DMA_REQ_MODE_MASK GENMASK(1, 0)
#define SPRD_DMA_FIX_SEL_OFFSET 21
#define SPRD_DMA_FIX_EN_OFFSET 20
#define SPRD_DMA_LLIST_END
_OFFSET 19
#define SPRD_DMA_LLIST_END
BIT(19)
#define SPRD_DMA_FRG_LEN_MASK GENMASK(16, 0)
/* SPRD_DMA_CHN_BLK_LEN register definition */
...
...
@@ -164,6 +165,7 @@ struct sprd_dma_desc {
struct
sprd_dma_chn
{
struct
virt_dma_chan
vc
;
void
__iomem
*
chn_base
;
struct
sprd_dma_linklist
linklist
;
struct
dma_slave_config
slave_cfg
;
u32
chn_num
;
u32
dev_id
;
...
...
@@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth)
}
static
int
sprd_dma_fill_desc
(
struct
dma_chan
*
chan
,
struct
sprd_dma_desc
*
sdesc
,
struct
sprd_dma_chn_hw
*
hw
,
unsigned
int
sglen
,
int
sg_index
,
dma_addr_t
src
,
dma_addr_t
dst
,
u32
len
,
enum
dma_transfer_direction
dir
,
unsigned
long
flags
,
...
...
@@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
{
struct
sprd_dma_dev
*
sdev
=
to_sprd_dma_dev
(
chan
);
struct
sprd_dma_chn
*
schan
=
to_sprd_dma_chan
(
chan
);
struct
sprd_dma_chn_hw
*
hw
=
&
sdesc
->
chn_hw
;
u32
req_mode
=
(
flags
>>
SPRD_DMA_REQ_SHIFT
)
&
SPRD_DMA_REQ_MODE_MASK
;
u32
int_mode
=
flags
&
SPRD_DMA_INT_MASK
;
int
src_datawidth
,
dst_datawidth
,
src_step
,
dst_step
;
...
...
@@ -670,12 +672,52 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
temp
|=
(
src_step
&
SPRD_DMA_TRSF_STEP_MASK
)
<<
SPRD_DMA_SRC_TRSF_STEP_OFFSET
;
hw
->
trsf_step
=
temp
;
/* link-list configuration */
if
(
schan
->
linklist
.
phy_addr
)
{
if
(
sg_index
==
sglen
-
1
)
hw
->
frg_len
|=
SPRD_DMA_LLIST_END
;
hw
->
cfg
|=
SPRD_DMA_LINKLIST_EN
;
/* link-list index */
temp
=
(
sg_index
+
1
)
%
sglen
;
/* Next link-list configuration's physical address offset */
temp
=
temp
*
sizeof
(
*
hw
)
+
SPRD_DMA_CHN_SRC_ADDR
;
/*
* Set the link-list pointer point to next link-list
* configuration's physical address.
*/
hw
->
llist_ptr
=
schan
->
linklist
.
phy_addr
+
temp
;
}
else
{
hw
->
llist_ptr
=
0
;
}
hw
->
frg_step
=
0
;
hw
->
src_blk_step
=
0
;
hw
->
des_blk_step
=
0
;
return
0
;
}
static
int
sprd_dma_fill_linklist_desc
(
struct
dma_chan
*
chan
,
unsigned
int
sglen
,
int
sg_index
,
dma_addr_t
src
,
dma_addr_t
dst
,
u32
len
,
enum
dma_transfer_direction
dir
,
unsigned
long
flags
,
struct
dma_slave_config
*
slave_cfg
)
{
struct
sprd_dma_chn
*
schan
=
to_sprd_dma_chan
(
chan
);
struct
sprd_dma_chn_hw
*
hw
;
if
(
!
schan
->
linklist
.
virt_addr
)
return
-
EINVAL
;
hw
=
(
struct
sprd_dma_chn_hw
*
)(
schan
->
linklist
.
virt_addr
+
sg_index
*
sizeof
(
*
hw
));
return
sprd_dma_fill_desc
(
chan
,
hw
,
sglen
,
sg_index
,
src
,
dst
,
len
,
dir
,
flags
,
slave_cfg
);
}
static
struct
dma_async_tx_descriptor
*
sprd_dma_prep_dma_memcpy
(
struct
dma_chan
*
chan
,
dma_addr_t
dest
,
dma_addr_t
src
,
size_t
len
,
unsigned
long
flags
)
...
...
@@ -744,10 +786,20 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
u32
len
=
0
;
int
ret
,
i
;
/* TODO: now we only support one sg for each DMA configuration. */
if
(
!
is_slave_direction
(
dir
)
||
sglen
>
1
)
if
(
!
is_slave_direction
(
dir
))
return
NULL
;
if
(
context
)
{
struct
sprd_dma_linklist
*
ll_cfg
=
(
struct
sprd_dma_linklist
*
)
context
;
schan
->
linklist
.
phy_addr
=
ll_cfg
->
phy_addr
;
schan
->
linklist
.
virt_addr
=
ll_cfg
->
virt_addr
;
}
else
{
schan
->
linklist
.
phy_addr
=
0
;
schan
->
linklist
.
virt_addr
=
0
;
}
sdesc
=
kzalloc
(
sizeof
(
*
sdesc
),
GFP_NOWAIT
);
if
(
!
sdesc
)
return
NULL
;
...
...
@@ -762,10 +814,25 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
src
=
slave_cfg
->
src_addr
;
dst
=
sg_dma_address
(
sg
);
}
/*
* The link-list mode needs at least 2 link-list
* configurations. If there is only one sg, it doesn't
* need to fill the link-list configuration.
*/
if
(
sglen
<
2
)
break
;
ret
=
sprd_dma_fill_linklist_desc
(
chan
,
sglen
,
i
,
src
,
dst
,
len
,
dir
,
flags
,
slave_cfg
);
if
(
ret
)
{
kfree
(
sdesc
);
return
NULL
;
}
}
ret
=
sprd_dma_fill_desc
(
chan
,
sdesc
,
src
,
dst
,
len
,
dir
,
flags
,
slave_cfg
);
ret
=
sprd_dma_fill_desc
(
chan
,
&
sdesc
->
chn_hw
,
0
,
0
,
src
,
dst
,
len
,
dir
,
flags
,
slave_cfg
);
if
(
ret
)
{
kfree
(
sdesc
);
return
NULL
;
...
...
include/linux/dma/sprd-dma.h
View file @
4b4447bf
...
...
@@ -58,4 +58,73 @@ enum sprd_dma_int_type {
SPRD_DMA_CFGERR_INT
,
};
/*
* struct sprd_dma_linklist - DMA link-list address structure
* @virt_addr: link-list virtual address to configure link-list node
* @phy_addr: link-list physical address to link DMA transfer
*
* The Spreadtrum DMA controller supports the link-list mode, that means slaves
* can supply several groups configurations (each configuration represents one
* DMA transfer) saved in memory, and DMA controller will link these groups
* configurations by writing the physical address of each configuration into the
* link-list register.
*
* Just as shown below, the link-list pointer register will be pointed to the
* physical address of 'configuration 1', and the 'configuration 1' link-list
* pointer will be pointed to 'configuration 2', and so on.
* Once trigger the DMA transfer, the DMA controller will load 'configuration
* 1' to its registers automatically, after 'configuration 1' transaction is
* done, DMA controller will load 'configuration 2' automatically, until all
* DMA transactions are done.
*
* Note: The last link-list pointer should point to the physical address
* of 'configuration 1', which can avoid DMA controller loads incorrect
* configuration when the last configuration transaction is done.
*
* DMA controller linklist memory
* ====================== -----------------------
*| | | configuration 1 |<---
*| DMA controller | ------->| | |
*| | | | | |
*| | | | | |
*| | | | | |
*| linklist pointer reg |---- ----| linklist pointer | |
* ====================== | ----------------------- |
* | |
* | ----------------------- |
* | | configuration 2 | |
* --->| | |
* | | |
* | | |
* | | |
* ----| linklist pointer | |
* | ----------------------- |
* | |
* | ----------------------- |
* | | configuration 3 | |
* --->| | |
* | | |
* | . | |
* . |
* . |
* . |
* | . |
* | ----------------------- |
* | | configuration n | |
* --->| | |
* | | |
* | | |
* | | |
* | linklist pointer |----
* -----------------------
*
* To support the link-list mode, DMA slaves should allocate one segment memory
* from always-on IRAM or dma coherent memory to store these groups of DMA
* configuration, and pass the virtual and physical address to DMA controller.
*/
struct
sprd_dma_linklist
{
unsigned
long
virt_addr
;
phys_addr_t
phy_addr
;
};
#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