Merge branch 'topic/cppi' into for-linus
This commit is contained in:
commit
f23514b101
|
@ -18,10 +18,26 @@ Required properties:
|
||||||
|
|
||||||
- phy-names: Should be "usb-phy"
|
- 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:
|
Optional properties:
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
- vbus-supply: Phandle to a regulator providing the USB bus power.
|
- 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:
|
Example:
|
||||||
usb_phy: usb-phy {
|
usb_phy: usb-phy {
|
||||||
compatible = "ti,da830-usb-phy";
|
compatible = "ti,da830-usb-phy";
|
||||||
|
@ -30,7 +46,10 @@ Example:
|
||||||
};
|
};
|
||||||
usb0: usb@200000 {
|
usb0: usb@200000 {
|
||||||
compatible = "ti,da830-musb";
|
compatible = "ti,da830-musb";
|
||||||
reg = <0x00200000 0x10000>;
|
reg = <0x00200000 0x1000>;
|
||||||
|
ranges;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
interrupts = <58>;
|
interrupts = <58>;
|
||||||
interrupt-names = "mc";
|
interrupt-names = "mc";
|
||||||
|
|
||||||
|
@ -39,5 +58,25 @@ Example:
|
||||||
phys = <&usb_phy 0>;
|
phys = <&usb_phy 0>;
|
||||||
phy-names = "usb-phy";
|
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";
|
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>;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -514,12 +514,12 @@ config TIMB_DMA
|
||||||
Enable support for the Timberdale FPGA DMA engine.
|
Enable support for the Timberdale FPGA DMA engine.
|
||||||
|
|
||||||
config TI_CPPI41
|
config TI_CPPI41
|
||||||
tristate "AM33xx CPPI41 DMA support"
|
tristate "CPPI 4.1 DMA support"
|
||||||
depends on ARCH_OMAP
|
depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX)
|
||||||
select DMA_ENGINE
|
select DMA_ENGINE
|
||||||
help
|
help
|
||||||
The Communications Port Programming Interface (CPPI) 4.1 DMA engine
|
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
|
config TI_DMA_CROSSBAR
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
#define QMGR_MEMCTRL_IDX_SH 16
|
#define QMGR_MEMCTRL_IDX_SH 16
|
||||||
#define QMGR_MEMCTRL_DESC_SH 8
|
#define QMGR_MEMCTRL_DESC_SH 8
|
||||||
|
|
||||||
#define QMGR_NUM_PEND 5
|
|
||||||
#define QMGR_PEND(x) (0x90 + (x) * 4)
|
#define QMGR_PEND(x) (0x90 + (x) * 4)
|
||||||
|
|
||||||
#define QMGR_PENDING_SLOT_Q(x) (x / 32)
|
#define QMGR_PENDING_SLOT_Q(x) (x / 32)
|
||||||
|
@ -131,7 +130,6 @@ struct cppi41_dd {
|
||||||
u32 first_td_desc;
|
u32 first_td_desc;
|
||||||
struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
|
struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
|
||||||
|
|
||||||
void __iomem *usbss_mem;
|
|
||||||
void __iomem *ctrl_mem;
|
void __iomem *ctrl_mem;
|
||||||
void __iomem *sched_mem;
|
void __iomem *sched_mem;
|
||||||
void __iomem *qmgr_mem;
|
void __iomem *qmgr_mem;
|
||||||
|
@ -139,6 +137,10 @@ struct cppi41_dd {
|
||||||
const struct chan_queues *queues_rx;
|
const struct chan_queues *queues_rx;
|
||||||
const struct chan_queues *queues_tx;
|
const struct chan_queues *queues_tx;
|
||||||
struct chan_queues td_queue;
|
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 */
|
struct list_head pending; /* Pending queued transfers */
|
||||||
spinlock_t lock; /* Lock for pending list */
|
spinlock_t lock; /* Lock for pending list */
|
||||||
|
@ -149,8 +151,7 @@ struct cppi41_dd {
|
||||||
bool is_suspended;
|
bool is_suspended;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FIST_COMPLETION_QUEUE 93
|
static struct chan_queues am335x_usb_queues_tx[] = {
|
||||||
static struct chan_queues usb_queues_tx[] = {
|
|
||||||
/* USB0 ENDP 1 */
|
/* USB0 ENDP 1 */
|
||||||
[ 0] = { .submit = 32, .complete = 93},
|
[ 0] = { .submit = 32, .complete = 93},
|
||||||
[ 1] = { .submit = 34, .complete = 94},
|
[ 1] = { .submit = 34, .complete = 94},
|
||||||
|
@ -186,7 +187,7 @@ static struct chan_queues usb_queues_tx[] = {
|
||||||
[29] = { .submit = 90, .complete = 139},
|
[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 */
|
/* USB0 ENDP 1 */
|
||||||
[ 0] = { .submit = 1, .complete = 109},
|
[ 0] = { .submit = 1, .complete = 109},
|
||||||
[ 1] = { .submit = 2, .complete = 110},
|
[ 1] = { .submit = 2, .complete = 110},
|
||||||
|
@ -222,11 +223,26 @@ static const struct chan_queues usb_queues_rx[] = {
|
||||||
[29] = { .submit = 30, .complete = 155},
|
[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 {
|
struct cppi_glue_infos {
|
||||||
irqreturn_t (*isr)(int irq, void *data);
|
|
||||||
const struct chan_queues *queues_rx;
|
const struct chan_queues *queues_rx;
|
||||||
const struct chan_queues *queues_tx;
|
const struct chan_queues *queues_tx;
|
||||||
struct chan_queues td_queue;
|
struct chan_queues td_queue;
|
||||||
|
u16 first_completion_queue;
|
||||||
|
u16 qmgr_num_pend;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
|
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)
|
static irqreturn_t cppi41_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct cppi41_dd *cdd = 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;
|
struct cppi41_channel *c;
|
||||||
int i;
|
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++) {
|
i++) {
|
||||||
u32 val;
|
u32 val;
|
||||||
u32 q_num;
|
u32 q_num;
|
||||||
|
|
||||||
val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
|
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;
|
u32 mask;
|
||||||
/* set corresponding bit for completetion Q 93 */
|
/* 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 */
|
/* not set all bits for queues less than Q 93 */
|
||||||
mask--;
|
mask--;
|
||||||
/* now invert and keep only Q 93+ set */
|
/* 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);
|
struct cppi41_channel *c = to_cpp41_chan(chan);
|
||||||
enum dma_status ret;
|
enum dma_status ret;
|
||||||
|
|
||||||
/* lock */
|
|
||||||
ret = dma_cookie_status(chan, cookie, txstate);
|
ret = dma_cookie_status(chan, cookie, txstate);
|
||||||
if (txstate && ret == DMA_COMPLETE)
|
|
||||||
txstate->residue = c->residue;
|
dma_set_residue(txstate, c->residue);
|
||||||
/* unlock */
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -630,7 +646,7 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c)
|
||||||
if (!c->is_tx) {
|
if (!c->is_tx) {
|
||||||
reg |= GCR_STARV_RETRY;
|
reg |= GCR_STARV_RETRY;
|
||||||
reg |= GCR_DESC_TYPE_HOST;
|
reg |= GCR_DESC_TYPE_HOST;
|
||||||
reg |= c->q_comp_num;
|
reg |= cdd->td_queue.complete;
|
||||||
}
|
}
|
||||||
reg |= GCR_TEARDOWN;
|
reg |= GCR_TEARDOWN;
|
||||||
cppi_writel(reg, c->gcr_reg);
|
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) {
|
if (!c->td_seen || !c->td_desc_seen) {
|
||||||
|
|
||||||
desc_phys = cppi41_pop_desc(cdd, cdd->td_queue.complete);
|
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);
|
desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
|
||||||
|
|
||||||
if (desc_phys == c->desc_phys) {
|
if (desc_phys == c->desc_phys) {
|
||||||
|
@ -723,39 +739,24 @@ static int cppi41_stop_chan(struct dma_chan *chan)
|
||||||
return 0;
|
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)
|
static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd)
|
||||||
{
|
{
|
||||||
struct cppi41_channel *cchan;
|
struct cppi41_channel *cchan, *chans;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
u32 n_chans = cdd->n_chans;
|
||||||
u32 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
|
* 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.
|
* that much dma channels because USB can only do RX or TX.
|
||||||
*/
|
*/
|
||||||
n_chans *= 2;
|
n_chans *= 2;
|
||||||
|
|
||||||
|
chans = devm_kcalloc(dev, n_chans, sizeof(*chans), GFP_KERNEL);
|
||||||
|
if (!chans)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < n_chans; i++) {
|
for (i = 0; i < n_chans; i++) {
|
||||||
cchan = kzalloc(sizeof(*cchan), GFP_KERNEL);
|
cchan = &chans[i];
|
||||||
if (!cchan)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
cchan->cdd = cdd;
|
cchan->cdd = cdd;
|
||||||
if (i & 1) {
|
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;
|
cdd->first_td_desc = n_chans;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
|
||||||
cleanup_chans(cdd);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void purge_descs(struct device *dev, struct cppi41_dd *cdd)
|
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;
|
word = 0;
|
||||||
cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
|
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_ENTRY0_CHAN(ch);
|
||||||
reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
|
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));
|
cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
|
||||||
word++;
|
word++;
|
||||||
}
|
}
|
||||||
reg = 15 * 2 * 2 - 1;
|
reg = cdd->n_chans * 2 - 1;
|
||||||
reg |= DMA_SCHED_CTRL_EN;
|
reg |= DMA_SCHED_CTRL_EN;
|
||||||
cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
|
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;
|
return -ENOMEM;
|
||||||
|
|
||||||
cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
|
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);
|
cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
|
||||||
|
|
||||||
ret = init_descs(dev, cdd);
|
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);
|
cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
|
||||||
init_sched(cdd);
|
init_sched(cdd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_td:
|
err_td:
|
||||||
deinit_cppi41(dev, cdd);
|
deinit_cppi41(dev, cdd);
|
||||||
|
@ -933,8 +932,9 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
|
||||||
else
|
else
|
||||||
queues = cdd->queues_rx;
|
queues = cdd->queues_rx;
|
||||||
|
|
||||||
BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx));
|
BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) !=
|
||||||
if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx)))
|
ARRAY_SIZE(am335x_usb_queues_tx));
|
||||||
|
if (WARN_ON(cchan->port_num > ARRAY_SIZE(am335x_usb_queues_rx)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cchan->q_num = queues[cchan->port_num].submit;
|
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]);
|
&dma_spec->args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cppi_glue_infos usb_infos = {
|
static const struct cppi_glue_infos am335x_usb_infos = {
|
||||||
.isr = cppi41_irq,
|
.queues_rx = am335x_usb_queues_rx,
|
||||||
.queues_rx = usb_queues_rx,
|
.queues_tx = am335x_usb_queues_tx,
|
||||||
.queues_tx = usb_queues_tx,
|
|
||||||
.td_queue = { .submit = 31, .complete = 0 },
|
.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[] = {
|
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);
|
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 cppi41_dd *cdd;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct cppi_glue_infos *glue_info;
|
const struct cppi_glue_infos *glue_info;
|
||||||
|
struct resource *mem;
|
||||||
|
int index;
|
||||||
int irq;
|
int irq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1021,19 +1033,31 @@ static int cppi41_dma_probe(struct platform_device *pdev)
|
||||||
INIT_LIST_HEAD(&cdd->ddev.channels);
|
INIT_LIST_HEAD(&cdd->ddev.channels);
|
||||||
cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
|
cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
|
||||||
|
|
||||||
cdd->usbss_mem = of_iomap(dev->of_node, 0);
|
index = of_property_match_string(dev->of_node,
|
||||||
cdd->ctrl_mem = of_iomap(dev->of_node, 1);
|
"reg-names", "controller");
|
||||||
cdd->sched_mem = of_iomap(dev->of_node, 2);
|
if (index < 0)
|
||||||
cdd->qmgr_mem = of_iomap(dev->of_node, 3);
|
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);
|
spin_lock_init(&cdd->lock);
|
||||||
INIT_LIST_HEAD(&cdd->pending);
|
INIT_LIST_HEAD(&cdd->pending);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, cdd);
|
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_enable(dev);
|
||||||
pm_runtime_set_autosuspend_delay(dev, 100);
|
pm_runtime_set_autosuspend_delay(dev, 100);
|
||||||
pm_runtime_use_autosuspend(dev);
|
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_rx = glue_info->queues_rx;
|
||||||
cdd->queues_tx = glue_info->queues_tx;
|
cdd->queues_tx = glue_info->queues_tx;
|
||||||
cdd->td_queue = glue_info->td_queue;
|
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);
|
ret = init_cppi41(dev, cdd);
|
||||||
if (ret)
|
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);
|
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||||
if (!irq) {
|
if (!irq) {
|
||||||
ret = -EINVAL;
|
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);
|
dev_name(dev), cdd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_irq;
|
goto err_chans;
|
||||||
cdd->irq = irq;
|
cdd->irq = irq;
|
||||||
|
|
||||||
ret = dma_async_device_register(&cdd->ddev);
|
ret = dma_async_device_register(&cdd->ddev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_dma_reg;
|
goto err_chans;
|
||||||
|
|
||||||
ret = of_dma_controller_register(dev->of_node,
|
ret = of_dma_controller_register(dev->of_node,
|
||||||
cppi41_dma_xlate, &cpp41_dma_info);
|
cppi41_dma_xlate, &cpp41_dma_info);
|
||||||
|
@ -1080,20 +1111,14 @@ static int cppi41_dma_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
err_of:
|
err_of:
|
||||||
dma_async_device_unregister(&cdd->ddev);
|
dma_async_device_unregister(&cdd->ddev);
|
||||||
err_dma_reg:
|
|
||||||
err_irq:
|
|
||||||
cleanup_chans(cdd);
|
|
||||||
err_chans:
|
err_chans:
|
||||||
deinit_cppi41(dev, cdd);
|
deinit_cppi41(dev, cdd);
|
||||||
err_init_cppi:
|
err_init_cppi:
|
||||||
pm_runtime_dont_use_autosuspend(dev);
|
pm_runtime_dont_use_autosuspend(dev);
|
||||||
|
err_get_n_chans:
|
||||||
err_get_sync:
|
err_get_sync:
|
||||||
pm_runtime_put_sync(dev);
|
pm_runtime_put_sync(dev);
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
iounmap(cdd->usbss_mem);
|
|
||||||
iounmap(cdd->ctrl_mem);
|
|
||||||
iounmap(cdd->sched_mem);
|
|
||||||
iounmap(cdd->qmgr_mem);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,12 +1135,7 @@ static int cppi41_dma_remove(struct platform_device *pdev)
|
||||||
dma_async_device_unregister(&cdd->ddev);
|
dma_async_device_unregister(&cdd->ddev);
|
||||||
|
|
||||||
devm_free_irq(&pdev->dev, cdd->irq, cdd);
|
devm_free_irq(&pdev->dev, cdd->irq, cdd);
|
||||||
cleanup_chans(cdd);
|
|
||||||
deinit_cppi41(&pdev->dev, 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_dont_use_autosuspend(&pdev->dev);
|
||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
Loading…
Reference in New Issue