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
f23514b1
Commit
f23514b1
authored
May 04, 2017
by
Vinod Koul
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/cppi' into for-linus
parents
fbfb8e1d
eda6f4e8
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
137 additions
and
78 deletions
+137
-78
Documentation/devicetree/bindings/usb/da8xx-usb.txt
Documentation/devicetree/bindings/usb/da8xx-usb.txt
+40
-1
drivers/dma/Kconfig
drivers/dma/Kconfig
+3
-3
drivers/dma/cppi41.c
drivers/dma/cppi41.c
+94
-74
No files found.
Documentation/devicetree/bindings/usb/da8xx-usb.txt
View file @
f23514b1
...
...
@@ -18,10 +18,26 @@ Required properties:
- phy-names: Should be "usb-phy"
- dmas: specifies the dma channels
- dma-names: specifies the names of the channels. Use "rxN" for receive
and "txN" for transmit endpoints. N specifies the endpoint number.
Optional properties:
~~~~~~~~~~~~~~~~~~~~
- vbus-supply: Phandle to a regulator providing the USB bus power.
DMA
~~~
- compatible: ti,da830-cppi41
- reg: offset and length of the following register spaces: CPPI DMA Controller,
CPPI DMA Scheduler, Queue Manager
- reg-names: "controller", "scheduler", "queuemgr"
- #dma-cells: should be set to 2. The first number represents the
channel number (0 … 3 for endpoints 1 … 4).
The second number is 0 for RX and 1 for TX transfers.
- #dma-channels: should be set to 4 representing the 4 endpoints.
Example:
usb_phy: usb-phy {
compatible = "ti,da830-usb-phy";
...
...
@@ -30,7 +46,10 @@ Example:
};
usb0: usb@200000 {
compatible = "ti,da830-musb";
reg = <0x00200000 0x10000>;
reg = <0x00200000 0x1000>;
ranges;
#address-cells = <1>;
#size-cells = <1>;
interrupts = <58>;
interrupt-names = "mc";
...
...
@@ -39,5 +58,25 @@ Example:
phys = <&usb_phy 0>;
phy-names = "usb-phy";
dmas = <&cppi41dma 0 0 &cppi41dma 1 0
&cppi41dma 2 0 &cppi41dma 3 0
&cppi41dma 0 1 &cppi41dma 1 1
&cppi41dma 2 1 &cppi41dma 3 1>;
dma-names =
"rx1", "rx2", "rx3", "rx4",
"tx1", "tx2", "tx3", "tx4";
status = "okay";
cppi41dma: dma-controller@201000 {
compatible = "ti,da830-cppi41";
reg = <0x201000 0x1000
0x202000 0x1000
0x204000 0x4000>;
reg-names = "controller", "scheduler", "queuemgr";
interrupts = <58>;
#dma-cells = <2>;
#dma-channels = <4>;
};
};
drivers/dma/Kconfig
View file @
f23514b1
...
...
@@ -514,12 +514,12 @@ config TIMB_DMA
Enable support for the Timberdale FPGA DMA engine.
config TI_CPPI41
tristate "
AM33xx CPPI4
1 DMA support"
depends on
ARCH_OMAP
tristate "
CPPI 4.
1 DMA support"
depends on
(ARCH_OMAP || ARCH_DAVINCI_DA8XX)
select DMA_ENGINE
help
The Communications Port Programming Interface (CPPI) 4.1 DMA engine
is currently used by the USB driver on AM335x platforms.
is currently used by the USB driver on AM335x
and DA8xx
platforms.
config TI_DMA_CROSSBAR
bool
...
...
drivers/dma/cppi41.c
View file @
f23514b1
...
...
@@ -68,7 +68,6 @@
#define QMGR_MEMCTRL_IDX_SH 16
#define QMGR_MEMCTRL_DESC_SH 8
#define QMGR_NUM_PEND 5
#define QMGR_PEND(x) (0x90 + (x) * 4)
#define QMGR_PENDING_SLOT_Q(x) (x / 32)
...
...
@@ -131,7 +130,6 @@ struct cppi41_dd {
u32
first_td_desc
;
struct
cppi41_channel
*
chan_busy
[
ALLOC_DECS_NUM
];
void
__iomem
*
usbss_mem
;
void
__iomem
*
ctrl_mem
;
void
__iomem
*
sched_mem
;
void
__iomem
*
qmgr_mem
;
...
...
@@ -139,6 +137,10 @@ struct cppi41_dd {
const
struct
chan_queues
*
queues_rx
;
const
struct
chan_queues
*
queues_tx
;
struct
chan_queues
td_queue
;
u16
first_completion_queue
;
u16
qmgr_num_pend
;
u32
n_chans
;
u8
platform
;
struct
list_head
pending
;
/* Pending queued transfers */
spinlock_t
lock
;
/* Lock for pending list */
...
...
@@ -149,8 +151,7 @@ struct cppi41_dd {
bool
is_suspended
;
};
#define FIST_COMPLETION_QUEUE 93
static
struct
chan_queues
usb_queues_tx
[]
=
{
static
struct
chan_queues
am335x_usb_queues_tx
[]
=
{
/* USB0 ENDP 1 */
[
0
]
=
{
.
submit
=
32
,
.
complete
=
93
},
[
1
]
=
{
.
submit
=
34
,
.
complete
=
94
},
...
...
@@ -186,7 +187,7 @@ static struct chan_queues usb_queues_tx[] = {
[
29
]
=
{
.
submit
=
90
,
.
complete
=
139
},
};
static
const
struct
chan_queues
usb_queues_rx
[]
=
{
static
const
struct
chan_queues
am335x_
usb_queues_rx
[]
=
{
/* USB0 ENDP 1 */
[
0
]
=
{
.
submit
=
1
,
.
complete
=
109
},
[
1
]
=
{
.
submit
=
2
,
.
complete
=
110
},
...
...
@@ -222,11 +223,26 @@ static const struct chan_queues usb_queues_rx[] = {
[
29
]
=
{
.
submit
=
30
,
.
complete
=
155
},
};
static
const
struct
chan_queues
da8xx_usb_queues_tx
[]
=
{
[
0
]
=
{
.
submit
=
16
,
.
complete
=
24
},
[
1
]
=
{
.
submit
=
18
,
.
complete
=
24
},
[
2
]
=
{
.
submit
=
20
,
.
complete
=
24
},
[
3
]
=
{
.
submit
=
22
,
.
complete
=
24
},
};
static
const
struct
chan_queues
da8xx_usb_queues_rx
[]
=
{
[
0
]
=
{
.
submit
=
1
,
.
complete
=
26
},
[
1
]
=
{
.
submit
=
3
,
.
complete
=
26
},
[
2
]
=
{
.
submit
=
5
,
.
complete
=
26
},
[
3
]
=
{
.
submit
=
7
,
.
complete
=
26
},
};
struct
cppi_glue_infos
{
irqreturn_t
(
*
isr
)(
int
irq
,
void
*
data
);
const
struct
chan_queues
*
queues_rx
;
const
struct
chan_queues
*
queues_tx
;
struct
chan_queues
td_queue
;
u16
first_completion_queue
;
u16
qmgr_num_pend
;
};
static
struct
cppi41_channel
*
to_cpp41_chan
(
struct
dma_chan
*
c
)
...
...
@@ -285,19 +301,21 @@ static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
static
irqreturn_t
cppi41_irq
(
int
irq
,
void
*
data
)
{
struct
cppi41_dd
*
cdd
=
data
;
u16
first_completion_queue
=
cdd
->
first_completion_queue
;
u16
qmgr_num_pend
=
cdd
->
qmgr_num_pend
;
struct
cppi41_channel
*
c
;
int
i
;
for
(
i
=
QMGR_PENDING_SLOT_Q
(
FIST_COMPLETION_QUEUE
);
i
<
QMGR_NUM_PEND
;
for
(
i
=
QMGR_PENDING_SLOT_Q
(
first_completion_queue
);
i
<
qmgr_num_pend
;
i
++
)
{
u32
val
;
u32
q_num
;
val
=
cppi_readl
(
cdd
->
qmgr_mem
+
QMGR_PEND
(
i
));
if
(
i
==
QMGR_PENDING_SLOT_Q
(
FIST_COMPLETION_QUEUE
)
&&
val
)
{
if
(
i
==
QMGR_PENDING_SLOT_Q
(
first_completion_queue
)
&&
val
)
{
u32
mask
;
/* set corresponding bit for completetion Q 93 */
mask
=
1
<<
QMGR_PENDING_BIT_Q
(
FIST_COMPLETION_QUEUE
);
mask
=
1
<<
QMGR_PENDING_BIT_Q
(
first_completion_queue
);
/* not set all bits for queues less than Q 93 */
mask
--
;
/* now invert and keep only Q 93+ set */
...
...
@@ -402,11 +420,9 @@ static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
struct
cppi41_channel
*
c
=
to_cpp41_chan
(
chan
);
enum
dma_status
ret
;
/* lock */
ret
=
dma_cookie_status
(
chan
,
cookie
,
txstate
);
if
(
txstate
&&
ret
==
DMA_COMPLETE
)
txstate
->
residue
=
c
->
residue
;
/* unlock */
dma_set_residue
(
txstate
,
c
->
residue
);
return
ret
;
}
...
...
@@ -630,7 +646,7 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c)
if
(
!
c
->
is_tx
)
{
reg
|=
GCR_STARV_RETRY
;
reg
|=
GCR_DESC_TYPE_HOST
;
reg
|=
c
->
q_comp_num
;
reg
|=
c
dd
->
td_queue
.
complete
;
}
reg
|=
GCR_TEARDOWN
;
cppi_writel
(
reg
,
c
->
gcr_reg
);
...
...
@@ -641,7 +657,7 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c)
if
(
!
c
->
td_seen
||
!
c
->
td_desc_seen
)
{
desc_phys
=
cppi41_pop_desc
(
cdd
,
cdd
->
td_queue
.
complete
);
if
(
!
desc_phys
)
if
(
!
desc_phys
&&
c
->
is_tx
)
desc_phys
=
cppi41_pop_desc
(
cdd
,
c
->
q_comp_num
);
if
(
desc_phys
==
c
->
desc_phys
)
{
...
...
@@ -723,39 +739,24 @@ static int cppi41_stop_chan(struct dma_chan *chan)
return
0
;
}
static
void
cleanup_chans
(
struct
cppi41_dd
*
cdd
)
{
while
(
!
list_empty
(
&
cdd
->
ddev
.
channels
))
{
struct
cppi41_channel
*
cchan
;
cchan
=
list_first_entry
(
&
cdd
->
ddev
.
channels
,
struct
cppi41_channel
,
chan
.
device_node
);
list_del
(
&
cchan
->
chan
.
device_node
);
kfree
(
cchan
);
}
}
static
int
cppi41_add_chans
(
struct
device
*
dev
,
struct
cppi41_dd
*
cdd
)
{
struct
cppi41_channel
*
cchan
;
struct
cppi41_channel
*
cchan
,
*
chans
;
int
i
;
int
ret
;
u32
n_chans
;
u32
n_chans
=
cdd
->
n_chans
;
ret
=
of_property_read_u32
(
dev
->
of_node
,
"#dma-channels"
,
&
n_chans
);
if
(
ret
)
return
ret
;
/*
* The channels can only be used as TX or as RX. So we add twice
* that much dma channels because USB can only do RX or TX.
*/
n_chans
*=
2
;
chans
=
devm_kcalloc
(
dev
,
n_chans
,
sizeof
(
*
chans
),
GFP_KERNEL
);
if
(
!
chans
)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
n_chans
;
i
++
)
{
cchan
=
kzalloc
(
sizeof
(
*
cchan
),
GFP_KERNEL
);
if
(
!
cchan
)
goto
err
;
cchan
=
&
chans
[
i
];
cchan
->
cdd
=
cdd
;
if
(
i
&
1
)
{
...
...
@@ -775,9 +776,6 @@ static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd)
cdd
->
first_td_desc
=
n_chans
;
return
0
;
err:
cleanup_chans
(
cdd
);
return
-
ENOMEM
;
}
static
void
purge_descs
(
struct
device
*
dev
,
struct
cppi41_dd
*
cdd
)
...
...
@@ -859,7 +857,7 @@ static void init_sched(struct cppi41_dd *cdd)
word
=
0
;
cppi_writel
(
0
,
cdd
->
sched_mem
+
DMA_SCHED_CTRL
);
for
(
ch
=
0
;
ch
<
15
*
2
;
ch
+=
2
)
{
for
(
ch
=
0
;
ch
<
cdd
->
n_chans
;
ch
+=
2
)
{
reg
=
SCHED_ENTRY0_CHAN
(
ch
);
reg
|=
SCHED_ENTRY1_CHAN
(
ch
)
|
SCHED_ENTRY1_IS_RX
;
...
...
@@ -869,7 +867,7 @@ static void init_sched(struct cppi41_dd *cdd)
cppi_writel
(
reg
,
cdd
->
sched_mem
+
DMA_SCHED_WORD
(
word
));
word
++
;
}
reg
=
15
*
2
*
2
-
1
;
reg
=
cdd
->
n_chans
*
2
-
1
;
reg
|=
DMA_SCHED_CTRL_EN
;
cppi_writel
(
reg
,
cdd
->
sched_mem
+
DMA_SCHED_CTRL
);
}
...
...
@@ -885,7 +883,7 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
return
-
ENOMEM
;
cppi_writel
(
cdd
->
scratch_phys
,
cdd
->
qmgr_mem
+
QMGR_LRAM0_BASE
);
cppi_writel
(
QMGR_SCRATCH_SIZE
,
cdd
->
qmgr_mem
+
QMGR_LRAM_SIZE
);
cppi_writel
(
TOTAL_DESCS_NUM
,
cdd
->
qmgr_mem
+
QMGR_LRAM_SIZE
);
cppi_writel
(
0
,
cdd
->
qmgr_mem
+
QMGR_LRAM1_BASE
);
ret
=
init_descs
(
dev
,
cdd
);
...
...
@@ -894,6 +892,7 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
cppi_writel
(
cdd
->
td_queue
.
submit
,
cdd
->
ctrl_mem
+
DMA_TDFDQ
);
init_sched
(
cdd
);
return
0
;
err_td:
deinit_cppi41
(
dev
,
cdd
);
...
...
@@ -933,8 +932,9 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
else
queues
=
cdd
->
queues_rx
;
BUILD_BUG_ON
(
ARRAY_SIZE
(
usb_queues_rx
)
!=
ARRAY_SIZE
(
usb_queues_tx
));
if
(
WARN_ON
(
cchan
->
port_num
>
ARRAY_SIZE
(
usb_queues_rx
)))
BUILD_BUG_ON
(
ARRAY_SIZE
(
am335x_usb_queues_rx
)
!=
ARRAY_SIZE
(
am335x_usb_queues_tx
));
if
(
WARN_ON
(
cchan
->
port_num
>
ARRAY_SIZE
(
am335x_usb_queues_rx
)))
return
false
;
cchan
->
q_num
=
queues
[
cchan
->
port_num
].
submit
;
...
...
@@ -962,15 +962,25 @@ static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
&
dma_spec
->
args
[
0
]);
}
static
const
struct
cppi_glue_infos
usb_infos
=
{
.
isr
=
cppi41_irq
,
.
queues_rx
=
usb_queues_rx
,
.
queues_tx
=
usb_queues_tx
,
static
const
struct
cppi_glue_infos
am335x_usb_infos
=
{
.
queues_rx
=
am335x_usb_queues_rx
,
.
queues_tx
=
am335x_usb_queues_tx
,
.
td_queue
=
{
.
submit
=
31
,
.
complete
=
0
},
.
first_completion_queue
=
93
,
.
qmgr_num_pend
=
5
,
};
static
const
struct
cppi_glue_infos
da8xx_usb_infos
=
{
.
queues_rx
=
da8xx_usb_queues_rx
,
.
queues_tx
=
da8xx_usb_queues_tx
,
.
td_queue
=
{
.
submit
=
31
,
.
complete
=
0
},
.
first_completion_queue
=
24
,
.
qmgr_num_pend
=
2
,
};
static
const
struct
of_device_id
cppi41_dma_ids
[]
=
{
{
.
compatible
=
"ti,am3359-cppi41"
,
.
data
=
&
usb_infos
},
{
.
compatible
=
"ti,am3359-cppi41"
,
.
data
=
&
am335x_usb_infos
},
{
.
compatible
=
"ti,da830-cppi41"
,
.
data
=
&
da8xx_usb_infos
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
cppi41_dma_ids
);
...
...
@@ -995,6 +1005,8 @@ static int cppi41_dma_probe(struct platform_device *pdev)
struct
cppi41_dd
*
cdd
;
struct
device
*
dev
=
&
pdev
->
dev
;
const
struct
cppi_glue_infos
*
glue_info
;
struct
resource
*
mem
;
int
index
;
int
irq
;
int
ret
;
...
...
@@ -1021,19 +1033,31 @@ static int cppi41_dma_probe(struct platform_device *pdev)
INIT_LIST_HEAD
(
&
cdd
->
ddev
.
channels
);
cpp41_dma_info
.
dma_cap
=
cdd
->
ddev
.
cap_mask
;
cdd
->
usbss_mem
=
of_iomap
(
dev
->
of_node
,
0
);
cdd
->
ctrl_mem
=
of_iomap
(
dev
->
of_node
,
1
);
cdd
->
sched_mem
=
of_iomap
(
dev
->
of_node
,
2
);
cdd
->
qmgr_mem
=
of_iomap
(
dev
->
of_node
,
3
);
index
=
of_property_match_string
(
dev
->
of_node
,
"reg-names"
,
"controller"
);
if
(
index
<
0
)
return
index
;
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
index
);
cdd
->
ctrl_mem
=
devm_ioremap_resource
(
dev
,
mem
);
if
(
IS_ERR
(
cdd
->
ctrl_mem
))
return
PTR_ERR
(
cdd
->
ctrl_mem
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
index
+
1
);
cdd
->
sched_mem
=
devm_ioremap_resource
(
dev
,
mem
);
if
(
IS_ERR
(
cdd
->
sched_mem
))
return
PTR_ERR
(
cdd
->
sched_mem
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
index
+
2
);
cdd
->
qmgr_mem
=
devm_ioremap_resource
(
dev
,
mem
);
if
(
IS_ERR
(
cdd
->
qmgr_mem
))
return
PTR_ERR
(
cdd
->
qmgr_mem
);
spin_lock_init
(
&
cdd
->
lock
);
INIT_LIST_HEAD
(
&
cdd
->
pending
);
platform_set_drvdata
(
pdev
,
cdd
);
if
(
!
cdd
->
usbss_mem
||
!
cdd
->
ctrl_mem
||
!
cdd
->
sched_mem
||
!
cdd
->
qmgr_mem
)
return
-
ENXIO
;
pm_runtime_enable
(
dev
);
pm_runtime_set_autosuspend_delay
(
dev
,
100
);
pm_runtime_use_autosuspend
(
dev
);
...
...
@@ -1044,6 +1068,13 @@ static int cppi41_dma_probe(struct platform_device *pdev)
cdd
->
queues_rx
=
glue_info
->
queues_rx
;
cdd
->
queues_tx
=
glue_info
->
queues_tx
;
cdd
->
td_queue
=
glue_info
->
td_queue
;
cdd
->
qmgr_num_pend
=
glue_info
->
qmgr_num_pend
;
cdd
->
first_completion_queue
=
glue_info
->
first_completion_queue
;
ret
=
of_property_read_u32
(
dev
->
of_node
,
"#dma-channels"
,
&
cdd
->
n_chans
);
if
(
ret
)
goto
err_get_n_chans
;
ret
=
init_cppi41
(
dev
,
cdd
);
if
(
ret
)
...
...
@@ -1056,18 +1087,18 @@ static int cppi41_dma_probe(struct platform_device *pdev)
irq
=
irq_of_parse_and_map
(
dev
->
of_node
,
0
);
if
(
!
irq
)
{
ret
=
-
EINVAL
;
goto
err_
irq
;
goto
err_
chans
;
}
ret
=
devm_request_irq
(
&
pdev
->
dev
,
irq
,
glue_info
->
isr
,
IRQF_SHARED
,
ret
=
devm_request_irq
(
&
pdev
->
dev
,
irq
,
cppi41_irq
,
IRQF_SHARED
,
dev_name
(
dev
),
cdd
);
if
(
ret
)
goto
err_
irq
;
goto
err_
chans
;
cdd
->
irq
=
irq
;
ret
=
dma_async_device_register
(
&
cdd
->
ddev
);
if
(
ret
)
goto
err_
dma_reg
;
goto
err_
chans
;
ret
=
of_dma_controller_register
(
dev
->
of_node
,
cppi41_dma_xlate
,
&
cpp41_dma_info
);
...
...
@@ -1080,20 +1111,14 @@ static int cppi41_dma_probe(struct platform_device *pdev)
return
0
;
err_of:
dma_async_device_unregister
(
&
cdd
->
ddev
);
err_dma_reg:
err_irq:
cleanup_chans
(
cdd
);
err_chans:
deinit_cppi41
(
dev
,
cdd
);
err_init_cppi:
pm_runtime_dont_use_autosuspend
(
dev
);
err_get_n_chans:
err_get_sync:
pm_runtime_put_sync
(
dev
);
pm_runtime_disable
(
dev
);
iounmap
(
cdd
->
usbss_mem
);
iounmap
(
cdd
->
ctrl_mem
);
iounmap
(
cdd
->
sched_mem
);
iounmap
(
cdd
->
qmgr_mem
);
return
ret
;
}
...
...
@@ -1110,12 +1135,7 @@ static int cppi41_dma_remove(struct platform_device *pdev)
dma_async_device_unregister
(
&
cdd
->
ddev
);
devm_free_irq
(
&
pdev
->
dev
,
cdd
->
irq
,
cdd
);
cleanup_chans
(
cdd
);
deinit_cppi41
(
&
pdev
->
dev
,
cdd
);
iounmap
(
cdd
->
usbss_mem
);
iounmap
(
cdd
->
ctrl_mem
);
iounmap
(
cdd
->
sched_mem
);
iounmap
(
cdd
->
qmgr_mem
);
pm_runtime_dont_use_autosuspend
(
&
pdev
->
dev
);
pm_runtime_put_sync
(
&
pdev
->
dev
);
pm_runtime_disable
(
&
pdev
->
dev
);
...
...
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