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
e4e48c47
Commit
e4e48c47
authored
Feb 21, 2017
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/intel' into for-linus
parents
b802c841
f7c799e9
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
227 additions
and
67 deletions
+227
-67
drivers/dma/dw/core.c
drivers/dma/dw/core.c
+151
-60
drivers/dma/dw/pci.c
drivers/dma/dw/pci.c
+17
-2
drivers/dma/dw/platform.c
drivers/dma/dw/platform.c
+1
-0
drivers/dma/dw/regs.h
drivers/dma/dw/regs.h
+54
-5
include/linux/dma/dw.h
include/linux/dma/dw.h
+2
-0
include/linux/platform_data/dma-dw.h
include/linux/platform_data/dma-dw.h
+2
-0
No files found.
drivers/dma/dw/core.c
View file @
e4e48c47
...
@@ -138,16 +138,32 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
...
@@ -138,16 +138,32 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
dwc
->
descs_allocated
--
;
dwc
->
descs_allocated
--
;
}
}
static
void
dwc_initialize
(
struct
dw_dma_chan
*
dwc
)
static
void
dwc_initialize_chan_idma32
(
struct
dw_dma_chan
*
dwc
)
{
u32
cfghi
=
0
;
u32
cfglo
=
0
;
/* Set default burst alignment */
cfglo
|=
IDMA32C_CFGL_DST_BURST_ALIGN
|
IDMA32C_CFGL_SRC_BURST_ALIGN
;
/* Low 4 bits of the request lines */
cfghi
|=
IDMA32C_CFGH_DST_PER
(
dwc
->
dws
.
dst_id
&
0xf
);
cfghi
|=
IDMA32C_CFGH_SRC_PER
(
dwc
->
dws
.
src_id
&
0xf
);
/* Request line extension (2 bits) */
cfghi
|=
IDMA32C_CFGH_DST_PER_EXT
(
dwc
->
dws
.
dst_id
>>
4
&
0x3
);
cfghi
|=
IDMA32C_CFGH_SRC_PER_EXT
(
dwc
->
dws
.
src_id
>>
4
&
0x3
);
channel_writel
(
dwc
,
CFG_LO
,
cfglo
);
channel_writel
(
dwc
,
CFG_HI
,
cfghi
);
}
static
void
dwc_initialize_chan_dw
(
struct
dw_dma_chan
*
dwc
)
{
{
struct
dw_dma
*
dw
=
to_dw_dma
(
dwc
->
chan
.
device
);
u32
cfghi
=
DWC_CFGH_FIFO_MODE
;
u32
cfghi
=
DWC_CFGH_FIFO_MODE
;
u32
cfglo
=
DWC_CFGL_CH_PRIOR
(
dwc
->
priority
);
u32
cfglo
=
DWC_CFGL_CH_PRIOR
(
dwc
->
priority
);
bool
hs_polarity
=
dwc
->
dws
.
hs_polarity
;
bool
hs_polarity
=
dwc
->
dws
.
hs_polarity
;
if
(
test_bit
(
DW_DMA_IS_INITIALIZED
,
&
dwc
->
flags
))
return
;
cfghi
|=
DWC_CFGH_DST_PER
(
dwc
->
dws
.
dst_id
);
cfghi
|=
DWC_CFGH_DST_PER
(
dwc
->
dws
.
dst_id
);
cfghi
|=
DWC_CFGH_SRC_PER
(
dwc
->
dws
.
src_id
);
cfghi
|=
DWC_CFGH_SRC_PER
(
dwc
->
dws
.
src_id
);
...
@@ -156,6 +172,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
...
@@ -156,6 +172,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
channel_writel
(
dwc
,
CFG_LO
,
cfglo
);
channel_writel
(
dwc
,
CFG_LO
,
cfglo
);
channel_writel
(
dwc
,
CFG_HI
,
cfghi
);
channel_writel
(
dwc
,
CFG_HI
,
cfghi
);
}
static
void
dwc_initialize
(
struct
dw_dma_chan
*
dwc
)
{
struct
dw_dma
*
dw
=
to_dw_dma
(
dwc
->
chan
.
device
);
if
(
test_bit
(
DW_DMA_IS_INITIALIZED
,
&
dwc
->
flags
))
return
;
if
(
dw
->
pdata
->
is_idma32
)
dwc_initialize_chan_idma32
(
dwc
);
else
dwc_initialize_chan_dw
(
dwc
);
/* Enable interrupts */
/* Enable interrupts */
channel_set_bit
(
dw
,
MASK
.
XFER
,
dwc
->
mask
);
channel_set_bit
(
dw
,
MASK
.
XFER
,
dwc
->
mask
);
...
@@ -184,6 +213,37 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
...
@@ -184,6 +213,37 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
cpu_relax
();
cpu_relax
();
}
}
static
u32
bytes2block
(
struct
dw_dma_chan
*
dwc
,
size_t
bytes
,
unsigned
int
width
,
size_t
*
len
)
{
struct
dw_dma
*
dw
=
to_dw_dma
(
dwc
->
chan
.
device
);
u32
block
;
/* Always in bytes for iDMA 32-bit */
if
(
dw
->
pdata
->
is_idma32
)
width
=
0
;
if
((
bytes
>>
width
)
>
dwc
->
block_size
)
{
block
=
dwc
->
block_size
;
*
len
=
block
<<
width
;
}
else
{
block
=
bytes
>>
width
;
*
len
=
bytes
;
}
return
block
;
}
static
size_t
block2bytes
(
struct
dw_dma_chan
*
dwc
,
u32
block
,
u32
width
)
{
struct
dw_dma
*
dw
=
to_dw_dma
(
dwc
->
chan
.
device
);
if
(
dw
->
pdata
->
is_idma32
)
return
IDMA32C_CTLH_BLOCK_TS
(
block
);
return
DWC_CTLH_BLOCK_TS
(
block
)
<<
width
;
}
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/* Perform single block transfer */
/* Perform single block transfer */
...
@@ -332,7 +392,7 @@ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
...
@@ -332,7 +392,7 @@ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
u32
ctlhi
=
channel_readl
(
dwc
,
CTL_HI
);
u32
ctlhi
=
channel_readl
(
dwc
,
CTL_HI
);
u32
ctllo
=
channel_readl
(
dwc
,
CTL_LO
);
u32
ctllo
=
channel_readl
(
dwc
,
CTL_LO
);
return
(
ctlhi
&
DWC_CTLH_BLOCK_TS_MASK
)
*
(
1
<<
(
ctllo
>>
4
&
7
)
);
return
block2bytes
(
dwc
,
ctlhi
,
ctllo
>>
4
&
7
);
}
}
static
void
dwc_scan_descriptors
(
struct
dw_dma
*
dw
,
struct
dw_dma_chan
*
dwc
)
static
void
dwc_scan_descriptors
(
struct
dw_dma
*
dw
,
struct
dw_dma_chan
*
dwc
)
...
@@ -692,10 +752,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
...
@@ -692,10 +752,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
DWC_CTLL_FC_M2M
;
|
DWC_CTLL_FC_M2M
;
prev
=
first
=
NULL
;
prev
=
first
=
NULL
;
for
(
offset
=
0
;
offset
<
len
;
offset
+=
xfer_count
<<
src_width
)
{
for
(
offset
=
0
;
offset
<
len
;
offset
+=
xfer_count
)
{
xfer_count
=
min_t
(
size_t
,
(
len
-
offset
)
>>
src_width
,
dwc
->
block_size
);
desc
=
dwc_desc_get
(
dwc
);
desc
=
dwc_desc_get
(
dwc
);
if
(
!
desc
)
if
(
!
desc
)
goto
err_desc_get
;
goto
err_desc_get
;
...
@@ -703,8 +760,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
...
@@ -703,8 +760,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
lli_write
(
desc
,
sar
,
src
+
offset
);
lli_write
(
desc
,
sar
,
src
+
offset
);
lli_write
(
desc
,
dar
,
dest
+
offset
);
lli_write
(
desc
,
dar
,
dest
+
offset
);
lli_write
(
desc
,
ctllo
,
ctllo
);
lli_write
(
desc
,
ctllo
,
ctllo
);
lli_write
(
desc
,
ctlhi
,
xfer_count
);
lli_write
(
desc
,
ctlhi
,
bytes2block
(
dwc
,
len
-
offset
,
src_width
,
&
xfer_count
)
);
desc
->
len
=
xfer_count
<<
src_width
;
desc
->
len
=
xfer_count
;
if
(
!
first
)
{
if
(
!
first
)
{
first
=
desc
;
first
=
desc
;
...
@@ -775,7 +832,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -775,7 +832,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
for_each_sg
(
sgl
,
sg
,
sg_len
,
i
)
{
for_each_sg
(
sgl
,
sg
,
sg_len
,
i
)
{
struct
dw_desc
*
desc
;
struct
dw_desc
*
desc
;
u32
len
,
dlen
,
mem
;
u32
len
,
mem
;
size_t
dlen
;
mem
=
sg_dma_address
(
sg
);
mem
=
sg_dma_address
(
sg
);
len
=
sg_dma_len
(
sg
);
len
=
sg_dma_len
(
sg
);
...
@@ -789,17 +847,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -789,17 +847,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
lli_write
(
desc
,
sar
,
mem
);
lli_write
(
desc
,
sar
,
mem
);
lli_write
(
desc
,
dar
,
reg
);
lli_write
(
desc
,
dar
,
reg
);
lli_write
(
desc
,
ctlhi
,
bytes2block
(
dwc
,
len
,
mem_width
,
&
dlen
));
lli_write
(
desc
,
ctllo
,
ctllo
|
DWC_CTLL_SRC_WIDTH
(
mem_width
));
lli_write
(
desc
,
ctllo
,
ctllo
|
DWC_CTLL_SRC_WIDTH
(
mem_width
));
if
((
len
>>
mem_width
)
>
dwc
->
block_size
)
{
dlen
=
dwc
->
block_size
<<
mem_width
;
mem
+=
dlen
;
len
-=
dlen
;
}
else
{
dlen
=
len
;
len
=
0
;
}
lli_write
(
desc
,
ctlhi
,
dlen
>>
mem_width
);
desc
->
len
=
dlen
;
desc
->
len
=
dlen
;
if
(
!
first
)
{
if
(
!
first
)
{
...
@@ -809,6 +858,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -809,6 +858,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
list_add_tail
(
&
desc
->
desc_node
,
&
first
->
tx_list
);
list_add_tail
(
&
desc
->
desc_node
,
&
first
->
tx_list
);
}
}
prev
=
desc
;
prev
=
desc
;
mem
+=
dlen
;
len
-=
dlen
;
total_len
+=
dlen
;
total_len
+=
dlen
;
if
(
len
)
if
(
len
)
...
@@ -828,13 +880,12 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -828,13 +880,12 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
for_each_sg
(
sgl
,
sg
,
sg_len
,
i
)
{
for_each_sg
(
sgl
,
sg
,
sg_len
,
i
)
{
struct
dw_desc
*
desc
;
struct
dw_desc
*
desc
;
u32
len
,
dlen
,
mem
;
u32
len
,
mem
;
size_t
dlen
;
mem
=
sg_dma_address
(
sg
);
mem
=
sg_dma_address
(
sg
);
len
=
sg_dma_len
(
sg
);
len
=
sg_dma_len
(
sg
);
mem_width
=
__ffs
(
data_width
|
mem
|
len
);
slave_sg_fromdev_fill_desc:
slave_sg_fromdev_fill_desc:
desc
=
dwc_desc_get
(
dwc
);
desc
=
dwc_desc_get
(
dwc
);
if
(
!
desc
)
if
(
!
desc
)
...
@@ -842,16 +893,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -842,16 +893,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
lli_write
(
desc
,
sar
,
reg
);
lli_write
(
desc
,
sar
,
reg
);
lli_write
(
desc
,
dar
,
mem
);
lli_write
(
desc
,
dar
,
mem
);
lli_write
(
desc
,
ctlhi
,
bytes2block
(
dwc
,
len
,
reg_width
,
&
dlen
));
mem_width
=
__ffs
(
data_width
|
mem
|
dlen
);
lli_write
(
desc
,
ctllo
,
ctllo
|
DWC_CTLL_DST_WIDTH
(
mem_width
));
lli_write
(
desc
,
ctllo
,
ctllo
|
DWC_CTLL_DST_WIDTH
(
mem_width
));
if
((
len
>>
reg_width
)
>
dwc
->
block_size
)
{
dlen
=
dwc
->
block_size
<<
reg_width
;
mem
+=
dlen
;
len
-=
dlen
;
}
else
{
dlen
=
len
;
len
=
0
;
}
lli_write
(
desc
,
ctlhi
,
dlen
>>
reg_width
);
desc
->
len
=
dlen
;
desc
->
len
=
dlen
;
if
(
!
first
)
{
if
(
!
first
)
{
...
@@ -861,6 +905,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
...
@@ -861,6 +905,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
list_add_tail
(
&
desc
->
desc_node
,
&
first
->
tx_list
);
list_add_tail
(
&
desc
->
desc_node
,
&
first
->
tx_list
);
}
}
prev
=
desc
;
prev
=
desc
;
mem
+=
dlen
;
len
-=
dlen
;
total_len
+=
dlen
;
total_len
+=
dlen
;
if
(
len
)
if
(
len
)
...
@@ -903,25 +950,20 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
...
@@ -903,25 +950,20 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
}
}
EXPORT_SYMBOL_GPL
(
dw_dma_filter
);
EXPORT_SYMBOL_GPL
(
dw_dma_filter
);
/*
* Fix sconfig's burst size according to dw_dmac. We need to convert them as:
* 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
*
* NOTE: burst size 2 is not supported by controller.
*
* This can be done by finding least significant bit set: n & (n - 1)
*/
static
inline
void
convert_burst
(
u32
*
maxburst
)
{
if
(
*
maxburst
>
1
)
*
maxburst
=
fls
(
*
maxburst
)
-
2
;
else
*
maxburst
=
0
;
}
static
int
dwc_config
(
struct
dma_chan
*
chan
,
struct
dma_slave_config
*
sconfig
)
static
int
dwc_config
(
struct
dma_chan
*
chan
,
struct
dma_slave_config
*
sconfig
)
{
{
struct
dw_dma_chan
*
dwc
=
to_dw_dma_chan
(
chan
);
struct
dw_dma_chan
*
dwc
=
to_dw_dma_chan
(
chan
);
struct
dma_slave_config
*
sc
=
&
dwc
->
dma_sconfig
;
struct
dw_dma
*
dw
=
to_dw_dma
(
chan
->
device
);
/*
* Fix sconfig's burst size according to dw_dmac. We need to convert
* them as:
* 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
*
* NOTE: burst size 2 is not supported by DesignWare controller.
* iDMA 32-bit supports it.
*/
u32
s
=
dw
->
pdata
->
is_idma32
?
1
:
2
;
/* Check if chan will be configured for slave transfers */
/* Check if chan will be configured for slave transfers */
if
(
!
is_slave_direction
(
sconfig
->
direction
))
if
(
!
is_slave_direction
(
sconfig
->
direction
))
...
@@ -930,28 +972,39 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
...
@@ -930,28 +972,39 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
memcpy
(
&
dwc
->
dma_sconfig
,
sconfig
,
sizeof
(
*
sconfig
));
memcpy
(
&
dwc
->
dma_sconfig
,
sconfig
,
sizeof
(
*
sconfig
));
dwc
->
direction
=
sconfig
->
direction
;
dwc
->
direction
=
sconfig
->
direction
;
convert_burst
(
&
dwc
->
dma_sconfig
.
src_maxburst
)
;
sc
->
src_maxburst
=
sc
->
src_maxburst
>
1
?
fls
(
sc
->
src_maxburst
)
-
s
:
0
;
convert_burst
(
&
dwc
->
dma_sconfig
.
dst_maxburst
)
;
sc
->
dst_maxburst
=
sc
->
dst_maxburst
>
1
?
fls
(
sc
->
dst_maxburst
)
-
s
:
0
;
return
0
;
return
0
;
}
}
static
int
dwc_pause
(
struct
dma_chan
*
cha
n
)
static
void
dwc_chan_pause
(
struct
dw_dma_chan
*
dwc
,
bool
drai
n
)
{
{
struct
dw_dma_chan
*
dwc
=
to_dw_dma_chan
(
chan
);
struct
dw_dma
*
dw
=
to_dw_dma
(
dwc
->
chan
.
device
);
unsigned
long
flags
;
unsigned
int
count
=
20
;
/* timeout iterations */
unsigned
int
count
=
20
;
/* timeout iterations */
u32
cfglo
;
u32
cfglo
;
spin_lock_irqsave
(
&
dwc
->
lock
,
flags
);
cfglo
=
channel_readl
(
dwc
,
CFG_LO
);
cfglo
=
channel_readl
(
dwc
,
CFG_LO
);
if
(
dw
->
pdata
->
is_idma32
)
{
if
(
drain
)
cfglo
|=
IDMA32C_CFGL_CH_DRAIN
;
else
cfglo
&=
~
IDMA32C_CFGL_CH_DRAIN
;
}
channel_writel
(
dwc
,
CFG_LO
,
cfglo
|
DWC_CFGL_CH_SUSP
);
channel_writel
(
dwc
,
CFG_LO
,
cfglo
|
DWC_CFGL_CH_SUSP
);
while
(
!
(
channel_readl
(
dwc
,
CFG_LO
)
&
DWC_CFGL_FIFO_EMPTY
)
&&
count
--
)
while
(
!
(
channel_readl
(
dwc
,
CFG_LO
)
&
DWC_CFGL_FIFO_EMPTY
)
&&
count
--
)
udelay
(
2
);
udelay
(
2
);
set_bit
(
DW_DMA_IS_PAUSED
,
&
dwc
->
flags
);
set_bit
(
DW_DMA_IS_PAUSED
,
&
dwc
->
flags
);
}
static
int
dwc_pause
(
struct
dma_chan
*
chan
)
{
struct
dw_dma_chan
*
dwc
=
to_dw_dma_chan
(
chan
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
dwc
->
lock
,
flags
);
dwc_chan_pause
(
dwc
,
false
);
spin_unlock_irqrestore
(
&
dwc
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
dwc
->
lock
,
flags
);
return
0
;
return
0
;
...
@@ -993,6 +1046,8 @@ static int dwc_terminate_all(struct dma_chan *chan)
...
@@ -993,6 +1046,8 @@ static int dwc_terminate_all(struct dma_chan *chan)
clear_bit
(
DW_DMA_IS_SOFT_LLP
,
&
dwc
->
flags
);
clear_bit
(
DW_DMA_IS_SOFT_LLP
,
&
dwc
->
flags
);
dwc_chan_pause
(
dwc
,
true
);
dwc_chan_disable
(
dw
,
dwc
);
dwc_chan_disable
(
dw
,
dwc
);
dwc_chan_resume
(
dwc
);
dwc_chan_resume
(
dwc
);
...
@@ -1085,6 +1140,32 @@ static void dwc_issue_pending(struct dma_chan *chan)
...
@@ -1085,6 +1140,32 @@ static void dwc_issue_pending(struct dma_chan *chan)
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
/*
* Program FIFO size of channels.
*
* By default full FIFO (1024 bytes) is assigned to channel 0. Here we
* slice FIFO on equal parts between channels.
*/
static
void
idma32_fifo_partition
(
struct
dw_dma
*
dw
)
{
u64
value
=
IDMA32C_FP_PSIZE_CH0
(
128
)
|
IDMA32C_FP_PSIZE_CH1
(
128
)
|
IDMA32C_FP_UPDATE
;
u64
fifo_partition
=
0
;
if
(
!
dw
->
pdata
->
is_idma32
)
return
;
/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
fifo_partition
|=
value
<<
0
;
/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
fifo_partition
|=
value
<<
32
;
/* Program FIFO Partition registers - 128 bytes for each channel */
idma32_writeq
(
dw
,
FIFO_PARTITION1
,
fifo_partition
);
idma32_writeq
(
dw
,
FIFO_PARTITION0
,
fifo_partition
);
}
static
void
dw_dma_off
(
struct
dw_dma
*
dw
)
static
void
dw_dma_off
(
struct
dw_dma
*
dw
)
{
{
unsigned
int
i
;
unsigned
int
i
;
...
@@ -1504,8 +1585,16 @@ int dw_dma_probe(struct dw_dma_chip *chip)
...
@@ -1504,8 +1585,16 @@ int dw_dma_probe(struct dw_dma_chip *chip)
/* Force dma off, just in case */
/* Force dma off, just in case */
dw_dma_off
(
dw
);
dw_dma_off
(
dw
);
idma32_fifo_partition
(
dw
);
/* Device and instance ID for IRQ and DMA pool */
if
(
pdata
->
is_idma32
)
snprintf
(
dw
->
name
,
sizeof
(
dw
->
name
),
"idma32:dmac%d"
,
chip
->
id
);
else
snprintf
(
dw
->
name
,
sizeof
(
dw
->
name
),
"dw:dmac%d"
,
chip
->
id
);
/* Create a pool of consistent memory blocks for hardware descriptors */
/* Create a pool of consistent memory blocks for hardware descriptors */
dw
->
desc_pool
=
dmam_pool_create
(
"dw_dmac_desc_pool"
,
chip
->
dev
,
dw
->
desc_pool
=
dmam_pool_create
(
dw
->
name
,
chip
->
dev
,
sizeof
(
struct
dw_desc
),
4
,
0
);
sizeof
(
struct
dw_desc
),
4
,
0
);
if
(
!
dw
->
desc_pool
)
{
if
(
!
dw
->
desc_pool
)
{
dev_err
(
chip
->
dev
,
"No memory for descriptors dma pool
\n
"
);
dev_err
(
chip
->
dev
,
"No memory for descriptors dma pool
\n
"
);
...
@@ -1516,7 +1605,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
...
@@ -1516,7 +1605,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
tasklet_init
(
&
dw
->
tasklet
,
dw_dma_tasklet
,
(
unsigned
long
)
dw
);
tasklet_init
(
&
dw
->
tasklet
,
dw_dma_tasklet
,
(
unsigned
long
)
dw
);
err
=
request_irq
(
chip
->
irq
,
dw_dma_interrupt
,
IRQF_SHARED
,
err
=
request_irq
(
chip
->
irq
,
dw_dma_interrupt
,
IRQF_SHARED
,
"dw_dmac"
,
dw
);
dw
->
name
,
dw
);
if
(
err
)
if
(
err
)
goto
err_pdata
;
goto
err_pdata
;
...
@@ -1665,6 +1754,8 @@ int dw_dma_enable(struct dw_dma_chip *chip)
...
@@ -1665,6 +1754,8 @@ int dw_dma_enable(struct dw_dma_chip *chip)
{
{
struct
dw_dma
*
dw
=
chip
->
dw
;
struct
dw_dma
*
dw
=
chip
->
dw
;
idma32_fifo_partition
(
dw
);
dw_dma_on
(
dw
);
dw_dma_on
(
dw
);
return
0
;
return
0
;
}
}
...
...
drivers/dma/dw/pci.c
View file @
e4e48c47
...
@@ -15,6 +15,18 @@
...
@@ -15,6 +15,18 @@
#include "internal.h"
#include "internal.h"
static
struct
dw_dma_platform_data
mrfld_pdata
=
{
.
nr_channels
=
8
,
.
is_private
=
true
,
.
is_memcpy
=
true
,
.
is_idma32
=
true
,
.
chan_allocation_order
=
CHAN_ALLOCATION_ASCENDING
,
.
chan_priority
=
CHAN_PRIORITY_ASCENDING
,
.
block_size
=
131071
,
.
nr_masters
=
1
,
.
data_width
=
{
4
},
};
static
int
dw_pci_probe
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
pid
)
static
int
dw_pci_probe
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
pid
)
{
{
const
struct
dw_dma_platform_data
*
pdata
=
(
void
*
)
pid
->
driver_data
;
const
struct
dw_dma_platform_data
*
pdata
=
(
void
*
)
pid
->
driver_data
;
...
@@ -47,6 +59,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
...
@@ -47,6 +59,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
return
-
ENOMEM
;
return
-
ENOMEM
;
chip
->
dev
=
&
pdev
->
dev
;
chip
->
dev
=
&
pdev
->
dev
;
chip
->
id
=
pdev
->
devfn
;
chip
->
regs
=
pcim_iomap_table
(
pdev
)[
0
];
chip
->
regs
=
pcim_iomap_table
(
pdev
)[
0
];
chip
->
irq
=
pdev
->
irq
;
chip
->
irq
=
pdev
->
irq
;
chip
->
pdata
=
pdata
;
chip
->
pdata
=
pdata
;
...
@@ -95,14 +108,16 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
...
@@ -95,14 +108,16 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
};
};
static
const
struct
pci_device_id
dw_pci_id_table
[]
=
{
static
const
struct
pci_device_id
dw_pci_id_table
[]
=
{
/* Medfield */
/* Medfield
(GPDMA)
*/
{
PCI_VDEVICE
(
INTEL
,
0x0827
)
},
{
PCI_VDEVICE
(
INTEL
,
0x0827
)
},
{
PCI_VDEVICE
(
INTEL
,
0x0830
)
},
/* BayTrail */
/* BayTrail */
{
PCI_VDEVICE
(
INTEL
,
0x0f06
)
},
{
PCI_VDEVICE
(
INTEL
,
0x0f06
)
},
{
PCI_VDEVICE
(
INTEL
,
0x0f40
)
},
{
PCI_VDEVICE
(
INTEL
,
0x0f40
)
},
/* Merrifield iDMA 32-bit (GPDMA) */
{
PCI_VDEVICE
(
INTEL
,
0x11a2
),
(
kernel_ulong_t
)
&
mrfld_pdata
},
/* Braswell */
/* Braswell */
{
PCI_VDEVICE
(
INTEL
,
0x2286
)
},
{
PCI_VDEVICE
(
INTEL
,
0x2286
)
},
{
PCI_VDEVICE
(
INTEL
,
0x22c0
)
},
{
PCI_VDEVICE
(
INTEL
,
0x22c0
)
},
...
...
drivers/dma/dw/platform.c
View file @
e4e48c47
...
@@ -202,6 +202,7 @@ static int dw_probe(struct platform_device *pdev)
...
@@ -202,6 +202,7 @@ static int dw_probe(struct platform_device *pdev)
pdata
=
dw_dma_parse_dt
(
pdev
);
pdata
=
dw_dma_parse_dt
(
pdev
);
chip
->
dev
=
dev
;
chip
->
dev
=
dev
;
chip
->
id
=
pdev
->
id
;
chip
->
pdata
=
pdata
;
chip
->
pdata
=
pdata
;
chip
->
clk
=
devm_clk_get
(
chip
->
dev
,
"hclk"
);
chip
->
clk
=
devm_clk_get
(
chip
->
dev
,
"hclk"
);
...
...
drivers/dma/dw/regs.h
View file @
e4e48c47
...
@@ -3,15 +3,19 @@
...
@@ -3,15 +3,19 @@
*
*
* Copyright (C) 2005-2007 Atmel Corporation
* Copyright (C) 2005-2007 Atmel Corporation
* Copyright (C) 2010-2011 ST Microelectronics
* Copyright (C) 2010-2011 ST Microelectronics
* Copyright (C) 2016 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* 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
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation.
*/
*/
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dmaengine.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include "internal.h"
#include "internal.h"
#define DW_DMA_MAX_NR_REQUESTS 16
#define DW_DMA_MAX_NR_REQUESTS 16
...
@@ -85,9 +89,9 @@ struct dw_dma_regs {
...
@@ -85,9 +89,9 @@ struct dw_dma_regs {
DW_REG
(
ID
);
DW_REG
(
ID
);
DW_REG
(
TEST
);
DW_REG
(
TEST
);
/*
reserved
*/
/*
iDMA 32-bit support
*/
DW_REG
(
__reserved
0
);
DW_REG
(
CLASS_PRIORITY
0
);
DW_REG
(
__reserved
1
);
DW_REG
(
CLASS_PRIORITY
1
);
/* optional encoded params, 0x3c8..0x3f7 */
/* optional encoded params, 0x3c8..0x3f7 */
u32
__reserved
;
u32
__reserved
;
...
@@ -99,6 +103,17 @@ struct dw_dma_regs {
...
@@ -99,6 +103,17 @@ struct dw_dma_regs {
/* top-level parameters */
/* top-level parameters */
u32
DW_PARAMS
;
u32
DW_PARAMS
;
/* component ID */
u32
COMP_TYPE
;
u32
COMP_VERSION
;
/* iDMA 32-bit support */
DW_REG
(
FIFO_PARTITION0
);
DW_REG
(
FIFO_PARTITION1
);
DW_REG
(
SAI_ERR
);
DW_REG
(
GLOBAL_CFG
);
};
};
/*
/*
...
@@ -170,8 +185,9 @@ enum dw_dma_msize {
...
@@ -170,8 +185,9 @@ enum dw_dma_msize {
#define DWC_CTLL_LLP_S_EN (1 << 28)
/* src block chain */
#define DWC_CTLL_LLP_S_EN (1 << 28)
/* src block chain */
/* Bitfields in CTL_HI */
/* Bitfields in CTL_HI */
#define DWC_CTLH_DONE 0x00001000
#define DWC_CTLH_BLOCK_TS_MASK GENMASK(11, 0)
#define DWC_CTLH_BLOCK_TS_MASK 0x00000fff
#define DWC_CTLH_BLOCK_TS(x) ((x) & DWC_CTLH_BLOCK_TS_MASK)
#define DWC_CTLH_DONE (1 << 12)
/* Bitfields in CFG_LO */
/* Bitfields in CFG_LO */
#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5)
/* priority mask */
#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5)
/* priority mask */
...
@@ -214,6 +230,33 @@ enum dw_dma_msize {
...
@@ -214,6 +230,33 @@ enum dw_dma_msize {
/* Bitfields in CFG */
/* Bitfields in CFG */
#define DW_CFG_DMA_EN (1 << 0)
#define DW_CFG_DMA_EN (1 << 0)
/* iDMA 32-bit support */
/* Bitfields in CTL_HI */
#define IDMA32C_CTLH_BLOCK_TS_MASK GENMASK(16, 0)
#define IDMA32C_CTLH_BLOCK_TS(x) ((x) & IDMA32C_CTLH_BLOCK_TS_MASK)
#define IDMA32C_CTLH_DONE (1 << 17)
/* Bitfields in CFG_LO */
#define IDMA32C_CFGL_DST_BURST_ALIGN (1 << 0)
/* dst burst align */
#define IDMA32C_CFGL_SRC_BURST_ALIGN (1 << 1)
/* src burst align */
#define IDMA32C_CFGL_CH_DRAIN (1 << 10)
/* drain FIFO */
#define IDMA32C_CFGL_DST_OPT_BL (1 << 20)
/* optimize dst burst length */
#define IDMA32C_CFGL_SRC_OPT_BL (1 << 21)
/* optimize src burst length */
/* Bitfields in CFG_HI */
#define IDMA32C_CFGH_SRC_PER(x) ((x) << 0)
#define IDMA32C_CFGH_DST_PER(x) ((x) << 4)
#define IDMA32C_CFGH_RD_ISSUE_THD(x) ((x) << 8)
#define IDMA32C_CFGH_RW_ISSUE_THD(x) ((x) << 18)
#define IDMA32C_CFGH_SRC_PER_EXT(x) ((x) << 28)
/* src peripheral extension */
#define IDMA32C_CFGH_DST_PER_EXT(x) ((x) << 30)
/* dst peripheral extension */
/* Bitfields in FIFO_PARTITION */
#define IDMA32C_FP_PSIZE_CH0(x) ((x) << 0)
#define IDMA32C_FP_PSIZE_CH1(x) ((x) << 13)
#define IDMA32C_FP_UPDATE (1 << 26)
enum
dw_dmac_flags
{
enum
dw_dmac_flags
{
DW_DMA_IS_CYCLIC
=
0
,
DW_DMA_IS_CYCLIC
=
0
,
DW_DMA_IS_SOFT_LLP
=
1
,
DW_DMA_IS_SOFT_LLP
=
1
,
...
@@ -270,6 +313,7 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
...
@@ -270,6 +313,7 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
struct
dw_dma
{
struct
dw_dma
{
struct
dma_device
dma
;
struct
dma_device
dma
;
char
name
[
20
];
void
__iomem
*
regs
;
void
__iomem
*
regs
;
struct
dma_pool
*
desc_pool
;
struct
dma_pool
*
desc_pool
;
struct
tasklet_struct
tasklet
;
struct
tasklet_struct
tasklet
;
...
@@ -293,6 +337,11 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
...
@@ -293,6 +337,11 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
#define dma_writel(dw, name, val) \
#define dma_writel(dw, name, val) \
dma_writel_native((val), &(__dw_regs(dw)->name))
dma_writel_native((val), &(__dw_regs(dw)->name))
#define idma32_readq(dw, name) \
hi_lo_readq(&(__dw_regs(dw)->name))
#define idma32_writeq(dw, name, val) \
hi_lo_writeq((val), &(__dw_regs(dw)->name))
#define channel_set_bit(dw, reg, mask) \
#define channel_set_bit(dw, reg, mask) \
dma_writel(dw, reg, ((mask) << 8) | (mask))
dma_writel(dw, reg, ((mask) << 8) | (mask))
#define channel_clear_bit(dw, reg, mask) \
#define channel_clear_bit(dw, reg, mask) \
...
...
include/linux/dma/dw.h
View file @
e4e48c47
...
@@ -23,6 +23,7 @@ struct dw_dma;
...
@@ -23,6 +23,7 @@ struct dw_dma;
/**
/**
* struct dw_dma_chip - representation of DesignWare DMA controller hardware
* struct dw_dma_chip - representation of DesignWare DMA controller hardware
* @dev: struct device of the DMA controller
* @dev: struct device of the DMA controller
* @id: instance ID
* @irq: irq line
* @irq: irq line
* @regs: memory mapped I/O space
* @regs: memory mapped I/O space
* @clk: hclk clock
* @clk: hclk clock
...
@@ -31,6 +32,7 @@ struct dw_dma;
...
@@ -31,6 +32,7 @@ struct dw_dma;
*/
*/
struct
dw_dma_chip
{
struct
dw_dma_chip
{
struct
device
*
dev
;
struct
device
*
dev
;
int
id
;
int
irq
;
int
irq
;
void
__iomem
*
regs
;
void
__iomem
*
regs
;
struct
clk
*
clk
;
struct
clk
*
clk
;
...
...
include/linux/platform_data/dma-dw.h
View file @
e4e48c47
...
@@ -41,6 +41,7 @@ struct dw_dma_slave {
...
@@ -41,6 +41,7 @@ struct dw_dma_slave {
* @is_private: The device channels should be marked as private and not for
* @is_private: The device channels should be marked as private and not for
* by the general purpose DMA channel allocator.
* by the general purpose DMA channel allocator.
* @is_memcpy: The device channels do support memory-to-memory transfers.
* @is_memcpy: The device channels do support memory-to-memory transfers.
* @is_idma32: The type of the DMA controller is iDMA32
* @chan_allocation_order: Allocate channels starting from 0 or 7
* @chan_allocation_order: Allocate channels starting from 0 or 7
* @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
* @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
* @block_size: Maximum block size supported by the controller
* @block_size: Maximum block size supported by the controller
...
@@ -53,6 +54,7 @@ struct dw_dma_platform_data {
...
@@ -53,6 +54,7 @@ struct dw_dma_platform_data {
unsigned
int
nr_channels
;
unsigned
int
nr_channels
;
bool
is_private
;
bool
is_private
;
bool
is_memcpy
;
bool
is_memcpy
;
bool
is_idma32
;
#define CHAN_ALLOCATION_ASCENDING 0
/* zero to seven */
#define CHAN_ALLOCATION_ASCENDING 0
/* zero to seven */
#define CHAN_ALLOCATION_DESCENDING 1
/* seven to zero */
#define CHAN_ALLOCATION_DESCENDING 1
/* seven to zero */
unsigned
char
chan_allocation_order
;
unsigned
char
chan_allocation_order
;
...
...
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