Hello,
this series contains support for the two available MUSB instances on
AM335x and DMA support. I added dma support at the end since it depends on
the rework to support multiple instances.
Patch two "still" extends the phy-nop driver since I have to dump it
somewhere. I have no problems to replace it with George Cherian PHY driver
which was posted earlier. Infact I will to try to review it and integrate
it into my series if it fits.
The whole series is also available at
git://git.breakpoint.cc/bigeasy/linux.git am335x_usb
Sebastian
If the init / shutdown function of the phy moves out of dsps into the
phy driver, then dsps needs to call the callbacks of the phy driver to
ensure that this happens.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 5233804..603ea74 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -428,6 +428,8 @@ static int dsps_musb_init(struct musb *musb)
goto err0;
}
+ usb_phy_init(musb->xceiv);
+
setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
/* Reset the musb */
@@ -463,6 +465,7 @@ static int dsps_musb_exit(struct musb *musb)
/* Shutdown the on-chip PHY and its PLL. */
musb_dsps_phy_control(glue, pdev->id, 0);
+ usb_phy_shutdown(musb->xceiv);
/* NOP driver needs change if supporting dual instance */
usb_put_phy(musb->xceiv);
--
1.8.3.2
ti81xx does not have a baseport mainline i.e. it should not boot. The
amount of rework that is required makes it easier to simply remove that
platform (i.e. that possible platform device) and add it later once it
comes back with DT support.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index ab723fa..1440fac 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -46,9 +46,7 @@
#include "musb_core.h"
-#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[];
-#endif
/**
* avoid using musb_readx()/musb_writex() as glue layer should not be
@@ -659,23 +657,12 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
.instances = 1,
};
-static const struct platform_device_id musb_dsps_id_table[] = {
- {
- .name = "musb-ti81xx",
- .driver_data = (kernel_ulong_t) &ti81xx_driver_data,
- },
- { }, /* Terminating Entry */
-};
-MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
-
-#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[] = {
{ .compatible = "ti,musb-am33xx",
.data = (void *) &ti81xx_driver_data, },
{ },
};
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
-#endif
static struct platform_driver dsps_usbss_driver = {
.probe = dsps_probe,
@@ -684,7 +671,6 @@ static struct platform_driver dsps_usbss_driver = {
.name = "musb-dsps",
.of_match_table = of_match_ptr(musb_dsps_of_match),
},
- .id_table = musb_dsps_id_table,
};
MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
--
1.8.3.2
The core code creates a controller and immediately after that it calls
the ->start() callback. This one might drop an error but nobody cares.
The same thing happens in the destroy corner: First ->stop() called
followed by destroy callback. So why not merge those two into the same
function since there is no difference.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/cppi_dma.c | 18 +++++-------------
drivers/usb/musb/musb_core.c | 18 ++++--------------
drivers/usb/musb/musb_dma.h | 2 --
drivers/usb/musb/musbhsdma.c | 16 +++-------------
drivers/usb/musb/tusb6010_omap.c | 24 ------------------------
drivers/usb/musb/ux500_dma.c | 19 ++++++++-----------
6 files changed, 20 insertions(+), 77 deletions(-)
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 9db211e..904fb85 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -150,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c)
c->last_processed = NULL;
}
-static int cppi_controller_start(struct dma_controller *c)
+static void cppi_controller_start(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
- controller = container_of(c, struct cppi, controller);
-
/* do whatever is necessary to start controller */
for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
controller->tx[i].transmit = true;
@@ -212,8 +209,6 @@ static int cppi_controller_start(struct dma_controller *c)
/* disable RNDIS mode, also host rx RNDIS autorequest */
musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-
- return 0;
}
/*
@@ -222,14 +217,12 @@ static int cppi_controller_start(struct dma_controller *c)
* De-Init the DMA controller as necessary.
*/
-static int cppi_controller_stop(struct dma_controller *c)
+static void cppi_controller_stop(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
struct musb *musb;
- controller = container_of(c, struct cppi, controller);
musb = controller->musb;
tibase = controller->tibase;
@@ -255,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c)
/*disable tx/rx cppi */
musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-
- return 0;
}
/* While dma channel is allocated, we only want the core irqs active
@@ -1321,8 +1312,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
controller->tibase = mregs - DAVINCI_BASE_OFFSET;
controller->musb = musb;
- controller->controller.start = cppi_controller_start;
- controller->controller.stop = cppi_controller_stop;
controller->controller.channel_alloc = cppi_channel_allocate;
controller->controller.channel_release = cppi_channel_release;
controller->controller.channel_program = cppi_channel_program;
@@ -1351,6 +1340,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
controller->irq = irq;
}
+ cppi_controller_start(controller);
return &controller->controller;
}
@@ -1363,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c)
cppi = container_of(c, struct cppi, controller);
+ cppi_controller_stop(cppi);
+
if (cppi->irq)
free_irq(cppi->irq, cppi->musb);
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 29a24ce..a4434d2 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1764,12 +1764,8 @@ static void musb_free(struct musb *musb)
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
- if (is_dma_capable() && musb->dma_controller) {
- struct dma_controller *c = musb->dma_controller;
-
- (void) c->stop(c);
- dma_controller_destroy(c);
- }
+ if (is_dma_capable() && musb->dma_controller)
+ dma_controller_destroy(musb->dma_controller);
musb_host_free(musb);
}
@@ -1845,14 +1841,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_get_sync(musb->controller);
#ifndef CONFIG_MUSB_PIO_ONLY
- if (use_dma && dev->dma_mask) {
- struct dma_controller *c;
-
- c = dma_controller_create(musb, musb->mregs);
- musb->dma_controller = c;
- if (c)
- (void) c->start(c);
- }
+ if (use_dma && dev->dma_mask)
+ musb->dma_controller = dma_controller_create(musb, musb->mregs);
#endif
/* ideally this would be abstracted in platform setup */
if (!is_dma_capable() || !musb->dma_controller)
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 8919ce2..3603711 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c)
* Controllers manage dma channels.
*/
struct dma_controller {
- int (*start)(struct dma_controller *);
- int (*stop)(struct dma_controller *);
struct dma_channel *(*channel_alloc)(struct dma_controller *,
struct musb_hw_ep *, u8 is_tx);
void (*channel_release)(struct dma_channel *);
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 3d1fd52..092cedf 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -37,18 +37,10 @@
#include "musb_core.h"
#include "musbhsdma.h"
-static int dma_controller_start(struct dma_controller *c)
-{
- /* nothing to do */
- return 0;
-}
-
static void dma_channel_release(struct dma_channel *channel);
-static int dma_controller_stop(struct dma_controller *c)
+static void dma_controller_stop(struct musb_dma_controller *controller)
{
- struct musb_dma_controller *controller = container_of(c,
- struct musb_dma_controller, controller);
struct musb *musb = controller->private_data;
struct dma_channel *channel;
u8 bit;
@@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c)
}
}
}
-
- return 0;
}
static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
@@ -374,6 +364,8 @@ void dma_controller_destroy(struct dma_controller *c)
if (!controller)
return;
+ dma_controller_stop(controller);
+
if (controller->irq)
free_irq(controller->irq, c);
@@ -400,8 +392,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller->private_data = musb;
controller->base = base;
- controller->controller.start = dma_controller_start;
- controller->controller.stop = dma_controller_stop;
controller->controller.channel_alloc = dma_channel_allocate;
controller->controller.channel_release = dma_channel_release;
controller->controller.channel_program = dma_channel_program;
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 98df17c..b8794eb 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -66,28 +66,6 @@ struct tusb_omap_dma {
unsigned multichannel:1;
};
-static int tusb_omap_dma_start(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
-static int tusb_omap_dma_stop(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
/*
* Allocate dmareq0 to the current channel unless it's already taken
*/
@@ -695,8 +673,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
tusb_dma->dmareq = -1;
tusb_dma->sync_dev = -1;
- tusb_dma->controller.start = tusb_omap_dma_start;
- tusb_dma->controller.stop = tusb_omap_dma_stop;
tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
tusb_dma->controller.channel_release = tusb_omap_dma_release;
tusb_dma->controller.channel_program = tusb_omap_dma_program;
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index bfb7a65..1ce214e 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -254,10 +254,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
return 0;
}
-static int ux500_dma_controller_stop(struct dma_controller *c)
+static void ux500_dma_controller_stop(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel;
struct dma_channel *channel;
u8 ch_num;
@@ -281,14 +279,10 @@ static int ux500_dma_controller_stop(struct dma_controller *c)
if (ux500_channel->dma_chan)
dma_release_channel(ux500_channel->dma_chan);
}
-
- return 0;
}
-static int ux500_dma_controller_start(struct dma_controller *c)
+static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel = NULL;
struct musb *musb = controller->private_data;
struct device *dev = musb->controller;
@@ -347,7 +341,7 @@ static int ux500_dma_controller_start(struct dma_controller *c)
dir, ch_num);
/* Release already allocated channels */
- ux500_dma_controller_stop(c);
+ ux500_dma_controller_stop(controller);
return -EBUSY;
}
@@ -369,6 +363,7 @@ void dma_controller_destroy(struct dma_controller *c)
struct ux500_dma_controller *controller = container_of(c,
struct ux500_dma_controller, controller);
+ ux500_dma_controller_stop(controller);
kfree(controller);
}
@@ -378,6 +373,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,
struct ux500_dma_controller *controller;
struct platform_device *pdev = to_platform_device(musb->controller);
struct resource *iomem;
+ int ret;
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
@@ -394,14 +390,15 @@ struct dma_controller *dma_controller_create(struct musb *musb,
controller->phy_base = (dma_addr_t) iomem->start;
- controller->controller.start = ux500_dma_controller_start;
- controller->controller.stop = ux500_dma_controller_stop;
controller->controller.channel_alloc = ux500_dma_channel_allocate;
controller->controller.channel_release = ux500_dma_channel_release;
controller->controller.channel_program = ux500_dma_channel_program;
controller->controller.channel_abort = ux500_dma_channel_abort;
controller->controller.is_compatible = ux500_dma_is_compatible;
+ ret = ux500_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
return &controller->controller;
plat_get_fail:
--
1.8.3.2
Add a dma_controller_create() returning NULL so a few ifdefs can
dropped.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dma.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 3603711..c8e67fd 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -175,9 +175,20 @@ struct dma_controller {
/* called after channel_program(), may indicate a fault */
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
+#ifdef CONFIG_MUSB_PIO_ONLY
+static inline struct dma_controller *dma_controller_create(struct musb *m,
+ void __iomem *io)
+{
+ return NULL;
+}
+
+static inline void dma_controller_destroy(struct dma_controller *d) { }
+
+#else
extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
extern void dma_controller_destroy(struct dma_controller *);
+#endif
#endif /* __MUSB_DMA_H__ */
--
1.8.3.2
The ifdef reads somehow better than an ifndef
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dma.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 1b6b827..8919ce2 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -62,10 +62,10 @@ struct musb_hw_ep;
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#ifndef CONFIG_MUSB_PIO_ONLY
-#define is_dma_capable() (1)
-#else
+#ifdef CONFIG_MUSB_PIO_ONLY
#define is_dma_capable() (0)
+#else
+#define is_dma_capable() (1)
#endif
#ifdef CONFIG_USB_TI_CPPI_DMA
--
1.8.3.2
This patch adds the MUSB_DEVCTL_SESSION back after it has been removed.
If it is missing then the host session is not recognized. This bit is
added initially added in musb_start() and removed after the first device
disconnect.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 2e45723..1a2b163 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -186,6 +186,9 @@ static void otg_timer(unsigned long _musb)
dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
+ devctl |= MUSB_DEVCTL_SESSION;
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
if (devctl & MUSB_DEVCTL_BDEVICE) {
musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
--
1.8.3.2
If the descriptor is missing the reqeust is never unmapped. This patch
changes this and renames the cleanup label to unlock since there is no
cleanup done. The cleanup would revert the allocation of ressource (i.e.
this dma mapping) but it does not, it simply unlocks and returns.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_gadget.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 0414bc1..96632f9 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1266,7 +1266,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
req, ep->name, "disabled");
status = -ESHUTDOWN;
- goto cleanup;
+ unmap_dma_buffer(request, musb);
+ goto unlock;
}
/* add request to the list */
@@ -1276,7 +1277,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
musb_ep_restart(musb, request);
-cleanup:
+unlock:
spin_unlock_irqrestore(&musb->lock, lockflags);
return status;
}
--
1.8.3.2
Commit 8d2421e ("usb: musb: kill global and static for multi instance")
removed the global dma_mask copy and replaced by parent's DMA mask. The
problem here is that if the parent does not have a dma_mask then
musb_remove() goes kaboom.
Instead trying to fix this I was thinking we do we need to erase
dma_mask in the first place?
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_core.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 9b774e7..80ffd7e 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1843,10 +1843,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (use_dma && dev->dma_mask)
musb->dma_controller = dma_controller_create(musb, musb->mregs);
- /* ideally this would be abstracted in platform setup */
- if (!musb->dma_controller)
- dev->dma_mask = NULL;
-
/* be sure interrupts are disabled before connecting ISR */
musb_platform_disable(musb);
musb_generic_disable(musb);
@@ -1993,9 +1989,6 @@ static int musb_remove(struct platform_device *pdev)
musb_free(musb);
device_init_wakeup(dev, 0);
-#ifndef CONFIG_MUSB_PIO_ONLY
- dma_set_mask(dev, *dev->parent->dma_mask);
-#endif
return 0;
}
--
1.8.3.2
The cleanup in the error is missing the dma controller. The structure is
allocated at runtime and ux500 allocates even a little more than just
this struct. So cleanup!
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index b33bed5..9b774e7 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1933,6 +1933,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_gadget_cleanup(musb);
fail3:
+ if (musb->dma_controller)
+ dma_controller_destroy(musb->dma_controller);
pm_runtime_put_sync(musb->controller);
fail2:
--
1.8.3.2
This patch removes is_dma_capable() and an ifdef in the init/exit path
around init/de-init of the dma_controller. Since we have the empty stubs
in the PIO code we can call it without gcc trouble. Earlier we had an
ifdef and the is_dma_capable() macro where gcc ignored the if (0) path
even that the function was not around :)
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_core.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index a4434d2..b33bed5 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1764,7 +1764,7 @@ static void musb_free(struct musb *musb)
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
- if (is_dma_capable() && musb->dma_controller)
+ if (musb->dma_controller)
dma_controller_destroy(musb->dma_controller);
musb_host_free(musb);
@@ -1840,12 +1840,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_get_sync(musb->controller);
-#ifndef CONFIG_MUSB_PIO_ONLY
if (use_dma && dev->dma_mask)
musb->dma_controller = dma_controller_create(musb, musb->mregs);
-#endif
+
/* ideally this would be abstracted in platform setup */
- if (!is_dma_capable() || !musb->dma_controller)
+ if (!musb->dma_controller)
dev->dma_mask = NULL;
/* be sure interrupts are disabled before connecting ISR */
--
1.8.3.2
This driver is currently used by musb' cppi41 couter part. I may merge
both dma engine user of musb at some point but not just yet.
The driver seems to work in RX/TX mode. Canceling of transfer is missing
haven't noticed any problems so far.
v1..v2:
- RX path added
- dma mode 0 & 1 is working
- device tree nodes re-created.
Cc: Vinod Koul <[email protected]>
Cc: Dan Williams <[email protected]>
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
arch/arm/boot/dts/am335x-evm.dts | 4 +
arch/arm/boot/dts/am33xx.dtsi | 61 +++
drivers/dma/Kconfig | 8 +
drivers/dma/Makefile | 1 +
drivers/dma/cppi41.c | 911 +++++++++++++++++++++++++++++++++++++++
drivers/usb/musb/Kconfig | 4 +
drivers/usb/musb/Makefile | 1 +
drivers/usb/musb/musb_cppi41.c | 433 +++++++++++++++++++
drivers/usb/musb/musb_dma.h | 2 +-
9 files changed, 1424 insertions(+), 1 deletion(-)
create mode 100644 drivers/dma/cppi41.c
create mode 100644 drivers/usb/musb/musb_cppi41.c
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index a3a642a..d71ca92 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -189,6 +189,10 @@
usb@47401800 {
status = "okay";
};
+
+ dma@07402000 {
+ status = "okay";
+ };
};
i2c1: i2c@4802a000 {
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 81afb27..9e2b543 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -375,6 +375,29 @@
port-mode = <3>;
power = <250>;
phys = <&usb0_phy>;
+
+ dmas = <&cppi41dma 0 0 &cppi41dma 1 0
+ &cppi41dma 2 0 &cppi41dma 3 0
+ &cppi41dma 4 0 &cppi41dma 5 0
+ &cppi41dma 6 0 &cppi41dma 7 0
+ &cppi41dma 8 0 &cppi41dma 9 0
+ &cppi41dma 10 0 &cppi41dma 11 0
+ &cppi41dma 12 0 &cppi41dma 13 0
+ &cppi41dma 14 0 &cppi41dma 0 1
+ &cppi41dma 1 1 &cppi41dma 2 1
+ &cppi41dma 3 1 &cppi41dma 4 1
+ &cppi41dma 5 1 &cppi41dma 6 1
+ &cppi41dma 7 1 &cppi41dma 8 1
+ &cppi41dma 9 1 &cppi41dma 10 1
+ &cppi41dma 11 1 &cppi41dma 12 1
+ &cppi41dma 13 1 &cppi41dma 14 1>;
+ dma-names =
+ "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+ "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+ "rx14", "rx15",
+ "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+ "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+ "tx14", "tx15";
};
};
@@ -407,8 +430,46 @@
port-mode = <3>;
power = <250>;
phys = <&usb1_phy>;
+
+ dmas = <&cppi41dma 15 0 &cppi41dma 16 0
+ &cppi41dma 17 0 &cppi41dma 18 0
+ &cppi41dma 19 0 &cppi41dma 20 0
+ &cppi41dma 21 0 &cppi41dma 22 0
+ &cppi41dma 23 0 &cppi41dma 24 0
+ &cppi41dma 25 0 &cppi41dma 26 0
+ &cppi41dma 27 0 &cppi41dma 28 0
+ &cppi41dma 29 0 &cppi41dma 15 1
+ &cppi41dma 16 1 &cppi41dma 17 1
+ &cppi41dma 18 1 &cppi41dma 19 1
+ &cppi41dma 20 1 &cppi41dma 21 1
+ &cppi41dma 22 1 &cppi41dma 23 1
+ &cppi41dma 24 1 &cppi41dma 25 1
+ &cppi41dma 26 1 &cppi41dma 27 1
+ &cppi41dma 28 1 &cppi41dma 29 1>;
+ dma-names =
+ "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+ "rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+ "rx14", "rx15",
+ "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+ "tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+ "tx14", "tx15";
};
};
+
+ cppi41dma: dma@07402000 {
+ compatible = "ti,am3359-cppi41";
+ reg = <0x47400000 0x1000
+ 0x47402000 0x1000
+ 0x47403000 0x1000
+ 0x47404000 0x4000>;
+ reg-names = "glue controller scheduler queuemgr";
+ interrupts = <17>;
+ interrupt-names = "glue";
+ #dma-cells = <2>;
+ #dma-channels = <30>;
+ #dma-requests = <256>;
+ status = "disabled";
+ };
};
epwmss0: epwmss@48300000 {
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6825957..77bc480 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -287,6 +287,14 @@ config DMA_OMAP
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config TI_CPPI41
+ tristate "AM33xx CPPI41 DMA support"
+ depends on ARCH_OMAP
+ select DMA_ENGINE
+ help
+ The Communications Port Programming Interface (CPPI) 4.1 DMA engine
+ is currently used by the USB driver on AM335x platforms.
+
config MMP_PDMA
bool "MMP PDMA support"
depends on (ARCH_MMP || ARCH_PXA)
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 5e0f2ef..6d62ec3 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
+obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
new file mode 100644
index 0000000..040209a
--- /dev/null
+++ b/drivers/dma/cppi41.c
@@ -0,0 +1,911 @@
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include "dmaengine.h"
+
+#define DESC_TYPE 27
+#define DESC_TYPE_HOST 0x10
+#define DESC_TYPE_TEARD 0x13
+
+#define TD_DESC_TX_RX 16
+#define TD_DESC_DMA_NUM 10
+
+#define DESC_LENGTH_BITS_NUM 21
+
+#define DESC_TYPE_USB (5 << 26)
+#define DESC_PD_COMPLETE (1 << 31)
+
+/* DMA engine */
+#define DMA_TXGCR(x) (0x800 + (x) * 0x20)
+#define DMA_RXGCR(x) (0x808 + (x) * 0x20)
+#define RXHPCRA0 4
+
+#define GCR_CHAN_ENABLE (1 << 31)
+#define GCR_STARV_RETRY (1 << 24)
+#define GCR_DESC_TYPE_HOST (1 << 14)
+
+/* DMA scheduler */
+#define DMA_SCHED_CTRL 0
+#define DMA_SCHED_CTRL_EN (1 << 31)
+#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800)
+
+#define SCHED_ENTRY0_CHAN(x) ((x) << 0)
+#define SCHED_ENTRY0_IS_RX (1 << 7)
+
+#define SCHED_ENTRY1_CHAN(x) ((x) << 8)
+#define SCHED_ENTRY1_IS_RX (1 << 15)
+
+#define SCHED_ENTRY2_CHAN(x) ((x) << 16)
+#define SCHED_ENTRY2_IS_RX (1 << 23)
+
+#define SCHED_ENTRY3_CHAN(x) ((x) << 24)
+#define SCHED_ENTRY3_IS_RX (1 << 31)
+
+/* Queue manager */
+/* 4 KiB of memory for descriptors, 2 for each endpoint */
+#define ALLOC_DECS_NUM 128
+#define DESCS_AREAS 1
+#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS)
+#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4)
+
+#define QMGR_LRAM0_BASE 0x80
+#define QMGR_LRAM_SIZE 0x84
+#define QMGR_LRAM1_BASE 0x88
+#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10)
+#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10)
+#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)
+#define QMGR_PENDING_BIT_Q(x) (x % 32)
+
+#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10)
+#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10)
+#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10)
+#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10)
+
+/* Glue layer specific */
+/* USBSS / USB AM335x */
+#define USBSS_IRQ_STATUS 0x28
+#define USBSS_IRQ_ENABLER 0x2c
+#define USBSS_IRQ_CLEARR 0x30
+
+#define USBSS_IRQ_PD_COMP (1 << 2)
+
+struct cppi41_channel {
+ struct dma_chan chan;
+ struct dma_async_tx_descriptor txd;
+ struct cppi41_dd *cdd;
+ struct cppi41_desc *desc;
+ dma_addr_t desc_phys;
+ void __iomem *gcr_reg;
+ int is_tx;
+
+ unsigned int q_num;
+ unsigned int q_comp_num;
+ unsigned int port_num;
+};
+
+struct cppi41_desc {
+ u32 pd0;
+ u32 pd1;
+ u32 pd2;
+ u32 pd3;
+ u32 pd4;
+ u32 pd5;
+ u32 pd6;
+ u32 pd7;
+} __aligned(32);
+
+struct chan_queues {
+ u16 submit;
+ u16 complete;
+};
+
+struct cppi41_dd {
+ struct dma_device ddev;
+
+ void *qmgr_scratch;
+ dma_addr_t scratch_phys;
+
+ struct cppi41_desc *cd;
+ dma_addr_t descs_phys;
+ struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
+
+ void __iomem *usbss_mem;
+ void __iomem *ctrl_mem;
+ void __iomem *sched_mem;
+ void __iomem *qmgr_mem;
+ unsigned int irq;
+ const struct chan_queues *queues_rx;
+ const struct chan_queues *queues_tx;
+};
+
+#define FIST_COMPLETION_QUEUE 93
+static struct chan_queues usb_queues_tx[] = {
+ /* USB0 ENDP 1 */
+ [ 0] = { .submit = 32, .complete = 93},
+ [ 1] = { .submit = 34, .complete = 94},
+ [ 2] = { .submit = 36, .complete = 95},
+ [ 3] = { .submit = 38, .complete = 96},
+ [ 4] = { .submit = 40, .complete = 97},
+ [ 5] = { .submit = 42, .complete = 98},
+ [ 6] = { .submit = 44, .complete = 99},
+ [ 7] = { .submit = 46, .complete = 100},
+ [ 8] = { .submit = 48, .complete = 101},
+ [ 9] = { .submit = 50, .complete = 102},
+ [10] = { .submit = 52, .complete = 103},
+ [11] = { .submit = 54, .complete = 104},
+ [12] = { .submit = 56, .complete = 105},
+ [13] = { .submit = 58, .complete = 106},
+ [14] = { .submit = 60, .complete = 107},
+
+ /* USB1 ENDP1 */
+ [15] = { .submit = 62, .complete = 125},
+ [16] = { .submit = 64, .complete = 126},
+ [17] = { .submit = 66, .complete = 127},
+ [18] = { .submit = 68, .complete = 128},
+ [19] = { .submit = 70, .complete = 129},
+ [20] = { .submit = 72, .complete = 130},
+ [21] = { .submit = 74, .complete = 131},
+ [22] = { .submit = 76, .complete = 132},
+ [23] = { .submit = 78, .complete = 133},
+ [24] = { .submit = 80, .complete = 134},
+ [25] = { .submit = 82, .complete = 135},
+ [26] = { .submit = 84, .complete = 136},
+ [27] = { .submit = 86, .complete = 137},
+ [28] = { .submit = 88, .complete = 138},
+ [29] = { .submit = 90, .complete = 139},
+};
+
+static const struct chan_queues usb_queues_rx[] = {
+ /* USB0 ENDP 1 */
+ [ 0] = { .submit = 0, .complete = 109},
+ [ 1] = { .submit = 1, .complete = 110},
+ [ 2] = { .submit = 2, .complete = 111},
+ [ 3] = { .submit = 3, .complete = 112},
+ [ 4] = { .submit = 4, .complete = 113},
+ [ 5] = { .submit = 5, .complete = 114},
+ [ 6] = { .submit = 6, .complete = 115},
+ [ 7] = { .submit = 7, .complete = 116},
+ [ 8] = { .submit = 8, .complete = 117},
+ [ 9] = { .submit = 9, .complete = 118},
+ [10] = { .submit = 10, .complete = 119},
+ [11] = { .submit = 11, .complete = 120},
+ [12] = { .submit = 12, .complete = 121},
+ [13] = { .submit = 13, .complete = 122},
+ [14] = { .submit = 14, .complete = 123},
+
+ /* USB1 ENDP 1 */
+ [15] = { .submit = 16, .complete = 141},
+ [16] = { .submit = 17, .complete = 142},
+ [17] = { .submit = 18, .complete = 143},
+ [18] = { .submit = 19, .complete = 144},
+ [19] = { .submit = 20, .complete = 145},
+ [20] = { .submit = 21, .complete = 146},
+ [21] = { .submit = 22, .complete = 147},
+ [22] = { .submit = 23, .complete = 148},
+ [23] = { .submit = 24, .complete = 149},
+ [24] = { .submit = 25, .complete = 150},
+ [25] = { .submit = 26, .complete = 151},
+ [26] = { .submit = 27, .complete = 152},
+ [27] = { .submit = 28, .complete = 153},
+ [28] = { .submit = 29, .complete = 154},
+ [29] = { .submit = 30, .complete = 155},
+};
+
+struct cppi_glue_infos {
+ irqreturn_t (*isr)(int irq, void *data);
+ const struct chan_queues *queues_rx;
+ const struct chan_queues *queues_tx;
+};
+
+static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
+{
+ return container_of(c, struct cppi41_channel, chan);
+}
+
+static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
+{
+ struct cppi41_channel *c;
+ u32 descs_size;
+ u32 desc_num;
+
+ descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM;
+
+ if (!((desc >= cdd->descs_phys) &&
+ (desc < (cdd->descs_phys + descs_size)))) {
+ return NULL;
+ }
+
+ desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ BUG_ON(desc_num > ALLOC_DECS_NUM);
+ c = cdd->chan_busy[desc_num];
+ cdd->chan_busy[desc_num] = NULL;
+ return c;
+}
+
+static void cppi_writel(u32 val, void *__iomem *mem)
+{
+ __raw_writel(val, mem);
+}
+
+static u32 cppi_readl(void *__iomem *mem)
+{
+ return __raw_readl(mem);
+}
+
+static u32 pd_trans_len(u32 val)
+{
+ return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1);
+}
+
+static irqreturn_t cppi41_irq(int irq, void *data)
+{
+ struct cppi41_dd *cdd = data;
+ struct cppi41_channel *c;
+ u32 status;
+ int i;
+
+ status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS);
+ if (!(status & USBSS_IRQ_PD_COMP))
+ return IRQ_NONE;
+ cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS);
+
+ for (i = QMGR_PENDING_SLOT_Q(FIST_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) {
+ u32 mask;
+ /* set corresponding bit for completetion Q 93 */
+ mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE);
+ /* not set all bits for queues less than Q 93 */
+ mask--;
+ /* now invert and keep only Q 93+ set */
+ val &= ~mask;
+ }
+
+ if (val)
+ __iormb();
+
+ while (val) {
+ u32 desc;
+
+ q_num = __fls(val);
+ val &= ~(1 << q_num);
+ q_num += 32 * i;
+ desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num));
+ desc &= ~0x1f;
+ c = desc_to_chan(cdd, desc);
+ if (WARN_ON(!c))
+ continue;
+ c->txd.transfered = pd_trans_len(c->desc->pd0);
+
+ dma_cookie_complete(&c->txd);
+ c->txd.callback(c->txd.callback_param);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ dma_cookie_t cookie;
+
+ cookie = dma_cookie_assign(tx);
+
+ return cookie;
+}
+
+static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+
+ dma_cookie_init(chan);
+ dma_async_tx_descriptor_init(&c->txd, chan);
+ c->txd.tx_submit = cppi41_tx_submit;
+
+ if (!c->is_tx)
+ cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
+
+ return 0;
+}
+
+static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ enum dma_status ret;
+
+ /* lock */
+ ret = dma_cookie_status(chan, cookie, txstate);
+ /* unlock */
+
+ return ret;
+}
+
+static void push_desc_queue(struct cppi41_channel *cppi41_chan)
+{
+ struct cppi41_dd *cdd = cppi41_chan->cdd;
+ u32 desc_num;
+ u32 desc_phys;
+ u32 reg;
+
+ desc_phys = lower_32_bits(cppi41_chan->desc_phys);
+ desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ WARN_ON(cdd->chan_busy[desc_num]);
+ cdd->chan_busy[desc_num] = cppi41_chan;
+
+ reg = (sizeof(struct cppi41_desc) - 24) / 4;
+ reg |= desc_phys;
+ cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(cppi41_chan->q_num));
+}
+
+static void cppi41_dma_issue_pending(struct dma_chan *chan)
+{
+ struct cppi41_channel *cppi41_chan = to_cpp41_chan(chan);
+ u32 reg;
+
+ reg = GCR_CHAN_ENABLE;
+ if (!cppi41_chan->is_tx) {
+ reg |= GCR_STARV_RETRY;
+ reg |= GCR_DESC_TYPE_HOST;
+ reg |= cppi41_chan->q_comp_num;
+ }
+
+ cppi_writel(reg, cppi41_chan->gcr_reg);
+
+ /*
+ * We don't use writel() but __raw_writel() so we have to make sure
+ * that the DMA descriptor in coherent memory made to the main memory
+ * before starting the dma engine.
+ */
+ __iowmb();
+ push_desc_queue(cppi41_chan);
+}
+
+static u32 get_host_pd0(u32 length)
+{
+ u32 reg;
+
+ reg = DESC_TYPE_HOST << DESC_TYPE;
+ reg |= length;
+
+ return reg;
+}
+
+static u32 get_host_pd1(struct cppi41_channel *c)
+{
+ u32 reg;
+
+ reg = 0;
+
+ return reg;
+}
+
+static u32 get_host_pd2(struct cppi41_channel *c)
+{
+ u32 reg;
+
+ reg = DESC_TYPE_USB;
+ reg |= c->q_comp_num;
+
+ return reg;
+}
+
+static u32 get_host_pd3(u32 length)
+{
+ u32 reg;
+
+ /* PD3 = packet size */
+ reg = length;
+
+ return reg;
+}
+
+static u32 get_host_pd6(u32 length)
+{
+ u32 reg;
+
+ /* PD6 buffer size */
+ reg = DESC_PD_COMPLETE;
+ reg |= length;
+
+ return reg;
+}
+
+static u32 get_host_pd4_or_7(u32 addr)
+{
+ u32 reg;
+
+ reg = addr;
+
+ return reg;
+}
+
+static u32 get_host_pd5(void)
+{
+ u32 reg;
+
+ reg = 0;
+
+ return reg;
+}
+
+static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len,
+ enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_desc *d;
+ struct scatterlist *sg;
+ unsigned int i;
+ unsigned int num;
+
+ num = 0;
+ d = c->desc;
+ for_each_sg(sgl, sg, sg_len, i) {
+ u32 addr;
+ u32 len;
+
+ /* We need to use more than one desc once musb supports sg */
+ BUG_ON(num > 0);
+ addr = lower_32_bits(sg_dma_address(sg));
+ len = sg_dma_len(sg);
+
+ d->pd0 = get_host_pd0(len);
+ d->pd1 = get_host_pd1(c);
+ d->pd2 = get_host_pd2(c);
+ d->pd3 = get_host_pd3(len);
+ d->pd4 = get_host_pd4_or_7(addr);
+ d->pd5 = get_host_pd5();
+ d->pd6 = get_host_pd6(len);
+ d->pd7 = get_host_pd4_or_7(addr);
+
+ d++;
+ }
+
+ return &c->txd;
+}
+
+static int cpp41_cfg_chan(struct cppi41_channel *c,
+ struct dma_slave_config *cfg)
+{
+ return 0;
+}
+
+static int cppi41_stop_chan(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_dd *cdd = c->cdd;
+ u32 desc_num;
+ u32 desc_phys;
+
+ /* XXX tear down */
+ desc_phys = lower_32_bits(c->desc_phys);
+ desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ WARN_ON(!cdd->chan_busy[desc_num]);
+ cdd->chan_busy[desc_num] = NULL;
+
+ return 0;
+}
+
+static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ int ret;
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
+ break;
+ case DMA_TERMINATE_ALL:
+
+ ret = cppi41_stop_chan(chan);
+ break;
+ default:
+ ret = -ENXIO;
+ break;
+ }
+ return ret;
+}
+
+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 platform_device *pdev, struct cppi41_dd *cdd)
+{
+ struct cppi41_channel *cchan;
+ int i;
+ int ret;
+ u32 n_chans;
+
+ ret = of_property_read_u32(pdev->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;
+
+ for (i = 0; i < n_chans; i++) {
+ cchan = kzalloc(sizeof(*cchan), GFP_KERNEL);
+ if (!cchan)
+ goto err;
+
+ cchan->cdd = cdd;
+ if (i & 1) {
+ cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1);
+ cchan->is_tx = 1;
+ } else {
+ cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1);
+ cchan->is_tx = 0;
+ }
+ cchan->port_num = i >> 1;
+ cchan->desc = &cdd->cd[i * 2];
+ cchan->desc_phys = cdd->descs_phys;
+ cchan->desc_phys += i * 2 * sizeof(struct cppi41_desc);
+ cchan->chan.device = &cdd->ddev;
+ list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
+ }
+ return 0;
+err:
+ cleanup_chans(cdd);
+ return -ENOMEM;
+}
+
+static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ unsigned int mem_decs;
+ int i;
+
+ mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc);
+
+ for (i = 0; i < DESCS_AREAS; i++) {
+
+ cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i));
+ cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+ dma_free_coherent(&pdev->dev, mem_decs, cdd->cd,
+ cdd->descs_phys);
+ }
+}
+
+static void disable_sched(struct cppi41_dd *cdd)
+{
+ cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ disable_sched(cdd);
+
+ purge_descs(pdev, cdd);
+
+ cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+ cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+ dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch,
+ cdd->scratch_phys);
+}
+
+static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ unsigned int desc_size;
+ unsigned int mem_decs;
+ int i;
+ u32 reg;
+ u32 idx;
+
+ BUILD_BUG_ON(sizeof(struct cppi41_desc) &
+ (sizeof(struct cppi41_desc) - 1));
+ BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32);
+ BUILD_BUG_ON(ALLOC_DECS_NUM < 32);
+
+ desc_size = sizeof(struct cppi41_desc);
+ mem_decs = ALLOC_DECS_NUM * desc_size;
+
+ idx = 0;
+ for (i = 0; i < DESCS_AREAS; i++) {
+
+ reg = idx << QMGR_MEMCTRL_IDX_SH;
+ reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH;
+ reg |= ilog2(ALLOC_DECS_NUM) - 5;
+
+ BUILD_BUG_ON(DESCS_AREAS != 1);
+ cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs,
+ &cdd->descs_phys, GFP_KERNEL);
+ if (!cdd->cd)
+ return -ENOMEM;
+
+ cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
+ cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+ idx += ALLOC_DECS_NUM;
+ }
+ return 0;
+}
+
+static void init_sched(struct cppi41_dd *cdd)
+{
+ unsigned ch;
+ unsigned word;
+ u32 reg;
+
+ word = 0;
+ cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+ for (ch = 0; ch < 15 * 2; ch += 2) {
+
+ reg = SCHED_ENTRY0_CHAN(ch);
+ reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
+
+ reg |= SCHED_ENTRY2_CHAN(ch + 1);
+ reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX;
+ cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
+ word++;
+ }
+ reg = 15 * 2 * 2 - 1;
+ reg |= DMA_SCHED_CTRL_EN;
+ cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ int ret;
+
+ BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1));
+ cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE,
+ &cdd->scratch_phys, GFP_KERNEL);
+ if (!cdd->qmgr_scratch)
+ 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(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
+
+ ret = init_descs(pdev, cdd);
+ if (ret)
+ goto err_td;
+
+ init_sched(cdd);
+ return 0;
+err_td:
+ deinit_cpii41(pdev, cdd);
+ return ret;
+}
+
+static struct platform_driver cpp41_dma_driver;
+/*
+ * The param format is:
+ * X Y
+ * X: Port
+ * Y: 0 = RX else TX
+ */
+#define INFO_PORT 0
+#define INFO_IS_TX 1
+
+static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+ struct cppi41_channel *cchan;
+ struct cppi41_dd *cdd;
+ const struct chan_queues *queues;
+ u32 *num = param;
+
+ if (chan->device->dev->driver != &cpp41_dma_driver.driver)
+ return false;
+
+ cchan = to_cpp41_chan(chan);
+
+ if (cchan->port_num != num[INFO_PORT])
+ return false;
+
+ if (cchan->is_tx && !num[INFO_IS_TX])
+ return false;
+ cdd = cchan->cdd;
+ if (cchan->is_tx)
+ queues = cdd->queues_tx;
+ 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)))
+ return false;
+
+ cchan->q_num = queues[cchan->port_num].submit;
+ cchan->q_comp_num = queues[cchan->port_num].complete;
+ return true;
+}
+
+static struct of_dma_filter_info cpp41_dma_info = {
+ .filter_fn = cpp41_dma_filter_fn,
+};
+
+static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ int count = dma_spec->args_count;
+ struct of_dma_filter_info *info = ofdma->of_dma_data;
+
+ if (!info || !info->filter_fn)
+ return NULL;
+
+ if (count != 2)
+ return NULL;
+
+ return dma_request_channel(info->dma_cap, info->filter_fn,
+ &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 of_device_id cppi41_dma_ids[] = {
+ { .compatible = "ti,am3359-cppi41", .data = &usb_infos},
+ {},
+};
+MODULE_DEVICE_TABLE(of, cppi41_dma_ids);
+
+static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node);
+ if (!of_id)
+ return NULL;
+ return of_id->data;
+}
+
+static int cppi41_dma_probe(struct platform_device *pdev)
+{
+ struct cppi41_dd *cdd;
+ const struct cppi_glue_infos *glue_info;
+ int irq;
+ int ret;
+
+ glue_info = get_glue_info(pdev);
+ if (!glue_info)
+ return -EINVAL;
+
+ cdd = kzalloc(sizeof(*cdd), GFP_KERNEL);
+ if (!cdd)
+ return -ENOMEM;
+
+ dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask);
+ cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources;
+ cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources;
+ cdd->ddev.device_tx_status = cppi41_dma_tx_status;
+ cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
+ cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
+ cdd->ddev.device_control = cppi41_dma_control;
+ cdd->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&cdd->ddev.channels);
+ cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
+
+ cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0);
+ cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1);
+ cdd->sched_mem = of_iomap(pdev->dev.of_node, 2);
+ cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3);
+
+ if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem ||
+ !cdd->qmgr_mem) {
+ ret = -ENXIO;
+ goto err_remap;
+ }
+
+ cdd->queues_rx = glue_info->queues_rx;
+ cdd->queues_tx = glue_info->queues_tx;
+
+ ret = init_cppi41(pdev, cdd);
+ if (ret)
+ goto err_init_cppi;
+
+ ret = cppi41_add_chans(pdev, cdd);
+ if (ret)
+ goto err_chans;
+
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (!irq)
+ goto err_irq;
+
+ cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
+
+ ret = request_irq(irq, glue_info->isr, IRQF_SHARED,
+ dev_name(&pdev->dev), cdd);
+ if (ret)
+ goto err_irq;
+ cdd->irq = irq;
+
+ ret = dma_async_device_register(&cdd->ddev);
+ if (ret)
+ goto err_dma_reg;
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ cppi41_dma_xlate, &cpp41_dma_info);
+ if (ret)
+ goto err_of;
+
+ platform_set_drvdata(pdev, cdd);
+ dev_err(&pdev->dev, "finally\n");
+ return 0;
+err_of:
+ dma_async_device_unregister(&cdd->ddev);
+err_dma_reg:
+ free_irq(irq, cdd);
+err_irq:
+ cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+ cleanup_chans(cdd);
+err_chans:
+ deinit_cpii41(pdev, cdd);
+err_init_cppi:
+ iounmap(cdd->usbss_mem);
+ iounmap(cdd->ctrl_mem);
+ iounmap(cdd->sched_mem);
+ iounmap(cdd->qmgr_mem);
+err_remap:
+ kfree(cdd);
+ return ret;
+}
+
+static int cppi41_dma_remove(struct platform_device *pdev)
+{
+ struct cppi41_dd *cdd = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&cdd->ddev);
+
+ cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+ free_irq(cdd->irq, cdd);
+ cleanup_chans(cdd);
+ deinit_cpii41(pdev, cdd);
+ iounmap(cdd->usbss_mem);
+ iounmap(cdd->ctrl_mem);
+ iounmap(cdd->sched_mem);
+ iounmap(cdd->qmgr_mem);
+ kfree(cdd);
+ return 0;
+}
+
+static struct platform_driver cpp41_dma_driver = {
+ .probe = cppi41_dma_probe,
+ .remove = cppi41_dma_remove,
+ .driver = {
+ .name = "cppi41-dma-engine",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cppi41_dma_ids),
+ },
+};
+
+module_platform_driver(cpp41_dma_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <[email protected]>");
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b7257ae..04658d7 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -129,6 +129,10 @@ config USB_TI_CPPI_DMA
help
Enable DMA transfers when TI CPPI DMA is available.
+config USB_TI_CPPI41_DMA
+ bool 'TI CPPI 4.1 (AM335x)'
+ depends on ARCH_OMAP
+
config USB_TUSB_OMAP_DMA
bool 'TUSB 6010'
depends on USB_MUSB_TUSB6010
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 52f552c..c5ea5c6 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -32,3 +32,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o
musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o
musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o
musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
new file mode 100644
index 0000000..2b66204
--- /dev/null
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -0,0 +1,433 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sizes.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "musb_core.h"
+
+#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
+
+#define EP_MODE_AUTOREG_NONE 0
+#define EP_MODE_AUTOREG_ALL_NEOP 1
+#define EP_MODE_AUTOREG_ALWAYS 3
+
+#define EP_MODE_DMA_TRANSPARENT 0
+#define EP_MODE_DMA_RNDIS 1
+#define EP_MODE_DMA_GEN_RNDIS 3
+
+#define USB_CTRL_TX_MODE 0x70
+#define USB_CTRL_RX_MODE 0x74
+#define USB_CTRL_AUTOREQ 0xd0
+
+struct cppi41_dma_channel {
+ struct dma_channel channel;
+ struct cppi41_dma_controller *controller;
+ struct musb_hw_ep *hw_ep;
+ struct dma_chan *dc;
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+ u8 port_num;
+ u8 is_tx;
+ u8 is_allocated;
+
+ dma_addr_t buf_addr;
+ u32 total_len;
+ u32 transfered;
+ u32 packet_sz;
+};
+
+#define MUSB_DMA_NUM_CHANNELS 15
+
+struct cppi41_dma_controller {
+ struct dma_controller controller;
+ struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
+ struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
+ struct musb *musb;
+ u32 rx_mode;
+ u32 tx_mode;
+ u32 auto_req;
+};
+
+static void cppi41_dma_callback(void *private_data)
+{
+ struct dma_channel *channel = private_data;
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ struct dma_async_tx_descriptor *dma_desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ dma_desc = cppi41_channel->desc;
+ cppi41_channel->transfered += dma_desc->transfered;
+
+ dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
+ hw_ep->epnum, cppi41_channel->transfered,
+ cppi41_channel->total_len);
+
+ if (cppi41_channel->transfered == cppi41_channel->total_len ||
+ dma_desc->transfered < cppi41_channel->packet_sz) {
+
+ /* done, complete */
+ cppi41_channel->channel.actual_len = cppi41_channel->transfered;
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
+ } else {
+ /* next iteration, reload */
+ struct dma_chan *dc = cppi41_channel->dc;
+ enum dma_transfer_direction direction;
+ u16 csr;
+ u32 remain_bytes;
+ void __iomem *epio = cppi41_channel->hw_ep->regs;
+
+ cppi41_channel->buf_addr += cppi41_channel->packet_sz;
+
+ remain_bytes = cppi41_channel->total_len;
+ remain_bytes -= cppi41_channel->transfered;
+ remain_bytes = min(remain_bytes, cppi41_channel->packet_sz);
+
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV
+ : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc,
+ cppi41_channel->buf_addr,
+ remain_bytes,
+ direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (WARN_ON(!dma_desc))
+ return;
+ cppi41_channel->desc = dma_desc;
+
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+ dma_async_issue_pending(dc);
+
+ if (!cppi41_channel->is_tx) {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old)
+{
+ unsigned shift;
+
+ shift = (ep - 1) * 2;
+ old &= ~(3 << shift);
+ old |= mode << shift;
+ return old;
+}
+
+static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ if (cppi41_channel->is_tx)
+ old_mode = controller->tx_mode;
+ else
+ old_mode = controller->rx_mode;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ if (cppi41_channel->is_tx) {
+ controller->tx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE,
+ new_mode);
+ } else {
+ controller->rx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE,
+ new_mode);
+ }
+}
+
+static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ old_mode = controller->auto_req;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ controller->auto_req = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode);
+}
+
+static bool cppi41_configure_channel(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct dma_chan *dc = cppi41_channel->dc;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_transfer_direction direction;
+ struct musb *musb = cppi41_channel->controller->musb;
+
+ dev_dbg(musb->controller,
+ "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
+ cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, cppi41_channel->is_tx);
+
+ cppi41_channel->buf_addr = dma_addr;
+ cppi41_channel->total_len = len;
+ cppi41_channel->transfered = 0;
+ cppi41_channel->packet_sz = packet_sz;
+#if 0
+ /* RNDIS mode */
+ if (len > packet_sz) {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), len);
+ /* gen rndis */
+ cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_GEN_RNDIS);
+
+ /* auto req */
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_ALL_NEOP);
+ } else {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), 0);
+ cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_NONE);
+ }
+#else
+ /* fallback mode */
+ cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+ len = min_t(u32, packet_sz, len);
+#endif
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma_desc)
+ return false;
+
+ cppi41_channel->desc = dma_desc;
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+
+ dma_async_issue_pending(dc);
+ return true;
+}
+
+static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep, u8 is_tx)
+{
+ struct cppi41_dma_controller *controller = container_of(c,
+ struct cppi41_dma_controller, controller);
+ struct cppi41_dma_channel *cppi41_channel = NULL;
+ u8 ch_num = hw_ep->epnum - 1;
+
+ if (ch_num >= MUSB_DMA_NUM_CHANNELS)
+ return NULL;
+
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[ch_num];
+ else
+ cppi41_channel = &controller->rx_channel[ch_num];
+
+ if (!cppi41_channel->dc)
+ return NULL;
+
+ if (cppi41_channel->is_allocated)
+ return NULL;
+
+ cppi41_channel->hw_ep = hw_ep;
+ cppi41_channel->is_allocated = 1;
+
+ return &cppi41_channel->channel;
+}
+
+static void cppi41_dma_channel_release(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+
+ if (cppi41_channel->is_allocated) {
+ cppi41_channel->is_allocated = 0;
+ channel->status = MUSB_DMA_STATUS_FREE;
+ channel->actual_len = 0;
+ }
+}
+
+static int cppi41_dma_channel_program(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ int ret;
+
+ BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+ channel->status == MUSB_DMA_STATUS_BUSY);
+
+ channel->status = MUSB_DMA_STATUS_BUSY;
+ channel->actual_len = 0;
+ ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);
+ if (!ret)
+ channel->status = MUSB_DMA_STATUS_FREE;
+
+ return ret;
+}
+
+static int cppi41_dma_channel_abort(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+
+ dev_err(musb->controller, "abort channel=%d, is_tx=%d\n",
+ cppi41_channel->port_num, cppi41_channel->is_tx);
+ dmaengine_terminate_all(cppi41_channel->dc);
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ return 0;
+}
+
+static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl)
+{
+ struct dma_chan *dc;
+ int i;
+
+ for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) {
+ dc = ctrl->tx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ dc = ctrl->rx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ }
+}
+
+static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller)
+{
+ cppi41_release_all_dma_chans(controller);
+}
+
+static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
+{
+ struct musb *musb = controller->musb;
+ struct device *dev = musb->controller;
+ struct device_node *np = dev->of_node;
+ struct cppi41_dma_channel *cppi41_channel;
+ int count;
+ int i;
+ int ret;
+
+ count = of_property_count_strings(np, "dma-names");
+ if (count < 0)
+ return count;
+
+ for (i = 0; i < count; i++) {
+ struct dma_chan *dc;
+ struct dma_channel *musb_dma;
+ const char *str;
+ unsigned is_tx;
+ unsigned int port;
+
+ ret = of_property_read_string_index(np, "dma-names", i, &str);
+ if (ret)
+ goto err;
+ if (!strncmp(str, "tx", 2))
+ is_tx = 1;
+ else if (!strncmp(str, "rx", 2))
+ is_tx = 0;
+ else {
+ dev_err(dev, "Wrong dmatype %s\n", str);
+ goto err;
+ }
+ ret = kstrtouint(str + 2, 0, &port);
+ if (ret)
+ goto err;
+
+ if (port > MUSB_DMA_NUM_CHANNELS || !port)
+ goto err;
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[port - 1];
+ else
+ cppi41_channel = &controller->rx_channel[port - 1];
+
+ cppi41_channel->controller = controller;
+ cppi41_channel->port_num = port;
+ cppi41_channel->is_tx = is_tx;
+
+ musb_dma = &cppi41_channel->channel;
+ musb_dma->private_data = cppi41_channel;
+ musb_dma->status = MUSB_DMA_STATUS_FREE;
+ musb_dma->max_len = SZ_4M;
+
+ dc = dma_request_slave_channel(dev, str);
+ if (!dc) {
+ dev_err(dev, "Falied to request %s.\n", str);
+ goto err;
+ }
+ cppi41_channel->dc = dc;
+
+#if 0
+ XXX just in case
+ ret = dc->device->device_control(dc, DMA_SLAVE_CONFIG,
+ (unsigned long) &cfg);
+ if (ret)
+ goto err;
+#endif
+ }
+ return 0;
+err:
+ cppi41_release_all_dma_chans(controller);
+ return -EINVAL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct cppi41_dma_controller *controller = container_of(c,
+ struct cppi41_dma_controller, controller);
+
+ cppi41_dma_controller_stop(controller);
+ kfree(controller);
+}
+
+struct dma_controller *dma_controller_create(struct musb *musb,
+ void __iomem *base)
+{
+ struct cppi41_dma_controller *controller;
+ int ret;
+
+ if (!musb->controller->of_node) {
+ dev_err(musb->controller, "Need DT for the DMA engine.\n");
+ return NULL;
+ }
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ goto kzalloc_fail;
+
+ controller->musb = musb;
+
+ controller->controller.channel_alloc = cppi41_dma_channel_allocate;
+ controller->controller.channel_release = cppi41_dma_channel_release;
+ controller->controller.channel_program = cppi41_dma_channel_program;
+ controller->controller.channel_abort = cppi41_dma_channel_abort;
+
+ ret = cppi41_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
+ return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ return NULL;
+}
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index c8e67fd..1345a4f 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -68,7 +68,7 @@ struct musb_hw_ep;
#define is_dma_capable() (1)
#endif
-#ifdef CONFIG_USB_TI_CPPI_DMA
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
#define is_cppi_enabled() 1
#else
#define is_cppi_enabled() 0
--
1.8.3.2
In USB RX path it is possible that the we receive less bytes than
requested. Take the following example:
The driver for USB-to-UART submits an URB with 256 bytes in size and the
dmaengine driver in turn programs a transfer of 256 bytes. The transfer
is programmed and the dma engine waits for the data to arrive. Once data
is sent on the UART the dma engine begins to move data. If there was
only one data byte in the USB packet received then the DMA engine will
only move one byte due to USB restrictions / rules. The real size of the
transfer has to be notified to the user / caller so he set this to the
caller.
This patch adds the transfered member to the dma_async_tx_descriptor
where the caller can obtain the final size.
Cc: Vinod Koul <[email protected]>
Cc: Dan Williams <[email protected]>
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
include/linux/dmaengine.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index cb286b1..c3a4635 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -403,6 +403,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
* @tx_submit: set the prepared descriptor(s) to be executed by the engine
* @callback: routine to call after this operation is complete
* @callback_param: general parameter to pass to the callback routine
+ * @transfered: number of bytes that were really transfered in case the channel
+ * transfered less than requested.
* ---async_tx api specific fields---
* @next: at completion submit this descriptor
* @parent: pointer to the next level up in the dependency chain
@@ -416,6 +418,7 @@ struct dma_async_tx_descriptor {
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback;
void *callback_param;
+ unsigned int transfered;
#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
struct dma_async_tx_descriptor *next;
struct dma_async_tx_descriptor *parent;
--
1.8.3.2
This moves the two instances from the big node into two child nodes. The
glue layer ontop does almost nothing.
There is one devices containing the (2) phy, (2) usb and later the dma
engine. The usb device is the "glue device" which contains the musb
device as a child. This is what we do ever since.
The new file musb_am335x is just here to prob the new bus and populate
child devices.
There are a lot of changes to the dsps file as a result of the changes:
- musb_core_offset
This is gone. The device tree provides memory ressources information
for the device there is no need to "fix" things
- instances
This is gone as well. If we have two instances then we have have two
child enabled nodes in the device tree. For instance the SoC in beagle
bone has two USB instances but only one has been wired up so there is
no need to load and init the second instance since it won't be used.
- dsps_glue is now per glue device
In the past there was one of this structs but with an array of two and
each instance accessed its variable depending on the platform device
id.
- no unneeded copy of structs
I do not know why struct dsps_musb_wrapper is copied but it is not
necessary. The same goes for musb_hdrc_platform_data which allocated
on demand and then again by platform_device_add_data(). One copy is
enough.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
arch/arm/boot/dts/am335x-bone.dts | 12 ++
arch/arm/boot/dts/am335x-evm.dts | 20 +++
arch/arm/boot/dts/am335x-evmsk.dts | 12 ++
arch/arm/boot/dts/am33xx.dtsi | 89 +++++++++++--
drivers/usb/musb/Kconfig | 4 +
drivers/usb/musb/Makefile | 3 +
drivers/usb/musb/musb_am335x.c | 55 ++++++++
drivers/usb/musb/musb_dsps.c | 255 ++++++++++++++-----------------------
8 files changed, 279 insertions(+), 171 deletions(-)
create mode 100644 drivers/usb/musb/musb_am335x.c
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 444b4ed..2c2ac84 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -120,6 +120,18 @@
status = "okay";
};
+ musb: usb@47400000 {
+ status = "okay";
+
+ phy@47401300 {
+ status = "okay";
+ };
+
+ usb@47401000 {
+ status = "okay";
+ };
+ };
+
i2c0: i2c@44e0b000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 3aee1a4..a3a642a 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -171,6 +171,26 @@
};
};
+ musb: usb@47400000 {
+ status = "okay";
+
+ phy@47401300 {
+ status = "okay";
+ };
+
+ phy@47401b00 {
+ status = "okay";
+ };
+
+ usb@47401000 {
+ status = "no";
+ };
+
+ usb@47401800 {
+ status = "okay";
+ };
+ };
+
i2c1: i2c@4802a000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 0c8ad17..766c23a 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -207,6 +207,18 @@
};
};
+ musb: usb@47400000 {
+ status = "okay";
+
+ phy@47401300 {
+ status = "okay";
+ };
+
+ usb@47401000 {
+ status = "okay";
+ };
+ };
+
epwmss2: epwmss@48304000 {
status = "okay";
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 38b446b..81afb27 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -26,6 +26,10 @@
serial5 = &uart5;
d_can0 = &dcan0;
d_can1 = &dcan1;
+ usb0 = &usb0;
+ usb1 = &usb1;
+ phy0 = &usb0_phy;
+ phy1 = &usb1_phy;
};
cpus {
@@ -333,21 +337,78 @@
status = "disabled";
};
- usb@47400000 {
- compatible = "ti,musb-am33xx";
- reg = <0x47400000 0x1000 /* usbss */
- 0x47401000 0x800 /* musb instance 0 */
- 0x47401800 0x800>; /* musb instance 1 */
- interrupts = <17 /* usbss */
- 18 /* musb instance 0 */
- 19>; /* musb instance 1 */
- multipoint = <1>;
- num-eps = <16>;
- ram-bits = <12>;
- port0-mode = <3>;
- port1-mode = <3>;
- power = <250>;
+ usb: usb@47400000 {
+ compatible = "ti,am33xx-usb";
+ reg = <0x47400000 0x1000>;
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
ti,hwmods = "usb_otg_hs";
+ status = "disabled";
+
+ usb0_phy: phy@47401300 {
+ compatible = "ti,am335x-usb-phy";
+ reg = <0x44e10620 0x8
+ 0x47401300 0x100>;
+ reg-names = "reset_mod", "phy";
+ status = "disabled";
+ };
+
+ usb0: usb@47401000 {
+ compatible = "ti,musb-am33xx";
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x47401000 0x200>;
+ reg-names = "control";
+ status = "disabled";
+
+ musb0: usb@47401400 {
+ compatible = "mg,musbmhdrc";
+ reg = <0x47401400 0x400>;
+ reg-names = "mc";
+ interrupts = <18>;
+ interrupt-names = "mc";
+ multipoint = <1>;
+ num-eps = <16>;
+ ram-bits = <12>;
+ port-mode = <3>;
+ power = <250>;
+ phys = <&usb0_phy>;
+ };
+ };
+
+ usb1_phy: phy@47401b00 {
+ compatible = "ti,am335x-usb-phy";
+ reg = <0x44e10628 0x8
+ 0x47401b00 0x100>;
+ reg-names = "reset_mod", "phy";
+ status = "disabled";
+ };
+
+ usb1: usb@47401800 {
+ compatible = "ti,musb-am33xx";
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x47401800 0x200>;
+ reg-names = "control";
+ status = "disabled";
+
+ musb1: usb@47401c00 {
+ compatible = "mg,musbmhdrc";
+ reg = <0x47401c00 0x400>;
+ reg-names = "mc";
+ interrupts = <19>;
+ interrupt-names = "mc";
+ multipoint = <1>;
+ num-eps = <16>;
+ ram-bits = <12>;
+ port-mode = <3>;
+ power = <250>;
+ phys = <&usb1_phy>;
+ };
+ };
};
epwmss0: epwmss@48300000 {
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 797e3fd..b7257ae 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -83,6 +83,7 @@ config USB_MUSB_AM35X
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
+ select USB_MUSB_AM335X_CHILD
config USB_MUSB_BLACKFIN
tristate "Blackfin"
@@ -93,6 +94,9 @@ config USB_MUSB_UX500
endchoice
+config USB_MUSB_AM335X_CHILD
+ tristate
+
choice
prompt 'MUSB DMA mode'
default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 2b82ed7..52f552c 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
+
+obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o
+
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
# PIO only, or DMA (several potential schemes).
diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c
new file mode 100644
index 0000000..41ac5b5
--- /dev/null
+++ b/drivers/usb/musb/musb_am335x.c
@@ -0,0 +1,55 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+static int am335x_child_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ of_device_unregister(pdev);
+ return 0;
+}
+
+static int am335x_child_remove(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, of_remove_populated_child);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id am335x_child_of_match[] = {
+ { .compatible = "ti,am33xx-usb" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, am335x_child_of_match);
+
+static struct platform_driver am335x_child_driver = {
+ .probe = am335x_child_probe,
+ .remove = am335x_child_remove,
+ .driver = {
+ .name = "am335x-usb-childs",
+ .of_match_table = of_match_ptr(am335x_child_of_match),
+ },
+};
+
+module_platform_driver(am335x_child_driver);
+MODULE_DESCRIPTION("AM33xx child devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 1440fac..37ebcbc 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -43,6 +43,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include "musb_core.h"
@@ -106,10 +107,7 @@ struct dsps_musb_wrapper {
/* bit positions for mode */
unsigned iddig:5;
/* miscellaneous stuff */
- u32 musb_core_offset;
u8 poll_seconds;
- /* number of musb instances */
- u8 instances;
};
/**
@@ -117,10 +115,10 @@ struct dsps_musb_wrapper {
*/
struct dsps_glue {
struct device *dev;
- struct platform_device *musb[2]; /* child musb pdev */
+ struct platform_device *musb; /* child musb pdev */
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
- struct timer_list timer[2]; /* otg_workaround timer */
- unsigned long last_timer[2]; /* last timer data for each instance */
+ struct timer_list timer; /* otg_workaround timer */
+ unsigned long last_timer; /* last timer data for each instance */
};
/**
@@ -170,7 +168,6 @@ static void otg_timer(unsigned long _musb)
struct musb *musb = (void *)_musb;
void __iomem *mregs = musb->mregs;
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
u8 devctl;
@@ -207,7 +204,7 @@ static void otg_timer(unsigned long _musb)
case OTG_STATE_B_IDLE:
devctl = dsps_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
- mod_timer(&glue->timer[pdev->id],
+ mod_timer(&glue->timer,
jiffies + wrp->poll_seconds * HZ);
else
musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -221,7 +218,6 @@ static void otg_timer(unsigned long _musb)
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
if (timeout == 0)
@@ -232,23 +228,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
usb_otg_state_string(musb->xceiv->state));
- del_timer(&glue->timer[pdev->id]);
- glue->last_timer[pdev->id] = jiffies;
+ del_timer(&glue->timer);
+ glue->last_timer = jiffies;
return;
}
- if (time_after(glue->last_timer[pdev->id], timeout) &&
- timer_pending(&glue->timer[pdev->id])) {
+ if (time_after(glue->last_timer, timeout) &&
+ timer_pending(&glue->timer)) {
dev_dbg(musb->controller,
"Longer idle timer already pending, ignoring...\n");
return;
}
- glue->last_timer[pdev->id] = timeout;
+ glue->last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
- mod_timer(&glue->timer[pdev->id], timeout);
+ mod_timer(&glue->timer, timeout);
}
static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -256,7 +252,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
unsigned long flags;
@@ -316,7 +311,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
- mod_timer(&glue->timer[pdev->id],
+ mod_timer(&glue->timer,
jiffies + wrp->poll_seconds * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
@@ -324,7 +319,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
MUSB_HST_MODE(musb);
musb->xceiv->otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
- del_timer(&glue->timer[pdev->id]);
+ del_timer(&glue->timer);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
@@ -351,8 +346,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* Poll for ID change */
if (musb->xceiv->state == OTG_STATE_B_IDLE)
- mod_timer(&glue->timer[pdev->id],
- jiffies + wrp->poll_seconds * HZ);
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -362,31 +356,34 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
static int dsps_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+ struct platform_device *parent = to_platform_device(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
- void __iomem *reg_base = musb->ctrl_base;
+ void __iomem *reg_base;
+ struct resource *r;
u32 rev, val;
- int status;
- /* mentor core register starts at offset of 0x400 from musb base */
- musb->mregs += wrp->musb_core_offset;
+ r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+ if (!r)
+ return -EINVAL;
+
+ reg_base = devm_ioremap_resource(dev, r);
+ if (!musb->ctrl_base)
+ return -EINVAL;
+ musb->ctrl_base = reg_base;
/* NOP driver needs change if supporting dual instance */
- musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0);
- if (IS_ERR_OR_NULL(musb->xceiv))
- return -EPROBE_DEFER;
+ musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+ if (IS_ERR(musb->xceiv))
+ return PTR_ERR(musb->xceiv);
/* Returns zero if e.g. not clocked */
rev = dsps_readl(reg_base, wrp->revision);
- if (!rev) {
- status = -ENODEV;
- goto err0;
- }
+ if (!rev)
+ return -ENODEV;
usb_phy_init(musb->xceiv);
-
- setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
/* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
@@ -402,17 +399,14 @@ static int dsps_musb_init(struct musb *musb)
dsps_writel(reg_base, wrp->eoi, 0);
return 0;
-err0:
- return status;
}
static int dsps_musb_exit(struct musb *musb)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
- del_timer_sync(&glue->timer[pdev->id]);
+ del_timer_sync(&glue->timer);
usb_phy_shutdown(musb->xceiv);
return 0;
@@ -430,106 +424,98 @@ static struct musb_platform_ops dsps_ops = {
static u64 musb_dmamask = DMA_BIT_MASK(32);
-static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+static int get_int_prop(struct device_node *dn, const char *s)
{
- struct device *dev = glue->dev;
- struct platform_device *pdev = to_platform_device(dev);
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
- struct device_node *np = pdev->dev.of_node;
- struct musb_hdrc_config *config;
- struct platform_device *musb;
- struct resource *res;
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32(dn, s, &val);
+ if (ret)
+ return 0;
+ return val;
+}
+
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
+ struct platform_device *parent)
+{
+ struct musb_hdrc_platform_data pdata;
struct resource resources[2];
- char res_name[11];
+ struct device *dev = &parent->dev;
+ struct musb_hdrc_config *config;
+ struct platform_device *musb;
+ struct device_node *dn = parent->dev.of_node;
+ struct device_node *child_node;
int ret;
- /* first resource is for usbss, so start index from 1 */
- res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
- if (!res) {
- dev_err(dev, "failed to get memory for instance %d\n", id);
- ret = -ENODEV;
- goto err0;
+ child_node = of_get_child_by_name(dn, "usb");
+ if (!child_node)
+ return -EINVAL;
+
+ memset(resources, 0, sizeof(resources));
+ ret = of_address_to_resource(child_node, 0, &resources[0]);
+ if (ret) {
+ dev_err(dev, "failed to get memory.\n");
+ return ret;
}
- res->parent = NULL;
- resources[0] = *res;
-
- /* first resource is for usbss, so start index from 1 */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
- if (!res) {
- dev_err(dev, "failed to get irq for instance %d\n", id);
- ret = -ENODEV;
- goto err0;
+
+ ret = of_irq_to_resource(child_node, 0, &resources[1]);
+ if (ret == 0) {
+ dev_err(dev, "failed to get irq.\n");
+ ret = -EINVAL;
+ return ret;
}
- res->parent = NULL;
- resources[1] = *res;
- resources[1].name = "mc";
/* allocate the child platform device */
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(dev, "failed to allocate musb device\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
musb->dev.parent = dev;
musb->dev.dma_mask = &musb_dmamask;
musb->dev.coherent_dma_mask = musb_dmamask;
+ musb->dev.of_node = of_node_get(child_node);
- glue->musb[id] = musb;
+ glue->musb = musb;
- ret = platform_device_add_resources(musb, resources, 2);
+ ret = platform_device_add_resources(musb, resources,
+ ARRAY_SIZE(resources));
if (ret) {
dev_err(dev, "failed to add resources\n");
- goto err2;
+ goto err;
}
- if (np) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev,
- "failed to allocate musb platform data\n");
- ret = -ENOMEM;
- goto err2;
- }
-
- config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
- if (!config) {
- dev_err(&pdev->dev,
- "failed to allocate musb hdrc config\n");
- ret = -ENOMEM;
- goto err2;
- }
-
- of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
- of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
- snprintf(res_name, sizeof(res_name), "port%d-mode", id);
- of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
- of_property_read_u32(np, "power", (u32 *)&pdata->power);
- config->multipoint = of_property_read_bool(np, "multipoint");
-
- pdata->config = config;
+ config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ dev_err(dev, "failed to allocate musb hdrc config\n");
+ ret = -ENOMEM;
+ goto err;
}
+ pdata.config = config;
+ pdata.platform_ops = &dsps_ops;
- pdata->platform_ops = &dsps_ops;
+ config->num_eps = get_int_prop(child_node, "num-eps");
+ config->ram_bits = get_int_prop(child_node, "ram-bits");
+ pdata.mode = get_int_prop(child_node, "port-mode");
+ pdata.power = get_int_prop(child_node, "power");
+ config->multipoint = of_property_read_bool(child_node, "multipoint");
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
if (ret) {
dev_err(dev, "failed to add platform_data\n");
- goto err2;
+ goto err;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(dev, "failed to register musb device\n");
- goto err2;
+ goto err;
}
-
return 0;
-err2:
+err:
platform_device_put(musb);
-err0:
return ret;
}
@@ -538,14 +524,12 @@ static int dsps_probe(struct platform_device *pdev)
const struct of_device_id *match;
const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue;
- struct resource *iomem;
- int ret, i;
+ int ret;
match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
- ret = -EINVAL;
- goto err0;
+ return -EINVAL;
}
wrp = match->data;
@@ -553,29 +537,13 @@ static int dsps_probe(struct platform_device *pdev)
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "unable to allocate glue memory\n");
- ret = -ENOMEM;
- goto err0;
- }
-
- /* get memory resource */
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem) {
- dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
- ret = -ENODEV;
- goto err1;
+ return -ENOMEM;
}
glue->dev = &pdev->dev;
+ glue->wrp = wrp;
- glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
- if (!glue->wrp) {
- dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
- ret = -ENOMEM;
- goto err1;
- }
platform_set_drvdata(pdev, glue);
-
- /* enable the usbss clocks */
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
@@ -584,17 +552,9 @@ static int dsps_probe(struct platform_device *pdev)
goto err2;
}
- /* create the child platform device for all instances of musb */
- for (i = 0; i < wrp->instances ; i++) {
- ret = dsps_create_musb_pdev(glue, i);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to create child pdev\n");
- /* release resources of previously created instances */
- for (i--; i >= 0 ; i--)
- platform_device_unregister(glue->musb[i]);
- goto err3;
- }
- }
+ ret = dsps_create_musb_pdev(glue, pdev);
+ if (ret)
+ goto err3;
return 0;
@@ -602,26 +562,19 @@ static int dsps_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
err2:
pm_runtime_disable(&pdev->dev);
- kfree(glue->wrp);
-err1:
kfree(glue);
-err0:
return ret;
}
+
static int dsps_remove(struct platform_device *pdev)
{
struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
- /* delete the child platform device */
- for (i = 0; i < wrp->instances ; i++)
- platform_device_unregister(glue->musb[i]);
+ platform_device_unregister(glue->musb);
/* disable usbss clocks */
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- kfree(glue->wrp);
kfree(glue);
return 0;
}
@@ -652,9 +605,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
.rxep_shift = 16,
.rxep_mask = 0xfffe,
.rxep_bitmap = (0xfffe << 16),
- .musb_core_offset = 0x400,
.poll_seconds = 2,
- .instances = 1,
};
static const struct of_device_id musb_dsps_of_match[] = {
@@ -678,14 +629,4 @@ MODULE_AUTHOR("Ravi B <[email protected]>");
MODULE_AUTHOR("Ajay Kumar Gupta <[email protected]>");
MODULE_LICENSE("GPL v2");
-static int __init dsps_init(void)
-{
- return platform_driver_register(&dsps_usbss_driver);
-}
-subsys_initcall(dsps_init);
-
-static void __exit dsps_exit(void)
-{
- platform_driver_unregister(&dsps_usbss_driver);
-}
-module_exit(dsps_exit);
+module_platform_driver(dsps_usbss_driver);
--
1.8.3.2
This patch renames the type struct from ti81xx_driver_data to
am33xx_driver_data since it is not used for ti81xx anymore. The EOI
member is also removed since the am33xx SoC does not have such register.
The interrupt is acknowledged by writting into the stat register.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 37ebcbc..2e45723 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -74,7 +74,6 @@ struct dsps_musb_wrapper {
u16 revision;
u16 control;
u16 status;
- u16 eoi;
u16 epintr_set;
u16 epintr_clear;
u16 epintr_status;
@@ -160,7 +159,6 @@ static void dsps_musb_disable(struct musb *musb)
dsps_writel(reg_base, wrp->epintr_clear,
wrp->txep_bitmap | wrp->rxep_bitmap);
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
- dsps_writel(reg_base, wrp->eoi, 0);
}
static void otg_timer(unsigned long _musb)
@@ -271,7 +269,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* Get usb core interrupts */
usbintr = dsps_readl(reg_base, wrp->coreintr_status);
if (!usbintr && !epintr)
- goto eoi;
+ goto out;
musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
if (usbintr)
@@ -339,15 +337,11 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
if (musb->int_tx || musb->int_rx || musb->int_usb)
ret |= musb_interrupt(musb);
- eoi:
- /* EOI needs to be written for the IRQ to be re-asserted. */
- if (ret == IRQ_HANDLED || epintr || usbintr)
- dsps_writel(reg_base, wrp->eoi, 1);
-
/* Poll for ID change */
if (musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+out:
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -395,9 +389,6 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
- /* clear level interrupt */
- dsps_writel(reg_base, wrp->eoi, 0);
-
return 0;
}
@@ -579,11 +570,10 @@ static int dsps_remove(struct platform_device *pdev)
return 0;
}
-static const struct dsps_musb_wrapper ti81xx_driver_data = {
+static const struct dsps_musb_wrapper am33xx_driver_data = {
.revision = 0x00,
.control = 0x14,
.status = 0x18,
- .eoi = 0x24,
.epintr_set = 0x38,
.epintr_clear = 0x40,
.epintr_status = 0x30,
@@ -610,7 +600,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
static const struct of_device_id musb_dsps_of_match[] = {
{ .compatible = "ti,musb-am33xx",
- .data = (void *) &ti81xx_driver_data, },
+ .data = (void *) &am33xx_driver_data, },
{ },
};
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
--
1.8.3.2
dsps uses a nop driver which is added in dsps itself and does the PHY
on/off calls within dsps. Since those calls are now moved the nop driver
itself, we can now request the phy proper phy and remove those calls.
Currently only the first musb interface is used so we only add one phy
node for now.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 97 +-------------------------------------------
1 file changed, 1 insertion(+), 96 deletions(-)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 603ea74..ab723fa 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -123,49 +123,8 @@ struct dsps_glue {
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
struct timer_list timer[2]; /* otg_workaround timer */
unsigned long last_timer[2]; /* last timer data for each instance */
- u32 __iomem *usb_ctrl[2];
};
-#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620
-#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628
-
-static const resource_size_t dsps_control_module_phys[] = {
- DSPS_AM33XX_CONTROL_MODULE_PHYS_0,
- DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
-};
-
-#define USBPHY_CM_PWRDN (1 << 0)
-#define USBPHY_OTG_PWRDN (1 << 1)
-#define USBPHY_OTGVDET_EN (1 << 19)
-#define USBPHY_OTGSESSEND_EN (1 << 20)
-
-/**
- * musb_dsps_phy_control - phy on/off
- * @glue: struct dsps_glue *
- * @id: musb instance
- * @on: flag for phy to be switched on or off
- *
- * This is to enable the PHY using usb_ctrl register in system control
- * module space.
- *
- * XXX: This function will be removed once we have a seperate driver for
- * control module
- */
-static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on)
-{
- u32 usbphycfg;
-
- usbphycfg = readl(glue->usb_ctrl[id]);
-
- if (on) {
- usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
- usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
- } else {
- usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
- }
-
- writel(usbphycfg, glue->usb_ctrl[id]);
-}
/**
* dsps_musb_enable - enable interrupts
*/
@@ -416,8 +375,7 @@ static int dsps_musb_init(struct musb *musb)
musb->mregs += wrp->musb_core_offset;
/* NOP driver needs change if supporting dual instance */
- usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0);
if (IS_ERR_OR_NULL(musb->xceiv))
return -EPROBE_DEFER;
@@ -435,9 +393,6 @@ static int dsps_musb_init(struct musb *musb)
/* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
- /* Start the on-chip PHY and its PLL. */
- musb_dsps_phy_control(glue, pdev->id, 1);
-
musb->isr = dsps_interrupt;
/* reset the otgdisable bit, needed for host mode to work */
@@ -450,8 +405,6 @@ static int dsps_musb_init(struct musb *musb)
return 0;
err0:
- usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
return status;
}
@@ -463,14 +416,7 @@ static int dsps_musb_exit(struct musb *musb)
del_timer_sync(&glue->timer[pdev->id]);
- /* Shutdown the on-chip PHY and its PLL. */
- musb_dsps_phy_control(glue, pdev->id, 0);
usb_phy_shutdown(musb->xceiv);
-
- /* NOP driver needs change if supporting dual instance */
- usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
-
return 0;
}
@@ -499,16 +445,6 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
char res_name[11];
int ret;
- resources[0].start = dsps_control_module_phys[id];
- resources[0].end = resources[0].start + SZ_4 - 1;
- resources[0].flags = IORESOURCE_MEM;
-
- glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources);
- if (IS_ERR(glue->usb_ctrl[id])) {
- ret = PTR_ERR(glue->usb_ctrl[id]);
- goto err0;
- }
-
/* first resource is for usbss, so start index from 1 */
res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
if (!res) {
@@ -692,36 +628,6 @@ static int dsps_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int dsps_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
-
- for (i = 0; i < wrp->instances; i++)
- musb_dsps_phy_control(glue, i, 0);
-
- return 0;
-}
-
-static int dsps_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
-
- for (i = 0; i < wrp->instances; i++)
- musb_dsps_phy_control(glue, i, 1);
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
-
static const struct dsps_musb_wrapper ti81xx_driver_data = {
.revision = 0x00,
.control = 0x14,
@@ -776,7 +682,6 @@ static struct platform_driver dsps_usbss_driver = {
.remove = dsps_remove,
.driver = {
.name = "musb-dsps",
- .pm = &dsps_pm_ops,
.of_match_table = of_match_ptr(musb_dsps_of_match),
},
.id_table = musb_dsps_id_table,
--
1.8.3.2
The am335x PHY code is well hidden in multiple places. The glue layer
uses the nop and does up/down in the background. This patch copies the
power on / power off part out of dsps so it can be removed later in
dsps. At this point I am not sure if it is better to write a new phy
driver for am335x or just add the missing pieces to this one.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/phy/phy-nop.c | 114 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 102 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c
index 55445e5d..7c84eec 100644
--- a/drivers/usb/phy/phy-nop.c
+++ b/drivers/usb/phy/phy-nop.c
@@ -35,6 +35,7 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
+#include <linux/of_address.h>
struct nop_usb_xceiv {
struct usb_phy phy;
@@ -42,6 +43,14 @@ struct nop_usb_xceiv {
struct clk *clk;
struct regulator *vcc;
struct regulator *reset;
+
+ void __iomem *priv_reg;
+};
+
+struct phy_data {
+ int (*phy_init)(struct usb_phy *x);
+ void (*phy_shutdown)(struct usb_phy *x);
+ int (*reg_init)(struct platform_device *pdev);
};
static struct platform_device *pd;
@@ -139,10 +148,85 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
return 0;
}
+static int am335x_reg_init(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct nop_usb_xceiv *nop;
+ struct resource res;
+ int ret;
+
+ nop = platform_get_drvdata(pdev);
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret)
+ return ret;
+
+ nop->priv_reg = devm_request_and_ioremap(&pdev->dev, &res);
+ if (!nop->priv_reg)
+ return -EINVAL;
+ return 0;
+}
+
+#define AM335X_USB_CTRL 0x00
+#define AM335x_USB_STS 0x04
+
+#define USBPHY_CM_PWRDN (1 << 0)
+#define USBPHY_OTG_PWRDN (1 << 1)
+#define USBPHY_OTGVDET_EN (1 << 19)
+#define USBPHY_OTGSESSEND_EN (1 << 20)
+
+static void am335x_phy_power(struct nop_usb_xceiv *nop, bool on)
+{
+ u32 val;
+
+ val = readl(nop->priv_reg);
+ if (on) {
+ val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+ val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ } else {
+ val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+ }
+
+ writel(val, nop->priv_reg);
+}
+
+static int am335x_phy_init(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+ int ret;
+
+ ret = nop_init(phy);
+ if (ret)
+ return ret;
+ am335x_phy_power(nop, true);
+ return 0;
+}
+
+static void am335x_phy_shutdown(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ am335x_phy_power(nop, false);
+ nop_shutdown(phy);
+}
+
+struct phy_data am335x_phy_data = {
+ .reg_init = am335x_reg_init,
+ .phy_init = am335x_phy_init,
+ .phy_shutdown = am335x_phy_shutdown,
+};
+
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+ { .compatible = "usb-nop-xceiv" },
+ { .compatible = "ti,am335x-usb-phy", .data = &am335x_phy_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
static int nop_usb_xceiv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
+ const struct phy_data *phy_data = NULL;
struct nop_usb_xceiv *nop;
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
@@ -154,6 +238,7 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
if (!nop)
return -ENOMEM;
+ platform_set_drvdata(pdev, nop);
nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
GFP_KERNEL);
if (!nop->phy.otg)
@@ -161,13 +246,20 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
if (dev->of_node) {
struct device_node *node = dev->of_node;
+ const struct of_device_id *of_id;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_reset = of_property_read_bool(node, "reset-supply");
-
+ of_id = of_match_node(nop_xceiv_dt_ids, node);
+ if (of_id) {
+ phy_data = of_id->data;
+ err = phy_data->reg_init(pdev);
+ if (err)
+ return err;
+ }
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
@@ -217,8 +309,15 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
nop->phy.set_suspend = nop_set_suspend;
- nop->phy.init = nop_init;
- nop->phy.shutdown = nop_shutdown;
+ if (phy_data && phy_data->phy_init)
+ nop->phy.init = phy_data->phy_init;
+ else
+ nop->phy.init = nop_init;
+
+ if (phy_data && phy_data->phy_shutdown)
+ nop->phy.shutdown = phy_data->phy_shutdown;
+ else
+ nop->phy.shutdown = nop_shutdown;
nop->phy.state = OTG_STATE_UNDEFINED;
nop->phy.type = type;
@@ -233,8 +332,6 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
goto err_add;
}
- platform_set_drvdata(pdev, nop);
-
ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
return 0;
@@ -257,13 +354,6 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id nop_xceiv_dt_ids[] = {
- { .compatible = "usb-nop-xceiv" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
-
static struct platform_driver nop_usb_xceiv_driver = {
.probe = nop_usb_xceiv_probe,
.remove = nop_usb_xceiv_remove,
--
1.8.3.2
On 07/22/2013 10:10 PM, Sebastian Andrzej Siewior wrote:
> In USB RX path it is possible that the we receive less bytes than
> requested. Take the following example:
> The driver for USB-to-UART submits an URB with 256 bytes in size and the
> dmaengine driver in turn programs a transfer of 256 bytes. The transfer
> is programmed and the dma engine waits for the data to arrive. Once data
> is sent on the UART the dma engine begins to move data. If there was
> only one data byte in the USB packet received then the DMA engine will
> only move one byte due to USB restrictions / rules. The real size of the
> transfer has to be notified to the user / caller so he set this to the
> caller.
> This patch adds the transfered member to the dma_async_tx_descriptor
> where the caller can obtain the final size.
> Cc: Vinod Koul <[email protected]>
> Cc: Dan Williams <[email protected]>
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
> ---
> include/linux/dmaengine.h | 3 +++
> 1 file changed, 3 insertions(+)
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index cb286b1..c3a4635 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -403,6 +403,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
> * @tx_submit: set the prepared descriptor(s) to be executed by the engine
> * @callback: routine to call after this operation is complete
> * @callback_param: general parameter to pass to the callback routine
> + * @transfered: number of bytes that were really transfered in case the channel
> + * transfered less than requested.
> * ---async_tx api specific fields---
> * @next: at completion submit this descriptor
> * @parent: pointer to the next level up in the dependency chain
> @@ -416,6 +418,7 @@ struct dma_async_tx_descriptor {
> dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
> dma_async_tx_callback callback;
> void *callback_param;
> + unsigned int transfered;
Correct grammar is "transferred".
WBR, Sergei
Hi Sebastian,
On 7/22/2013 11:39 PM, Sebastian Andrzej Siewior wrote:
> This patch renames the type struct from ti81xx_driver_data to
> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
> member is also removed since the am33xx SoC does not have such register.
> The interrupt is acknowledged by writting into the stat register.
>
AM335X TRM Section 16.6.5 and 16.7.5 describes about EOI registers.
Its at offset 0x24. Or is it that the interrupts are acknowledged even
without writing to eoi register?
--
-George
On 7/22/2013 11:39 PM, Sebastian Andrzej Siewior wrote:
> This moves the two instances from the big node into two child nodes. The
> glue layer ontop does almost nothing.
> There is one devices containing the (2) phy, (2) usb and later the dma
> engine. The usb device is the "glue device" which contains the musb
> device as a child. This is what we do ever since.
> The new file musb_am335x is just here to prob the new bus and populate
> child devices.
> There are a lot of changes to the dsps file as a result of the changes:
> - musb_core_offset
> This is gone. The device tree provides memory ressources information
> for the device there is no need to "fix" things
> - instances
> This is gone as well. If we have two instances then we have have two
> child enabled nodes in the device tree. For instance the SoC in beagle
> bone has two USB instances but only one has been wired up so there is
> no need to load and init the second instance since it won't be used.
> - dsps_glue is now per glue device
> In the past there was one of this structs but with an array of two and
> each instance accessed its variable depending on the platform device
> id.
> - no unneeded copy of structs
> I do not know why struct dsps_musb_wrapper is copied but it is not
> necessary. The same goes for musb_hdrc_platform_data which allocated
> on demand and then again by platform_device_add_data(). One copy is
> enough.
>
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
> ---
> arch/arm/boot/dts/am335x-bone.dts | 12 ++
> arch/arm/boot/dts/am335x-evm.dts | 20 +++
> arch/arm/boot/dts/am335x-evmsk.dts | 12 ++
> arch/arm/boot/dts/am33xx.dtsi | 89 +++++++++++--
> drivers/usb/musb/Kconfig | 4 +
> drivers/usb/musb/Makefile | 3 +
> drivers/usb/musb/musb_am335x.c | 55 ++++++++
> drivers/usb/musb/musb_dsps.c | 255 ++++++++++++++-----------------------
> 8 files changed, 279 insertions(+), 171 deletions(-)
> create mode 100644 drivers/usb/musb/musb_am335x.c
>
> diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
> index 444b4ed..2c2ac84 100644
> --- a/arch/arm/boot/dts/am335x-bone.dts
> +++ b/arch/arm/boot/dts/am335x-bone.dts
> @@ -120,6 +120,18 @@
> status = "okay";
> };
>
> + musb: usb@47400000 {
> + status = "okay";
> +
> + phy@47401300 {
> + status = "okay";
> + };
> +
> + usb@47401000 {
> + status = "okay";
> + };
> + };
> +
> i2c0: i2c@44e0b000 {
> pinctrl-names = "default";
> pinctrl-0 = <&i2c0_pins>;
> diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
> index 3aee1a4..a3a642a 100644
> --- a/arch/arm/boot/dts/am335x-evm.dts
> +++ b/arch/arm/boot/dts/am335x-evm.dts
> @@ -171,6 +171,26 @@
> };
> };
>
> + musb: usb@47400000 {
> + status = "okay";
> +
> + phy@47401300 {
> + status = "okay";
> + };
> +
> + phy@47401b00 {
> + status = "okay";
> + };
> +
> + usb@47401000 {
> + status = "no";
> + };
Any reason usb0 is disabled for am33xx evm? Just for testing?
> +
> + usb@47401800 {
> + status = "okay";
> + };
> + };
> +
> i2c1: i2c@4802a000 {
> pinctrl-names = "default";
> pinctrl-0 = <&i2c1_pins>;
> diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
> index 0c8ad17..766c23a 100644
> --- a/arch/arm/boot/dts/am335x-evmsk.dts
> +++ b/arch/arm/boot/dts/am335x-evmsk.dts
> @@ -207,6 +207,18 @@
> };
> };
>
> + musb: usb@47400000 {
> + status = "okay";
> +
> + phy@47401300 {
> + status = "okay";
> + };
> +
> + usb@47401000 {
> + status = "okay";
> + };
> + };
> +
> epwmss2: epwmss@48304000 {
> status = "okay";
>
> diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
> index 38b446b..81afb27 100644
> --- a/arch/arm/boot/dts/am33xx.dtsi
> +++ b/arch/arm/boot/dts/am33xx.dtsi
> @@ -26,6 +26,10 @@
> serial5 = &uart5;
> d_can0 = &dcan0;
> d_can1 = &dcan1;
> + usb0 = &usb0;
> + usb1 = &usb1;
> + phy0 = &usb0_phy;
> + phy1 = &usb1_phy;
> };
>
> cpus {
> @@ -333,21 +337,78 @@
> status = "disabled";
> };
>
> - usb@47400000 {
> - compatible = "ti,musb-am33xx";
> - reg = <0x47400000 0x1000 /* usbss */
> - 0x47401000 0x800 /* musb instance 0 */
> - 0x47401800 0x800>; /* musb instance 1 */
> - interrupts = <17 /* usbss */
> - 18 /* musb instance 0 */
> - 19>; /* musb instance 1 */
> - multipoint = <1>;
> - num-eps = <16>;
> - ram-bits = <12>;
> - port0-mode = <3>;
> - port1-mode = <3>;
> - power = <250>;
> + usb: usb@47400000 {
> + compatible = "ti,am33xx-usb";
> + reg = <0x47400000 0x1000>;
> + ranges;
> + #address-cells = <1>;
> + #size-cells = <1>;
> ti,hwmods = "usb_otg_hs";
> + status = "disabled";
> +
> + usb0_phy: phy@47401300 {
> + compatible = "ti,am335x-usb-phy";
> + reg = <0x44e10620 0x8
> + 0x47401300 0x100>;
> + reg-names = "reset_mod", "phy";
> + status = "disabled";
> + };
> +
> + usb0: usb@47401000 {
> + compatible = "ti,musb-am33xx";
> + ranges;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x47401000 0x200>;
> + reg-names = "control";
> + status = "disabled";
> +
> + musb0: usb@47401400 {
> + compatible = "mg,musbmhdrc";
> + reg = <0x47401400 0x400>;
> + reg-names = "mc";
> + interrupts = <18>;
> + interrupt-names = "mc";
> + multipoint = <1>;
> + num-eps = <16>;
> + ram-bits = <12>;
> + port-mode = <3>;
> + power = <250>;
> + phys = <&usb0_phy>;
> + };
> + };
> +
> + usb1_phy: phy@47401b00 {
> + compatible = "ti,am335x-usb-phy";
> + reg = <0x44e10628 0x8
> + 0x47401b00 0x100>;
> + reg-names = "reset_mod", "phy";
> + status = "disabled";
> + };
> +
> + usb1: usb@47401800 {
> + compatible = "ti,musb-am33xx";
> + ranges;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x47401800 0x200>;
> + reg-names = "control";
> + status = "disabled";
> +
> + musb1: usb@47401c00 {
> + compatible = "mg,musbmhdrc";
> + reg = <0x47401c00 0x400>;
> + reg-names = "mc";
> + interrupts = <19>;
> + interrupt-names = "mc";
> + multipoint = <1>;
> + num-eps = <16>;
> + ram-bits = <12>;
> + port-mode = <3>;
> + power = <250>;
> + phys = <&usb1_phy>;
> + };
> + };
> };
>
> epwmss0: epwmss@48300000 {
> diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
> index 797e3fd..b7257ae 100644
> --- a/drivers/usb/musb/Kconfig
> +++ b/drivers/usb/musb/Kconfig
> @@ -83,6 +83,7 @@ config USB_MUSB_AM35X
>
> config USB_MUSB_DSPS
> tristate "TI DSPS platforms"
> + select USB_MUSB_AM335X_CHILD
>
> config USB_MUSB_BLACKFIN
> tristate "Blackfin"
> @@ -93,6 +94,9 @@ config USB_MUSB_UX500
>
> endchoice
>
> +config USB_MUSB_AM335X_CHILD
> + tristate
> +
> choice
> prompt 'MUSB DMA mode'
> default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
> diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
> index 2b82ed7..52f552c 100644
> --- a/drivers/usb/musb/Makefile
> +++ b/drivers/usb/musb/Makefile
> @@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
> obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
> obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
>
> +
> +obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o
> +
> # the kconfig must guarantee that only one of the
> # possible I/O schemes will be enabled at a time ...
> # PIO only, or DMA (several potential schemes).
> diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c
> new file mode 100644
> index 0000000..41ac5b5
> --- /dev/null
> +++ b/drivers/usb/musb/musb_am335x.c
> @@ -0,0 +1,55 @@
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +
> +static int am335x_child_probe(struct platform_device *pdev)
> +{
> + int ret;
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> + if (ret)
> + goto err;
> +
> + return 0;
> +err:
> + pm_runtime_disable(&pdev->dev);
> + return ret;
> +}
> +
> +static int of_remove_populated_child(struct device *dev, void *d)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> +
> + of_device_unregister(pdev);
> + return 0;
> +}
> +
> +static int am335x_child_remove(struct platform_device *pdev)
> +{
> + device_for_each_child(&pdev->dev, NULL, of_remove_populated_child);
> + pm_runtime_disable(&pdev->dev);
> + return 0;
> +}
> +
> +static const struct of_device_id am335x_child_of_match[] = {
> + { .compatible = "ti,am33xx-usb" },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, am335x_child_of_match);
> +
> +static struct platform_driver am335x_child_driver = {
> + .probe = am335x_child_probe,
> + .remove = am335x_child_remove,
> + .driver = {
> + .name = "am335x-usb-childs",
> + .of_match_table = of_match_ptr(am335x_child_of_match),
> + },
> +};
> +
> +module_platform_driver(am335x_child_driver);
> +MODULE_DESCRIPTION("AM33xx child devices");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
> index 1440fac..37ebcbc 100644
> --- a/drivers/usb/musb/musb_dsps.c
> +++ b/drivers/usb/musb/musb_dsps.c
> @@ -43,6 +43,7 @@
> #include <linux/of.h>
> #include <linux/of_device.h>
> #include <linux/of_address.h>
> +#include <linux/of_irq.h>
>
> #include "musb_core.h"
>
> @@ -106,10 +107,7 @@ struct dsps_musb_wrapper {
> /* bit positions for mode */
> unsigned iddig:5;
> /* miscellaneous stuff */
> - u32 musb_core_offset;
> u8 poll_seconds;
> - /* number of musb instances */
> - u8 instances;
> };
>
> /**
> @@ -117,10 +115,10 @@ struct dsps_musb_wrapper {
> */
> struct dsps_glue {
> struct device *dev;
> - struct platform_device *musb[2]; /* child musb pdev */
> + struct platform_device *musb; /* child musb pdev */
> const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
> - struct timer_list timer[2]; /* otg_workaround timer */
> - unsigned long last_timer[2]; /* last timer data for each instance */
> + struct timer_list timer; /* otg_workaround timer */
> + unsigned long last_timer; /* last timer data for each instance */
> };
>
> /**
> @@ -170,7 +168,6 @@ static void otg_timer(unsigned long _musb)
> struct musb *musb = (void *)_musb;
> void __iomem *mregs = musb->mregs;
> struct device *dev = musb->controller;
> - struct platform_device *pdev = to_platform_device(dev);
> struct dsps_glue *glue = dev_get_drvdata(dev->parent);
> const struct dsps_musb_wrapper *wrp = glue->wrp;
> u8 devctl;
> @@ -207,7 +204,7 @@ static void otg_timer(unsigned long _musb)
> case OTG_STATE_B_IDLE:
> devctl = dsps_readb(mregs, MUSB_DEVCTL);
> if (devctl & MUSB_DEVCTL_BDEVICE)
> - mod_timer(&glue->timer[pdev->id],
> + mod_timer(&glue->timer,
> jiffies + wrp->poll_seconds * HZ);
> else
> musb->xceiv->state = OTG_STATE_A_IDLE;
> @@ -221,7 +218,6 @@ static void otg_timer(unsigned long _musb)
> static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
> {
> struct device *dev = musb->controller;
> - struct platform_device *pdev = to_platform_device(dev);
> struct dsps_glue *glue = dev_get_drvdata(dev->parent);
>
> if (timeout == 0)
> @@ -232,23 +228,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
> musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
> dev_dbg(musb->controller, "%s active, deleting timer\n",
> usb_otg_state_string(musb->xceiv->state));
> - del_timer(&glue->timer[pdev->id]);
> - glue->last_timer[pdev->id] = jiffies;
> + del_timer(&glue->timer);
> + glue->last_timer = jiffies;
> return;
> }
>
> - if (time_after(glue->last_timer[pdev->id], timeout) &&
> - timer_pending(&glue->timer[pdev->id])) {
> + if (time_after(glue->last_timer, timeout) &&
> + timer_pending(&glue->timer)) {
> dev_dbg(musb->controller,
> "Longer idle timer already pending, ignoring...\n");
> return;
> }
> - glue->last_timer[pdev->id] = timeout;
> + glue->last_timer = timeout;
>
> dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
> usb_otg_state_string(musb->xceiv->state),
> jiffies_to_msecs(timeout - jiffies));
> - mod_timer(&glue->timer[pdev->id], timeout);
> + mod_timer(&glue->timer, timeout);
> }
>
> static irqreturn_t dsps_interrupt(int irq, void *hci)
> @@ -256,7 +252,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
> struct musb *musb = hci;
> void __iomem *reg_base = musb->ctrl_base;
> struct device *dev = musb->controller;
> - struct platform_device *pdev = to_platform_device(dev);
> struct dsps_glue *glue = dev_get_drvdata(dev->parent);
> const struct dsps_musb_wrapper *wrp = glue->wrp;
> unsigned long flags;
> @@ -316,7 +311,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
> */
> musb->int_usb &= ~MUSB_INTR_VBUSERROR;
> musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
> - mod_timer(&glue->timer[pdev->id],
> + mod_timer(&glue->timer,
> jiffies + wrp->poll_seconds * HZ);
> WARNING("VBUS error workaround (delay coming)\n");
> } else if (drvvbus) {
> @@ -324,7 +319,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
> MUSB_HST_MODE(musb);
> musb->xceiv->otg->default_a = 1;
> musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
> - del_timer(&glue->timer[pdev->id]);
> + del_timer(&glue->timer);
> } else {
> musb->is_active = 0;
> MUSB_DEV_MODE(musb);
> @@ -351,8 +346,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
>
> /* Poll for ID change */
> if (musb->xceiv->state == OTG_STATE_B_IDLE)
> - mod_timer(&glue->timer[pdev->id],
> - jiffies + wrp->poll_seconds * HZ);
> + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
>
> spin_unlock_irqrestore(&musb->lock, flags);
>
> @@ -362,31 +356,34 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
> static int dsps_musb_init(struct musb *musb)
> {
> struct device *dev = musb->controller;
> - struct platform_device *pdev = to_platform_device(dev);
> struct dsps_glue *glue = dev_get_drvdata(dev->parent);
> + struct platform_device *parent = to_platform_device(dev->parent);
> const struct dsps_musb_wrapper *wrp = glue->wrp;
> - void __iomem *reg_base = musb->ctrl_base;
> + void __iomem *reg_base;
> + struct resource *r;
> u32 rev, val;
> - int status;
>
> - /* mentor core register starts at offset of 0x400 from musb base */
> - musb->mregs += wrp->musb_core_offset;
> + r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
> + if (!r)
> + return -EINVAL;
> +
> + reg_base = devm_ioremap_resource(dev, r);
> + if (!musb->ctrl_base)
> + return -EINVAL;
> + musb->ctrl_base = reg_base;
>
> /* NOP driver needs change if supporting dual instance */
> - musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0);
> - if (IS_ERR_OR_NULL(musb->xceiv))
> - return -EPROBE_DEFER;
> + musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
> + if (IS_ERR(musb->xceiv))
> + return PTR_ERR(musb->xceiv);
>
> /* Returns zero if e.g. not clocked */
> rev = dsps_readl(reg_base, wrp->revision);
> - if (!rev) {
> - status = -ENODEV;
> - goto err0;
> - }
> + if (!rev)
> + return -ENODEV;
>
> usb_phy_init(musb->xceiv);
> -
> - setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
> + setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
>
> /* Reset the musb */
> dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
> @@ -402,17 +399,14 @@ static int dsps_musb_init(struct musb *musb)
> dsps_writel(reg_base, wrp->eoi, 0);
>
> return 0;
> -err0:
> - return status;
> }
>
> static int dsps_musb_exit(struct musb *musb)
> {
> struct device *dev = musb->controller;
> - struct platform_device *pdev = to_platform_device(dev);
> struct dsps_glue *glue = dev_get_drvdata(dev->parent);
>
> - del_timer_sync(&glue->timer[pdev->id]);
> + del_timer_sync(&glue->timer);
>
> usb_phy_shutdown(musb->xceiv);
> return 0;
> @@ -430,106 +424,98 @@ static struct musb_platform_ops dsps_ops = {
>
> static u64 musb_dmamask = DMA_BIT_MASK(32);
>
> -static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
> +static int get_int_prop(struct device_node *dn, const char *s)
> {
> - struct device *dev = glue->dev;
> - struct platform_device *pdev = to_platform_device(dev);
> - struct musb_hdrc_platform_data *pdata = dev->platform_data;
> - struct device_node *np = pdev->dev.of_node;
> - struct musb_hdrc_config *config;
> - struct platform_device *musb;
> - struct resource *res;
> + int ret;
> + u32 val;
> +
> + ret = of_property_read_u32(dn, s, &val);
> + if (ret)
> + return 0;
> + return val;
> +}
> +
> +static int dsps_create_musb_pdev(struct dsps_glue *glue,
> + struct platform_device *parent)
> +{
> + struct musb_hdrc_platform_data pdata;
> struct resource resources[2];
> - char res_name[11];
> + struct device *dev = &parent->dev;
> + struct musb_hdrc_config *config;
> + struct platform_device *musb;
> + struct device_node *dn = parent->dev.of_node;
> + struct device_node *child_node;
> int ret;
>
> - /* first resource is for usbss, so start index from 1 */
> - res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
> - if (!res) {
> - dev_err(dev, "failed to get memory for instance %d\n", id);
> - ret = -ENODEV;
> - goto err0;
> + child_node = of_get_child_by_name(dn, "usb");
> + if (!child_node)
> + return -EINVAL;
> +
> + memset(resources, 0, sizeof(resources));
> + ret = of_address_to_resource(child_node, 0, &resources[0]);
> + if (ret) {
> + dev_err(dev, "failed to get memory.\n");
> + return ret;
> }
> - res->parent = NULL;
> - resources[0] = *res;
> -
> - /* first resource is for usbss, so start index from 1 */
> - res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
> - if (!res) {
> - dev_err(dev, "failed to get irq for instance %d\n", id);
> - ret = -ENODEV;
> - goto err0;
> +
> + ret = of_irq_to_resource(child_node, 0, &resources[1]);
> + if (ret == 0) {
> + dev_err(dev, "failed to get irq.\n");
> + ret = -EINVAL;
> + return ret;
> }
> - res->parent = NULL;
> - resources[1] = *res;
> - resources[1].name = "mc";
>
> /* allocate the child platform device */
> musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
> if (!musb) {
> dev_err(dev, "failed to allocate musb device\n");
> - ret = -ENOMEM;
> - goto err0;
> + return -ENOMEM;
> }
>
> musb->dev.parent = dev;
> musb->dev.dma_mask = &musb_dmamask;
> musb->dev.coherent_dma_mask = musb_dmamask;
> + musb->dev.of_node = of_node_get(child_node);
>
> - glue->musb[id] = musb;
> + glue->musb = musb;
>
> - ret = platform_device_add_resources(musb, resources, 2);
> + ret = platform_device_add_resources(musb, resources,
> + ARRAY_SIZE(resources));
> if (ret) {
> dev_err(dev, "failed to add resources\n");
> - goto err2;
> + goto err;
> }
>
> - if (np) {
> - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> - if (!pdata) {
> - dev_err(&pdev->dev,
> - "failed to allocate musb platform data\n");
> - ret = -ENOMEM;
> - goto err2;
> - }
> -
> - config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
> - if (!config) {
> - dev_err(&pdev->dev,
> - "failed to allocate musb hdrc config\n");
> - ret = -ENOMEM;
> - goto err2;
> - }
> -
> - of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
> - of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
> - snprintf(res_name, sizeof(res_name), "port%d-mode", id);
> - of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
> - of_property_read_u32(np, "power", (u32 *)&pdata->power);
> - config->multipoint = of_property_read_bool(np, "multipoint");
> -
> - pdata->config = config;
> + config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
> + if (!config) {
> + dev_err(dev, "failed to allocate musb hdrc config\n");
> + ret = -ENOMEM;
> + goto err;
> }
> + pdata.config = config;
> + pdata.platform_ops = &dsps_ops;
>
> - pdata->platform_ops = &dsps_ops;
> + config->num_eps = get_int_prop(child_node, "num-eps");
> + config->ram_bits = get_int_prop(child_node, "ram-bits");
> + pdata.mode = get_int_prop(child_node, "port-mode");
> + pdata.power = get_int_prop(child_node, "power");
> + config->multipoint = of_property_read_bool(child_node, "multipoint");
>
> - ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
> + ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
> if (ret) {
> dev_err(dev, "failed to add platform_data\n");
> - goto err2;
> + goto err;
> }
>
> ret = platform_device_add(musb);
> if (ret) {
> dev_err(dev, "failed to register musb device\n");
> - goto err2;
> + goto err;
> }
> -
> return 0;
>
> -err2:
> +err:
> platform_device_put(musb);
> -err0:
> return ret;
> }
>
> @@ -538,14 +524,12 @@ static int dsps_probe(struct platform_device *pdev)
> const struct of_device_id *match;
> const struct dsps_musb_wrapper *wrp;
> struct dsps_glue *glue;
> - struct resource *iomem;
> - int ret, i;
> + int ret;
>
> match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
> if (!match) {
> dev_err(&pdev->dev, "fail to get matching of_match struct\n");
> - ret = -EINVAL;
> - goto err0;
> + return -EINVAL;
> }
> wrp = match->data;
>
> @@ -553,29 +537,13 @@ static int dsps_probe(struct platform_device *pdev)
> glue = kzalloc(sizeof(*glue), GFP_KERNEL);
> if (!glue) {
> dev_err(&pdev->dev, "unable to allocate glue memory\n");
> - ret = -ENOMEM;
> - goto err0;
> - }
> -
> - /* get memory resource */
> - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!iomem) {
> - dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
> - ret = -ENODEV;
> - goto err1;
> + return -ENOMEM;
> }
>
> glue->dev = &pdev->dev;
> + glue->wrp = wrp;
>
> - glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
> - if (!glue->wrp) {
> - dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
> - ret = -ENOMEM;
> - goto err1;
> - }
> platform_set_drvdata(pdev, glue);
> -
> - /* enable the usbss clocks */
> pm_runtime_enable(&pdev->dev);
>
> ret = pm_runtime_get_sync(&pdev->dev);
> @@ -584,17 +552,9 @@ static int dsps_probe(struct platform_device *pdev)
> goto err2;
> }
>
> - /* create the child platform device for all instances of musb */
> - for (i = 0; i < wrp->instances ; i++) {
> - ret = dsps_create_musb_pdev(glue, i);
> - if (ret != 0) {
> - dev_err(&pdev->dev, "failed to create child pdev\n");
> - /* release resources of previously created instances */
> - for (i--; i >= 0 ; i--)
> - platform_device_unregister(glue->musb[i]);
> - goto err3;
> - }
> - }
> + ret = dsps_create_musb_pdev(glue, pdev);
> + if (ret)
> + goto err3;
>
> return 0;
>
> @@ -602,26 +562,19 @@ static int dsps_probe(struct platform_device *pdev)
> pm_runtime_put(&pdev->dev);
> err2:
> pm_runtime_disable(&pdev->dev);
> - kfree(glue->wrp);
> -err1:
> kfree(glue);
> -err0:
> return ret;
> }
> +
> static int dsps_remove(struct platform_device *pdev)
> {
> struct dsps_glue *glue = platform_get_drvdata(pdev);
> - const struct dsps_musb_wrapper *wrp = glue->wrp;
> - int i;
>
> - /* delete the child platform device */
> - for (i = 0; i < wrp->instances ; i++)
> - platform_device_unregister(glue->musb[i]);
> + platform_device_unregister(glue->musb);
>
> /* disable usbss clocks */
> pm_runtime_put(&pdev->dev);
> pm_runtime_disable(&pdev->dev);
> - kfree(glue->wrp);
> kfree(glue);
> return 0;
> }
> @@ -652,9 +605,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
> .rxep_shift = 16,
> .rxep_mask = 0xfffe,
> .rxep_bitmap = (0xfffe << 16),
> - .musb_core_offset = 0x400,
> .poll_seconds = 2,
> - .instances = 1,
> };
>
> static const struct of_device_id musb_dsps_of_match[] = {
> @@ -678,14 +629,4 @@ MODULE_AUTHOR("Ravi B <[email protected]>");
> MODULE_AUTHOR("Ajay Kumar Gupta <[email protected]>");
> MODULE_LICENSE("GPL v2");
>
> -static int __init dsps_init(void)
> -{
> - return platform_driver_register(&dsps_usbss_driver);
> -}
> -subsys_initcall(dsps_init);
> -
> -static void __exit dsps_exit(void)
> -{
> - platform_driver_unregister(&dsps_usbss_driver);
> -}
> -module_exit(dsps_exit);
> +module_platform_driver(dsps_usbss_driver);
--
-George
On 07/23/2013 08:04 AM, George Cherian wrote:
> Hi Sebastian,
>
>
> On 7/22/2013 11:39 PM, Sebastian Andrzej Siewior wrote:
>
>> This patch renames the type struct from ti81xx_driver_data to
>> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
>> member is also removed since the am33xx SoC does not have such register.
>> The interrupt is acknowledged by writting into the stat register.
>>
>
> AM335X TRM Section 16.6.5 and 16.7.5 describes about EOI registers.
> Its at offset 0x24. Or is it that the interrupts are acknowledged even
> without writing to eoi register?
I have here "Literature Number: SPRUH73H October 2011 ? Revised April
2013" which calls itself "AM335x ARM? CortexTM-A8 Microprocessors
(MPUs) Technical Reference Manual".
This document ends with 16.5 that means there is no chapter 16.6 or
16.7. The next one is 17.
16.5.2 and 16.5.3 describes the available registers of
USB[01]_CTRL REGISTERS which is where the EOI register is accessed. I
see here
20h USB0IRQMSTAT
28h USB0IRQSTATRAW0
so no 0x24 at least in my document.
Sebastian
On 7/23/2013 2:39 PM, Sebastian Andrzej Siewior wrote:
> On 07/23/2013 08:04 AM, George Cherian wrote:
>> Hi Sebastian,
>>
>>
>> On 7/22/2013 11:39 PM, Sebastian Andrzej Siewior wrote:
>>
>>> This patch renames the type struct from ti81xx_driver_data to
>>> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
>>> member is also removed since the am33xx SoC does not have such register.
>>> The interrupt is acknowledged by writting into the stat register.
>>>
>> AM335X TRM Section 16.6.5 and 16.7.5 describes about EOI registers.
>> Its at offset 0x24. Or is it that the interrupts are acknowledged even
>> without writing to eoi register?
> I have here "Literature Number: SPRUH73H October 2011 ? Revised April
> 2013" which calls itself "AM335x ARM? CortexTM-A8 Microprocessors
> (MPUs) Technical Reference Manual".
Looks like I have an old TRM with me, which has EOI register at 24h.
I need to update my TRM. ;)
> This document ends with 16.5 that means there is no chapter 16.6 or
> 16.7. The next one is 17.
> 16.5.2 and 16.5.3 describes the available registers of
> USB[01]_CTRL REGISTERS which is where the EOI register is accessed. I
> see here
>
> 20h USB0IRQMSTAT
> 28h USB0IRQSTATRAW0
>
> so no 0x24 at least in my document.
>
> Sebastian
--
-George
On 07/23/2013 08:46 AM, George Cherian wrote:
>> diff --git a/arch/arm/boot/dts/am335x-evm.dts
>> b/arch/arm/boot/dts/am335x-evm.dts
>> index 3aee1a4..a3a642a 100644
>> --- a/arch/arm/boot/dts/am335x-evm.dts
>> +++ b/arch/arm/boot/dts/am335x-evm.dts
>> @@ -171,6 +171,26 @@
>> };
>> };
>> + musb: usb@47400000 {
>> + status = "okay";
>> +
>> + phy@47401300 {
>> + status = "okay";
>> + };
>> +
>> + phy@47401b00 {
>> + status = "okay";
>> + };
>> +
>> + usb@47401000 {
>> + status = "no";
>> + };
> Any reason usb0 is disabled for am33xx evm? Just for testing?
No, that is an error and will be corrected.
Please try to reduce the email in reply to sane size / context. Here
the reader notices the file you refer to and your comment. Quoting the
whole patch eats up more resources for processing plus the reader might
overlook additional comments (he most likely will search for at least
one line).
Sebastian
On 07/22/2013 08:52 PM, Sergei Shtylyov wrote:
>> @@ -416,6 +418,7 @@ struct dma_async_tx_descriptor {
>> dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
>> dma_async_tx_callback callback;
>> void *callback_param;
>> + unsigned int transfered;
>
> Correct grammar is "transferred".
Thanks, corrected.
>
> WBR, Sergei
Sebastian
On 07/23/2013 07:28 PM, Bin Liu wrote:
> Hi,
Hi,
>
> On Mon, Jul 22, 2013 at 1:10 PM, Sebastian Andrzej Siewior
> <[email protected] <mailto:[email protected]>> wrote:
>
> This patch adds the MUSB_DEVCTL_SESSION back after it has been removed.
> If it is missing then the host session is not recognized. This bit is
> added initially added in musb_start() and removed after the first device
> disconnect.
>
> AFAIK, after the device is disconnected, the OTG state machine will go
> back to B_IDLE/A_IDLE state. SESSION is not needed in this case.
Okay.
> In OTG mode, when no device is plugged, the ID pin is floating, you can
> never hold the host session in this case, even set the SESSION bit. The
> SESSION bit will be cleared by the controller after 100ms.
In my testing the bit remains set. How is the bit supposed to come back
after I connect a host device?
> Regards,
> -Bin.
>
Sebastian
Hi Sebastian,
On Tue, Jul 23, 2013 at 12:31 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
>
> On 07/23/2013 07:28 PM, Bin Liu wrote:
> > Hi,
>
> Hi,
>
> >
> > On Mon, Jul 22, 2013 at 1:10 PM, Sebastian Andrzej Siewior
> > <[email protected] <mailto:[email protected]>> wrote:
> >
> > This patch adds the MUSB_DEVCTL_SESSION back after it has been removed.
> > If it is missing then the host session is not recognized. This bit is
> > added initially added in musb_start() and removed after the first device
> > disconnect.
> >
> > AFAIK, after the device is disconnected, the OTG state machine will go
> > back to B_IDLE/A_IDLE state. SESSION is not needed in this case.
>
>
> Okay.
>
> > In OTG mode, when no device is plugged, the ID pin is floating, you can
> > never hold the host session in this case, even set the SESSION bit. The
> > SESSION bit will be cleared by the controller after 100ms.
>
> In my testing the bit remains set. How is the bit supposed to come back
> after I connect a host device?
The bit remains even when no device is plugged and ID ping is float?
what platform do you use to test it?
'a host device'? you meant a usb device? By the otg specs, the session
will not automatically start. The user/app has to issue the command,
either by SRP or HNP, or something else. In TI 3.2 kernel, there is
workaround in otg_timer() to _toggle_ the SESSION bit to detect if ID
pin is grounded, which means a USB device is connected.
Regards,
-Bin.
>
> > Regards,
> > -Bin.
> >
>
> Sebastian
(re-send, due to last delivery failure to the mailing list...)
On Tue, Jul 23, 2013 at 1:23 PM, Bin Liu <[email protected]> wrote:
> Hi Sebastian,
>
> On Mon, Jul 22, 2013 at 1:09 PM, Sebastian Andrzej Siewior
> <[email protected]> wrote:
>>
>> This patch renames the type struct from ti81xx_driver_data to
>> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
>> member is also removed since the am33xx SoC does not have such register.
>> The interrupt is acknowledged by writting into the stat register.
>
> I guess the EOI register is removed from the TRM because AM33xx does not use
> it, there is no need to write to it to acknowledge. It does not hurt to
> write to it though since the register still exists, it just does nothing, I
> guess.
>
> But I am not sure if it is a good idea to remove eoi from the musb_dsps
> driver. If the intension is to merge the support for other SoC, such as
> AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
> how those devices use EOI.
>
> Regards,
> -Bin.
On Mon, Jul 22, 2013 at 08:09:52PM +0200, Sebastian Andrzej Siewior wrote:
> If the init / shutdown function of the phy moves out of dsps into the
> phy driver, then dsps needs to call the callbacks of the phy driver to
> ensure that this happens.
>
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
cool, eventually we should move these calls to musb_core.c though.
--
balbi
On Mon, Jul 22, 2013 at 08:09:53PM +0200, Sebastian Andrzej Siewior wrote:
> The am335x PHY code is well hidden in multiple places. The glue layer
> uses the nop and does up/down in the background. This patch copies the
> power on / power off part out of dsps so it can be removed later in
> dsps. At this point I am not sure if it is better to write a new phy
> driver for am335x or just add the missing pieces to this one.
>
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
right, I replied to the wrong series, please add a patch renaming file
and functions to phy-generic.c/usb_phy_gen_
or something similar.
--
balbi
* Bin Liu | 2013-07-23 13:23:57 [-0500]:
>Hi Sebastian,
Hi Liu,
>On Mon, Jul 22, 2013 at 1:09 PM, Sebastian Andrzej Siewior <
>[email protected]> wrote:
>
>> This patch renames the type struct from ti81xx_driver_data to
>> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
>> member is also removed since the am33xx SoC does not have such register.
>> The interrupt is acknowledged by writting into the stat register.
>>
>I guess the EOI register is removed from the TRM because AM33xx does not
>use it, there is no need to write to it to acknowledge. It does not hurt to
>write to it though since the register still exists, it just does nothing, I
>guess.
Is it really there or was it never there and it has been added to TRM by
accident?
>But I am not sure if it is a good idea to remove eoi from the musb_dsps
>driver. If the intension is to merge the support for other SoC, such as
>AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
>how those devices use EOI.
If one of the architectures gets added which need an EOI then the offset
can be 0 and the EOI will happen only if it is != 0.
>
>Regards,
>-Bin.
Sebastian
* Felipe Balbi | 2013-07-25 17:33:30 [+0300]:
>On Mon, Jul 22, 2013 at 08:09:53PM +0200, Sebastian Andrzej Siewior wrote:
>right, I replied to the wrong series, please add a patch renaming file
>and functions to phy-generic.c/usb_phy_gen_
Sorry, I can't parse that.
You want to rename phy-nop.c to phy-generic.c and add the additional
functions in usb_phy_gen.c?
>or something similar.
Sebastian
On Thu, Jul 25, 2013 at 04:45:29PM +0200, Sebastian Andrzej Siewior wrote:
> * Felipe Balbi | 2013-07-25 17:33:30 [+0300]:
>
> >On Mon, Jul 22, 2013 at 08:09:53PM +0200, Sebastian Andrzej Siewior wrote:
> >right, I replied to the wrong series, please add a patch renaming file
> >and functions to phy-generic.c/usb_phy_gen_
>
> Sorry, I can't parse that.
> You want to rename phy-nop.c to phy-generic.c and add the additional
> functions in usb_phy_gen.c?
$ git mv drivers/usb/phy/phy-nop.c drivers/usb/phy/phy-generic.c
$ sed -i 's/\<nop_/usb_phy_gen_/g' drivers/usb/phy/phy-generic.c
--
balbi
On 07/22/2013 08:10 PM, Sebastian Andrzej Siewior wrote:
> In USB RX path it is possible that the we receive less bytes than
> requested. Take the following example:
> The driver for USB-to-UART submits an URB with 256 bytes in size and the
> dmaengine driver in turn programs a transfer of 256 bytes. The transfer
> is programmed and the dma engine waits for the data to arrive. Once data
> is sent on the UART the dma engine begins to move data. If there was
> only one data byte in the USB packet received then the DMA engine will
> only move one byte due to USB restrictions / rules. The real size of the
> transfer has to be notified to the user / caller so he set this to the
> caller.
> This patch adds the transfered member to the dma_async_tx_descriptor
> where the caller can obtain the final size.
I'm not sure that this will work. Once you've submitted the descriptor it is
owned by the dmaengine driver and you are not allowed to dereference it
anymore since the dmaengine driver might free the memory at any time. You
should only reference the descriptor by the cookie returned by submit().
- Lars
On 07/25/2013 04:57 PM, Lars-Peter Clausen wrote:
> I'm not sure that this will work. Once you've submitted the descriptor it is
> owned by the dmaengine driver and you are not allowed to dereference it
> anymore since the dmaengine driver might free the memory at any time. You
> should only reference the descriptor by the cookie returned by submit().
I see. But it can't be reused before calling the callback if it is
going to call the callback, right?
So if this is a no-no, I'm left with an additional argument to the
complete callback?
> - Lars
Sebastian
Sebastian,
On Thu, Jul 25, 2013 at 9:41 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> * Bin Liu | 2013-07-23 13:23:57 [-0500]:
>
>>Hi Sebastian,
> Hi Liu,
>
>>On Mon, Jul 22, 2013 at 1:09 PM, Sebastian Andrzej Siewior <
>>[email protected]> wrote:
>>
>>> This patch renames the type struct from ti81xx_driver_data to
>>> am33xx_driver_data since it is not used for ti81xx anymore. The EOI
>>> member is also removed since the am33xx SoC does not have such register.
>>> The interrupt is acknowledged by writting into the stat register.
>>>
>>I guess the EOI register is removed from the TRM because AM33xx does not
>>use it, there is no need to write to it to acknowledge. It does not hurt to
>>write to it though since the register still exists, it just does nothing, I
>>guess.
>
> Is it really there or was it never there and it has been added to TRM by
> accident?
The EOI register IS in the USB subsystem of AM33xx, but the SoC does
not use it because it uses level triggering for USB interrupt.
>
>>But I am not sure if it is a good idea to remove eoi from the musb_dsps
>>driver. If the intension is to merge the support for other SoC, such as
>>AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
>>how those devices use EOI.
>
> If one of the architectures gets added which need an EOI then the offset
> can be 0 and the EOI will happen only if it is != 0.
This patch cleaned up the use of EOI. Do you mean EOI handling will be
added back with condition EOI offset != 0, when the support of new
device which uses EIO is added?
Regards,
-Bin.
>
>>
>>Regards,
>>-Bin.
>
> Sebastian
On 07/25/2013 05:12 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
>> Is it really there or was it never there and it has been added to TRM by
>> accident?
> The EOI register IS in the USB subsystem of AM33xx, but the SoC does
> not use it because it uses level triggering for USB interrupt.
I see.
>>> But I am not sure if it is a good idea to remove eoi from the musb_dsps
>>> driver. If the intension is to merge the support for other SoC, such as
>>> AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
>>> how those devices use EOI.
>>
>> If one of the architectures gets added which need an EOI then the offset
>> can be 0 and the EOI will happen only if it is != 0.
> This patch cleaned up the use of EOI. Do you mean EOI handling will be
> added back with condition EOI offset != 0, when the support of new
> device which uses EIO is added?
That is my intention.
> Regards,
> -Bin.
Sebastian
Sebastian,
On Thu, Jul 25, 2013 at 10:16 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> On 07/25/2013 05:12 PM, Bin Liu wrote:
>> Sebastian,
>
> Hi Bin,
>
>>> Is it really there or was it never there and it has been added to TRM by
>>> accident?
>> The EOI register IS in the USB subsystem of AM33xx, but the SoC does
>> not use it because it uses level triggering for USB interrupt.
>
> I see.
>
>>>> But I am not sure if it is a good idea to remove eoi from the musb_dsps
>>>> driver. If the intension is to merge the support for other SoC, such as
>>>> AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
>>>> how those devices use EOI.
>>>
>>> If one of the architectures gets added which need an EOI then the offset
>>> can be 0 and the EOI will happen only if it is != 0.
>> This patch cleaned up the use of EOI. Do you mean EOI handling will be
>> added back with condition EOI offset != 0, when the support of new
>> device which uses EIO is added?
>
> That is my intention.
Then should something like EOI cleanup be added into the commit
message for better git log searching experience? I would think the EOI
cleanup is more important then variable renaming in this patch. Or
even better to separate the changes into two patches.
>
>> Regards,
>> -Bin.
>
> Sebastian
Regards,
-Bin.
On 07/25/2013 05:12 PM, Sebastian Andrzej Siewior wrote:
> On 07/25/2013 04:57 PM, Lars-Peter Clausen wrote:
>> I'm not sure that this will work. Once you've submitted the descriptor it is
>> owned by the dmaengine driver and you are not allowed to dereference it
>> anymore since the dmaengine driver might free the memory at any time. You
>> should only reference the descriptor by the cookie returned by submit().
>
> I see. But it can't be reused before calling the callback if it is
> going to call the callback, right?
> So if this is a no-no, I'm left with an additional argument to the
> complete callback?
Hm, maybe using dmaengine_tx_status() and checking the residue field of the
state struct. transferred is basically len - residue.
Hi,
On Thu, Jul 25, 2013 at 05:16:53PM +0200, Sebastian Andrzej Siewior wrote:
> On 07/25/2013 05:12 PM, Bin Liu wrote:
> > Sebastian,
>
> Hi Bin,
>
> >> Is it really there or was it never there and it has been added to TRM by
> >> accident?
> > The EOI register IS in the USB subsystem of AM33xx, but the SoC does
> > not use it because it uses level triggering for USB interrupt.
>
> I see.
>
> >>> But I am not sure if it is a good idea to remove eoi from the musb_dsps
> >>> driver. If the intension is to merge the support for other SoC, such as
> >>> AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
> >>> how those devices use EOI.
> >>
> >> If one of the architectures gets added which need an EOI then the offset
> >> can be 0 and the EOI will happen only if it is != 0.
> > This patch cleaned up the use of EOI. Do you mean EOI handling will be
> > added back with condition EOI offset != 0, when the support of new
> > device which uses EIO is added?
>
> That is my intention.
right, I agree. If there are no users for the code, just delete it. If,
eventually, some platform comes to need it, then we add it *after* the
platform's base code is merged.
--
balbi
Hi,
On Thu, Jul 25, 2013 at 10:28:37AM -0500, Bin Liu wrote:
> Sebastian,
>
> On Thu, Jul 25, 2013 at 10:16 AM, Sebastian Andrzej Siewior
> <[email protected]> wrote:
> > On 07/25/2013 05:12 PM, Bin Liu wrote:
> >> Sebastian,
> >
> > Hi Bin,
> >
> >>> Is it really there or was it never there and it has been added to TRM by
> >>> accident?
> >> The EOI register IS in the USB subsystem of AM33xx, but the SoC does
> >> not use it because it uses level triggering for USB interrupt.
> >
> > I see.
> >
> >>>> But I am not sure if it is a good idea to remove eoi from the musb_dsps
> >>>> driver. If the intension is to merge the support for other SoC, such as
> >>>> AM35xx, AM18xx, then EOI handling might be still needed. I just don't know
> >>>> how those devices use EOI.
> >>>
> >>> If one of the architectures gets added which need an EOI then the offset
> >>> can be 0 and the EOI will happen only if it is != 0.
> >> This patch cleaned up the use of EOI. Do you mean EOI handling will be
> >> added back with condition EOI offset != 0, when the support of new
> >> device which uses EIO is added?
> >
> > That is my intention.
> Then should something like EOI cleanup be added into the commit
> message for better git log searching experience? I would think the EOI
> cleanup is more important then variable renaming in this patch. Or
> even better to separate the changes into two patches.
perhaps two separate patches would be best, indeed. At least it would
make it simpler to track regressions.
--
balbi
The ti81xx platform is not fully supported right now. This patch renames
the date structure to a am33xx prefix which is actually used.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 21838ba..28ed497 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -742,7 +742,7 @@ static int dsps_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
-static const struct dsps_musb_wrapper ti81xx_driver_data = {
+static const struct dsps_musb_wrapper am33xx_driver_data = {
.revision = 0x00,
.control = 0x14,
.status = 0x18,
@@ -774,7 +774,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
static const struct of_device_id musb_dsps_of_match[] = {
{ .compatible = "ti,musb-am33xx",
- .data = (void *) &ti81xx_driver_data, },
+ .data = (void *) &am33xx_driver_data, },
{ },
};
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
--
1.8.3.2
The EOI register is not present in the AM335x memory space according to
the TRM and thus removed.
Should any platform using the EOI register get merged then it may be
used again if the register address is not zero.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
drivers/usb/musb/musb_dsps.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 28ed497..36634e9 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -73,7 +73,6 @@ struct dsps_musb_wrapper {
u16 revision;
u16 control;
u16 status;
- u16 eoi;
u16 epintr_set;
u16 epintr_clear;
u16 epintr_status;
@@ -202,7 +201,6 @@ static void dsps_musb_disable(struct musb *musb)
dsps_writel(reg_base, wrp->epintr_clear,
wrp->txep_bitmap | wrp->rxep_bitmap);
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
- dsps_writel(reg_base, wrp->eoi, 0);
}
static void otg_timer(unsigned long _musb)
@@ -316,7 +314,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* Get usb core interrupts */
usbintr = dsps_readl(reg_base, wrp->coreintr_status);
if (!usbintr && !epintr)
- goto eoi;
+ goto out;
musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
if (usbintr)
@@ -384,16 +382,11 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
if (musb->int_tx || musb->int_rx || musb->int_usb)
ret |= musb_interrupt(musb);
- eoi:
- /* EOI needs to be written for the IRQ to be re-asserted. */
- if (ret == IRQ_HANDLED || epintr || usbintr)
- dsps_writel(reg_base, wrp->eoi, 1);
-
/* Poll for ID change */
if (musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&glue->timer[pdev->id],
jiffies + wrp->poll_seconds * HZ);
-
+out:
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -447,9 +440,6 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
- /* clear level interrupt */
- dsps_writel(reg_base, wrp->eoi, 0);
-
return 0;
err0:
usb_put_phy(musb->xceiv);
@@ -746,7 +736,6 @@ static const struct dsps_musb_wrapper am33xx_driver_data = {
.revision = 0x00,
.control = 0x14,
.status = 0x18,
- .eoi = 0x24,
.epintr_set = 0x38,
.epintr_clear = 0x40,
.epintr_status = 0x30,
--
1.8.3.2
On Thu, Jul 25, 2013 at 05:32:35PM +0200, Lars-Peter Clausen wrote:
> > I see. But it can't be reused before calling the callback if it is
> > going to call the callback, right?
> > So if this is a no-no, I'm left with an additional argument to the
> > complete callback?
>
> Hm, maybe using dmaengine_tx_status() and checking the residue field of the
> state struct. transferred is basically len - residue.
This might actually work. So this would reduce the patch to simply update the
kernel doc for residue in struct dma_tx_state that it might also be valid for
DMA_SUCCESS.
Sebastian
* Bin Liu | 2013-07-23 13:55:27 [-0500]:
>Hi Sebastian,
Hi Bin,
>> In my testing the bit remains set. How is the bit supposed to come back
>> after I connect a host device?
>The bit remains even when no device is plugged and ID ping is float?
After I set it, it remains set yes.
>what platform do you use to test it?
AM335x evm
>'a host device'? you meant a usb device? By the otg specs, the session
>will not automatically start. The user/app has to issue the command,
>either by SRP or HNP, or something else. In TI 3.2 kernel, there is
>workaround in otg_timer() to _toggle_ the SESSION bit to detect if ID
>pin is grounded, which means a USB device is connected.
I see. Let me check that TI kernel. The same thing happens however if
the musb is configured as host (not OTG).
>Regards,
>-Bin.
Sebastian
* Bin Liu | 2013-07-23 13:55:27 [-0500]:
>Hi Sebastian,
Hi Bin,
>either by SRP or HNP, or something else. In TI 3.2 kernel, there is
>workaround in otg_timer() to _toggle_ the SESSION bit to detect if ID
>pin is grounded, which means a USB device is connected.
I've been looking at
http://downloads.ti.com/sitara_linux/esd/AM335xSDK/latest/index_FDS.html
and I can't find what you are talking about. My MUSB_DEVCTL doesn't
change after I connect a device and the SESSION bit is not set. Also I
remain in a_idle state. Do you have maybe a hint for me? :)
>Regards,
>-Bin.
Sebastian
Sebastian,
On Fri, Jul 26, 2013 at 11:31 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> * Bin Liu | 2013-07-23 13:55:27 [-0500]:
>
>>Hi Sebastian,
> Hi Bin,
>
>>either by SRP or HNP, or something else. In TI 3.2 kernel, there is
>>workaround in otg_timer() to _toggle_ the SESSION bit to detect if ID
>>pin is grounded, which means a USB device is connected.
>
> I've been looking at
> http://downloads.ti.com/sitara_linux/esd/AM335xSDK/latest/index_FDS.html
>
> and I can't find what you are talking about. My MUSB_DEVCTL doesn't
> change after I connect a device and the SESSION bit is not set. Also I
> remain in a_idle state. Do you have maybe a hint for me? :)
In TI 3.2 kernel, the otg_timer() toggles the SESSION bit in
OTG_STATE_B_IDLE state. So whenever the ID pin is grounded by
connecting a device, the controller will try go into host mode.
But I have no idea why your board is in a_idle not b_idle. The toggle
does not handle a_idle.
Do you use the AM335x GP EVM, not the smaller StarterKit EVM, right?
the USB0 port on SK EVM is device only.
But anyway, I have not seen any use case which uses micro-AB
receptacle and requires such dynamic role switching. So I kind of
think it is unnecessary to implement this feature.
And it is not easy to implement it in a right way, because AM335x does
not have an interrupt for ID pin grounding, so we can only try to set
SESSION bit in otg_timer(), but that causes 2sec VBUS pulsing on the
wire, which violates the specs.
>
>>Regards,
>>-Bin.
>
> Sebastian
On Fri, Jul 26, 2013 at 12:53 PM, Bin Liu <[email protected]> wrote:
> Sebastian,
>
> On Fri, Jul 26, 2013 at 11:31 AM, Sebastian Andrzej Siewior
> <[email protected]> wrote:
>> * Bin Liu | 2013-07-23 13:55:27 [-0500]:
>>
>>>Hi Sebastian,
>> Hi Bin,
>>
>>>either by SRP or HNP, or something else. In TI 3.2 kernel, there is
>>>workaround in otg_timer() to _toggle_ the SESSION bit to detect if ID
>>>pin is grounded, which means a USB device is connected.
>>
>> I've been looking at
>> http://downloads.ti.com/sitara_linux/esd/AM335xSDK/latest/index_FDS.html
>>
>> and I can't find what you are talking about. My MUSB_DEVCTL doesn't
>> change after I connect a device and the SESSION bit is not set. Also I
>> remain in a_idle state. Do you have maybe a hint for me? :)
>
> In TI 3.2 kernel, the otg_timer() toggles the SESSION bit in
> OTG_STATE_B_IDLE state. So whenever the ID pin is grounded by
> connecting a device, the controller will try go into host mode.
> But I have no idea why your board is in a_idle not b_idle. The toggle
> does not handle a_idle.
>
> Do you use the AM335x GP EVM, not the smaller StarterKit EVM, right?
> the USB0 port on SK EVM is device only.
>
> But anyway, I have not seen any use case which uses micro-AB
> receptacle and requires such dynamic role switching. So I kind of
I meant the real customer use cases, not the EVMs ;)
On 07/26/2013 08:17 PM, Bin Liu wrote:
Hi Bin.
>> In TI 3.2 kernel, the otg_timer() toggles the SESSION bit in
>> OTG_STATE_B_IDLE state. So whenever the ID pin is grounded by
>> connecting a device, the controller will try go into host mode.
>> But I have no idea why your board is in a_idle not b_idle. The toggle
>> does not handle a_idle.
>>
>> Do you use the AM335x GP EVM, not the smaller StarterKit EVM, right?
>> the USB0 port on SK EVM is device only.
>>
>> But anyway, I have not seen any use case which uses micro-AB
>> receptacle and requires such dynamic role switching. So I kind of
>
> I meant the real customer use cases, not the EVMs ;)
>
I am using the about the second port on am335x evm which is used as
host (not OTG mode (3) but HOST (1)). If I start the timer OTG after
disconnect I see that it gets back to A mode:
[ 97.570852] musb-hdrc musb-hdrc.1.auto: Poll devctl 19 (a_wait_bcon)
[ 99.570306] musb-hdrc musb-hdrc.1.auto: Poll devctl 98 (a_idle)
?
[ 209.570259] musb-hdrc musb-hdrc.1.auto: Poll devctl 80 (a_idle)
and now the session bit is missing and never gets back so I can not
plug any other device. I really have no idea what is missing here?
Sebastian
Sebastian,
On Fri, Jul 26, 2013 at 1:22 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> On 07/26/2013 08:17 PM, Bin Liu wrote:
>
> Hi Bin.
>
>>> In TI 3.2 kernel, the otg_timer() toggles the SESSION bit in
>>> OTG_STATE_B_IDLE state. So whenever the ID pin is grounded by
>>> connecting a device, the controller will try go into host mode.
>>> But I have no idea why your board is in a_idle not b_idle. The toggle
>>> does not handle a_idle.
>>>
>>> Do you use the AM335x GP EVM, not the smaller StarterKit EVM, right?
>>> the USB0 port on SK EVM is device only.
>>>
>>> But anyway, I have not seen any use case which uses micro-AB
>>> receptacle and requires such dynamic role switching. So I kind of
>>
>> I meant the real customer use cases, not the EVMs ;)
>>
> I am using the about the second port on am335x evm which is used as
> host (not OTG mode (3) but HOST (1)). If I start the timer OTG after
> disconnect I see that it gets back to A mode:
>
> [ 97.570852] musb-hdrc musb-hdrc.1.auto: Poll devctl 19 (a_wait_bcon)
I don't think you are testing with the 3.2 kernel you referred from
the ti.com link you mentioned above.
3.2 kernel should have no '.auto' at the end of the device name.
If it is 3.8 or later, it seems the driver does something wrong,
SESSION bit should not be cleared after the device is unplugged.
> [ 99.570306] musb-hdrc musb-hdrc.1.auto: Poll devctl 98 (a_idle)
> ?
> [ 209.570259] musb-hdrc musb-hdrc.1.auto: Poll devctl 80 (a_idle)
>
> and now the session bit is missing and never gets back so I can not
> plug any other device. I really have no idea what is missing here?
>
> Sebastian
On 07/26/2013 08:29 PM, Bin Liu wrote:
Hi Bin,
>> [ 97.570852] musb-hdrc musb-hdrc.1.auto: Poll devctl 19 (a_wait_bcon)
> I don't think you are testing with the 3.2 kernel you referred from
> the ti.com link you mentioned above.
> 3.2 kernel should have no '.auto' at the end of the device name.
>
> If it is 3.8 or later, it seems the driver does something wrong,
> SESSION bit should not be cleared after the device is unplugged.
The bit is removed in otg_timer() because the phy gets into
OTG_STATE_A_WAIT_BCON.
Now, this is current HEAD + my stuff to get second port working. I
downloaded v3.2 and browsed as I was looking for the workaround, never
tested maybe I should?
On v3.8 from git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git I
don't get the second port to work. I see
[ 1.989101] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[ 1.996361] usb usb1: New USB device strings: Mfr=3, Product=2,
SerialNumber=1
[ 2.004060] usb usb1: Product: MUSB HDRC host driver
[ 2.009363] usb usb1: Manufacturer: Linux 3.8.13+ musb-hcd
[ 2.015183] usb usb1: SerialNumber: musb-hdrc.0.auto
[ 2.033653] hub 1-0:1.0: USB hub found
[ 2.037861] hub 1-0:1.0: 1 port detected
and nothing happens once I plug in the device.
Sebastian
Sebastian,
On Fri, Jul 26, 2013 at 2:55 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> The bit is removed in otg_timer() because the phy gets into
> OTG_STATE_A_WAIT_BCON.
>
> Now, this is current HEAD + my stuff to get second port working. I
> downloaded v3.2 and browsed as I was looking for the workaround, never
> tested maybe I should?
>
> On v3.8 from git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git I
> don't get the second port to work. I see
>
> [ 1.989101] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
> [ 1.996361] usb usb1: New USB device strings: Mfr=3, Product=2,
> SerialNumber=1
> [ 2.004060] usb usb1: Product: MUSB HDRC host driver
> [ 2.009363] usb usb1: Manufacturer: Linux 3.8.13+ musb-hcd
> [ 2.015183] usb usb1: SerialNumber: musb-hdrc.0.auto
> [ 2.033653] hub 1-0:1.0: USB hub found
> [ 2.037861] hub 1-0:1.0: 1 port detected
>
> and nothing happens once I plug in the device.
I started thinking when I tried this git.ti.com 3.8 kernel, I might
have done 'devmem2 0x47401c60 b 0x81' to manually set the SESSION bit
after plugged a device. It was months ago, I don't quite remember what
I tested.
My build server is down this afternoon. Once it comes back next week,
I will try 3.8 again, to see how I can help on this USB1 host mode
issue. its devctl register should stay on 0x19 even nothing is
connected.
>
> Sebastian
On 07/26/2013 10:15 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
> I started thinking when I tried this git.ti.com 3.8 kernel, I might
> have done 'devmem2 0x47401c60 b 0x81' to manually set the SESSION bit
> after plugged a device. It was months ago, I don't quite remember what
> I tested.
Ah. You cheated! :)
> My build server is down this afternoon. Once it comes back next week,
> I will try 3.8 again, to see how I can help on this USB1 host mode
> issue. its devctl register should stay on 0x19 even nothing is
> connected.
Your help is greatly appreciated. To hear what will happen :)
Sebastian
Sebastian,
On Fri, Jul 26, 2013 at 3:35 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
>> My build server is down this afternoon. Once it comes back next week,
>> I will try 3.8 again, to see how I can help on this USB1 host mode
>> issue. its devctl register should stay on 0x19 even nothing is
>> connected.
>
> Your help is greatly appreciated. To hear what will happen :)
>
> Sebastian
I have not tested it yet, but I believe I found why host mode works on
TI 3.2 kernel but not on mainline. Please look at Line 786 in 3.2
kernel musb_core.c [1].
773 if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
......
785 if (musb->a_wait_bcon != 0 &&
786 is_otg_enabled(musb))
787 musb_platform_try_idle(musb, jiffies
788 +
msecs_to_jiffies(musb->a_wait_bcon));
So when the device is unplugged, *_try_idle() is not called in host
mode, then the SESSION bit will stay set. But in mainline kernel,
*_try_idle() will be called regardless.
Please let me know your thoughts.
Regards,
-Bin.
[1] http://arago-project.org/git/projects/?p=linux-am33x.git;a=blob;f=drivers/usb/musb/musb_core.c;h=075aa5f9bec7cd041aa24eb534209fa756ed84fe;hb=refs/heads/v3.2-staging
On Mon, Jul 22, 2013 at 08:10:06PM +0200, Sebastian Andrzej Siewior wrote:
> In USB RX path it is possible that the we receive less bytes than
> requested. Take the following example:
> The driver for USB-to-UART submits an URB with 256 bytes in size and the
> dmaengine driver in turn programs a transfer of 256 bytes. The transfer
> is programmed and the dma engine waits for the data to arrive. Once data
> is sent on the UART the dma engine begins to move data. If there was
> only one data byte in the USB packet received then the DMA engine will
> only move one byte due to USB restrictions / rules. The real size of the
> transfer has to be notified to the user / caller so he set this to the
> caller.
> This patch adds the transfered member to the dma_async_tx_descriptor
> where the caller can obtain the final size.
>
> Cc: Vinod Koul <[email protected]>
> Cc: Dan Williams <[email protected]>
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
> ---
> include/linux/dmaengine.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index cb286b1..c3a4635 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -403,6 +403,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
> * @tx_submit: set the prepared descriptor(s) to be executed by the engine
> * @callback: routine to call after this operation is complete
> * @callback_param: general parameter to pass to the callback routine
> + * @transfered: number of bytes that were really transfered in case the channel
> + * transfered less than requested.
> * ---async_tx api specific fields---
> * @next: at completion submit this descriptor
> * @parent: pointer to the next level up in the dependency chain
> @@ -416,6 +418,7 @@ struct dma_async_tx_descriptor {
> dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
> dma_async_tx_callback callback;
> void *callback_param;
> + unsigned int transfered;
I think this should be doable with residue as well. You can return DMA_SUCCESS
for status and fill in what is NOT transfered indicating that txn completed but
lesser number of bytes are valid
~Vinod
--
On 07/29/2013 01:39 PM, Vinod Koul wrote:
>> @@ -416,6 +418,7 @@ struct dma_async_tx_descriptor {
>> dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
>> dma_async_tx_callback callback;
>> void *callback_param;
>> + unsigned int transfered;
> I think this should be doable with residue as well. You can return DMA_SUCCESS
> for status and fill in what is NOT transfered indicating that txn completed but
> lesser number of bytes are valid
Yes, will do.
>
> ~Vinod
>
Sebastian
* Bin Liu | 2013-07-26 22:07:14 [-0500]:
>Sebastian,
Hi Bin,
>I have not tested it yet, but I believe I found why host mode works on
>TI 3.2 kernel but not on mainline. Please look at Line 786 in 3.2
>kernel musb_core.c [1].
>
>773 if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
>......
>785 if (musb->a_wait_bcon != 0 &&
>786 is_otg_enabled(musb))
>787 musb_platform_try_idle(musb, jiffies
>788 +
>msecs_to_jiffies(musb->a_wait_bcon));
>
>So when the device is unplugged, *_try_idle() is not called in host
>mode, then the SESSION bit will stay set. But in mainline kernel,
>*_try_idle() will be called regardless.
>
>Please let me know your thoughts.
I am not too familiar with what should happen. The is_otg_enabled() part
is gone since v3.7-rc1 via:
|commit 032ec49f5351e9cb242b1a1c367d14415043ab95
|Author: Felipe Balbi <[email protected]>
|Date: Thu Nov 24 15:46:26 2011 +0200
|
| usb: musb: drop useless board_mode usage
|
| we are compiling the driver always with full OTG
| capabilities, so that board_mode trick becomes
| useless.
|
| Signed-off-by: Felipe Balbi <[email protected]>
So you say, am335x-evm is not able to run OTG mode and may only run in
host mode and as a consequence it must not call musb_platform_try_idle()
because it throws that one bit away and there is no way to bring it back?
However, if I look at the tree you reference, I see in
arch/arm/mach-omap2/board-am335xevm.c:
| static struct omap_musb_board_data musb_board_data = {
| .interface_type = MUSB_INTERFACE_ULPI,
| .mode = MUSB_OTG,
| .power = 500,
| .instances = 1,
| };
…
| static void __init am335x_evm_init(void)
…
| usb_musb_init(&musb_board_data);
and it creates a "ti81xx-usbss" device.
So it creates a musb device with mode MUSB_OTG no matter what.
I agree that without that try_idle part things keep working but it
seems, that it is also called in the other tree.
>
>Regards,
>-Bin.
Sebastian
Sebastian,
On Mon, Jul 29, 2013 at 11:53 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> So you say, am335x-evm is not able to run OTG mode and may only run in
> host mode and as a consequence it must not call musb_platform_try_idle()
> because it throws that one bit away and there is no way to bring it back?
I did not say AM335xEVM is not able to run OTG mode. The problem is in
OTG mode the SESSION bit will be cleared once the device is unplugged,
then there is no way the SESSION bit will come back in the current
mainline kernel.
The TI 3.2 kernel works around this OTG issue by toggling the SESSION
bit in b_idle handling in otg_timer(). The workaround makes most users
happy but it causes VBUS voltage pulsing. That is why I said I don't
know an ideal solution without a ID pin interrupt support.
>
> However, if I look at the tree you reference, I see in
> arch/arm/mach-omap2/board-am335xevm.c:
> | static struct omap_musb_board_data musb_board_data = {
> | .interface_type = MUSB_INTERFACE_ULPI,
> | .mode = MUSB_OTG,
> | .power = 500,
> | .instances = 1,
> | };
> ?
> | static void __init am335x_evm_init(void)
> ?
> | usb_musb_init(&musb_board_data);
>
> and it creates a "ti81xx-usbss" device.
>
> So it creates a musb device with mode MUSB_OTG no matter what.
I think you looked at a wrong file, maybe a wrong branch. Please check
[1], which defines
2644 * mode[0:3] = USB0PORT's mode
2645 * mode[4:7] = USB1PORT's mode
2646 * AM335X beta EVM has USB0 in OTG mode and USB1 in host mode.
2647 */
2648 .mode = (MUSB_HOST << 4) | MUSB_OTG,
> I agree that without that try_idle part things keep working but it
> seems, that it is also called in the other tree.
>
Then because AM335xEVM USB1 port does not call *try_idle() in this 3.2
kernel, its SESSION bit is always set.
But I don't have a clear idea how to solve this in the mainline kernel
since is_otg_enabled() has been cleaned.
>>
>>Regards,
>>-Bin.
>
> Sebastian
Regards,
-Bin.
[1]: http://arago-project.org/git/projects/?p=linux-am33x.git;a=blob;f=arch/arm/mach-omap2/board-am335xevm.c;h=aec37f371342455e06626c47e0e92beb51930ed2;hb=refs/heads/v3.2-staging
On 07/29/2013 07:26 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
> I did not say AM335xEVM is not able to run OTG mode. The problem is in
> OTG mode the SESSION bit will be cleared once the device is unplugged,
> then there is no way the SESSION bit will come back in the current
> mainline kernel.
Yes, you did.
>
> The TI 3.2 kernel works around this OTG issue by toggling the SESSION
> bit in b_idle handling in otg_timer(). The workaround makes most users
> happy but it causes VBUS voltage pulsing. That is why I said I don't
> know an ideal solution without a ID pin interrupt support.
Now I understand more pieces of the puzzle. And the missing ID pin
support is Am335x-evm specific since other am335x board may wire up
that pin.
But you say there is no way that the phy or anything else could help to
avoid that pulsing.
> I think you looked at a wrong file, maybe a wrong branch. Please check
> [1], which defines
>
> 2644 * mode[0:3] = USB0PORT's mode
> 2645 * mode[4:7] = USB1PORT's mode
> 2646 * AM335X beta EVM has USB0 in OTG mode and USB1 in host mode.
> 2647 */
> 2648 .mode = (MUSB_HOST << 4) | MUSB_OTG,
Oh it is a long way. So looked into the wrong branch.
>> I agree that without that try_idle part things keep working but it
>> seems, that it is also called in the other tree.
>>
>
> Then because AM335xEVM USB1 port does not call *try_idle() in this 3.2
> kernel, its SESSION bit is always set.
>
> But I don't have a clear idea how to solve this in the mainline kernel
> since is_otg_enabled() has been cleaned.
So now I think this is a board problem. What about switching port 1
from OTG to HOST only and avoiding kicking the timer in
dsps_musb_try_idle() in such a case? It seems we only need to do this
in OTG mode.
> Regards,
> -Bin.
Sebastian
Sebastian,
On Mon, Jul 29, 2013 at 12:51 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> On 07/29/2013 07:26 PM, Bin Liu wrote:
>> Sebastian,
>
> Hi Bin,
>
>> I did not say AM335xEVM is not able to run OTG mode. The problem is in
>> OTG mode the SESSION bit will be cleared once the device is unplugged,
>> then there is no way the SESSION bit will come back in the current
>> mainline kernel.
>
> Yes, you did.
If I did, that was wrong statement.
>
>>
>> The TI 3.2 kernel works around this OTG issue by toggling the SESSION
>> bit in b_idle handling in otg_timer(). The workaround makes most users
>> happy but it causes VBUS voltage pulsing. That is why I said I don't
>> know an ideal solution without a ID pin interrupt support.
>
> Now I understand more pieces of the puzzle. And the missing ID pin
> support is Am335x-evm specific since other am335x board may wire up
> that pin.
No, it is not board wiring issue. The AM335x EVM DOES have ID pin
wired to the ID pin of the micro-AB receptacle. I said AM335x does not
have IP pin INTERRUPT support, by which the kernel does not know when
a device is plugged in without setting the SESSION bit.
> But you say there is no way that the phy or anything else could help to
> avoid that pulsing.
>
>> I think you looked at a wrong file, maybe a wrong branch. Please check
>> [1], which defines
>>
>> 2644 * mode[0:3] = USB0PORT's mode
>> 2645 * mode[4:7] = USB1PORT's mode
>> 2646 * AM335X beta EVM has USB0 in OTG mode and USB1 in host mode.
>> 2647 */
>> 2648 .mode = (MUSB_HOST << 4) | MUSB_OTG,
>
> Oh it is a long way. So looked into the wrong branch.
>
>>> I agree that without that try_idle part things keep working but it
>>> seems, that it is also called in the other tree.
>>>
>>
>> Then because AM335xEVM USB1 port does not call *try_idle() in this 3.2
>> kernel, its SESSION bit is always set.
>>
>> But I don't have a clear idea how to solve this in the mainline kernel
>> since is_otg_enabled() has been cleaned.
>
> So now I think this is a board problem. What about switching port 1
> from OTG to HOST only and avoiding kicking the timer in
> dsps_musb_try_idle() in such a case? It seems we only need to do this
> in OTG mode.
I have not read the MUSB driver in the mainline kernel yet. If somehow
port 1 can could be set to HOST mode then the SESSION bit would stay,
then that should solve the issue.
>
>> Regards,
>> -Bin.
>
> Sebastian
This is what I observe:
On the first connect, the musb starts with DEVCTL.Session set. On
disconnect, musb_core calls try_idle. That functions removes the Session
bit signalize that the session is over (something that only in OTG is
required). A new device, that is plugged, is no longer recognized.
I've setup a timer and checked the DEVCTL register and I haven't seen a
change in VBus and I saw the B-Device bit set. After setting the IDDIG
into A mode and forcing the device to behave like I didn't see a change.
Neither VBUS goes to 0b11 nor does a session start request come.
The TI-v3.2 kernel they skip to call musb_platform_try_idle() in the
OTG_STATE_A_WAIT_BCON state while not in OTG mode.
Since the second port hast a standard A plug the patch changes the port
to run in host mode only, force the id-pin to host only and skip the
timer which would remove DEVCTL.Session.
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
---
arch/arm/boot/dts/am335x-evm.dts | 3 +++
drivers/usb/musb/musb_dsps.c | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index c26c16c..38a821a 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -192,6 +192,9 @@
usb@47401800 {
status = "okay";
+ musb1: usb@47401c00 {
+ port-mode = <1>;
+ };
};
dma@07402000 {
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 4ffbaac..b0752fa 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -65,6 +65,9 @@ static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
{ __raw_writel(data, addr + offset); }
+#define USBMODE_IDDIG_A (0 << 8)
+#define USBMODE_ID_MUX_REG (1 << 7)
+#define USBMODE_ID_MUX_PHY (0 << 7)
/**
* DSPS musb wrapper register offset.
* FIXME: This should be expanded to have all the wrapper registers from TI DSPS
@@ -230,6 +233,8 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
glue->last_timer = jiffies;
return;
}
+ if (musb->port_mode == MUSB_PORT_MODE_HOST)
+ return;
if (time_after(glue->last_timer, timeout) &&
timer_pending(&glue->timer)) {
@@ -388,6 +393,14 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+ if (musb->port_mode == MUSB_PORT_MODE_HOST) {
+ val = USBMODE_IDDIG_A;
+ val |= USBMODE_ID_MUX_REG;
+ } else {
+ val = USBMODE_ID_MUX_PHY;
+ }
+ dsps_writel(musb->ctrl_base, wrp->mode, val);
+
return 0;
}
--
1.8.3.2
Hello.
On 08/09/2013 08:03 PM, Sebastian Andrzej Siewior wrote:
> This is what I observe:
> On the first connect, the musb starts with DEVCTL.Session set. On
> disconnect, musb_core calls try_idle. That functions removes the Session
> bit signalize that the session is over (something that only in OTG is
> required). A new device, that is plugged, is no longer recognized.
> I've setup a timer and checked the DEVCTL register and I haven't seen a
> change in VBus and I saw the B-Device bit set. After setting the IDDIG
> into A mode and forcing the device to behave like I didn't see a change.
> Neither VBUS goes to 0b11 nor does a session start request come.
> The TI-v3.2 kernel they skip to call musb_platform_try_idle() in the
> OTG_STATE_A_WAIT_BCON state while not in OTG mode.
> Since the second port hast a standard A plug the patch changes the port
> to run in host mode only, force the id-pin to host only and skip the
> timer which would remove DEVCTL.Session.
> Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
[...]
> diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
> index 4ffbaac..b0752fa 100644
> --- a/drivers/usb/musb/musb_dsps.c
> +++ b/drivers/usb/musb/musb_dsps.c
[...]
> @@ -388,6 +393,14 @@ static int dsps_musb_init(struct musb *musb)
> val &= ~(1 << wrp->otg_disable);
> dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
>
> + if (musb->port_mode == MUSB_PORT_MODE_HOST) {
> + val = USBMODE_IDDIG_A;
> + val |= USBMODE_ID_MUX_REG;
Why not do the above in one line and save on {} {}? It will look more
aesthetically pleasing IMHO.
> + } else {
> + val = USBMODE_ID_MUX_PHY;
> + }
> + dsps_writel(musb->ctrl_base, wrp->mode, val);
> +
WBR, Sergei
On 08/09/2013 10:30 PM, Sergei Shtylyov wrote:
> Hello.
Hi Sergei,
>> + if (musb->port_mode == MUSB_PORT_MODE_HOST) {
>> + val = USBMODE_IDDIG_A;
>> + val |= USBMODE_ID_MUX_REG;
>
> Why not do the above in one line and save on {} {}? It will look more
> aesthetically pleasing IMHO.
I'm going to redo this if it is agreed that we want to fix it that way.
Sebastian
Sebastian,
On Tue, Aug 13, 2013 at 2:14 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> On 08/09/2013 10:30 PM, Sergei Shtylyov wrote:
>> Hello.
>
> Hi Sergei,
>
>>> + if (musb->port_mode == MUSB_PORT_MODE_HOST) {
>>> + val = USBMODE_IDDIG_A;
>>> + val |= USBMODE_ID_MUX_REG;
>>
>> Why not do the above in one line and save on {} {}? It will look more
>> aesthetically pleasing IMHO.
>
> I'm going to redo this if it is agreed that we want to fix it that way.
I am going to so some tests today for this. I don't object to use the
mode register, but am wondering why we have to play with it for
host-only mode. The ID pin is grounded for host-only mode, which
should cause the same as setting mode register.
>
> Sebastian
-Bin.
On 08/13/2013 03:03 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
>>>> + if (musb->port_mode == MUSB_PORT_MODE_HOST) {
>>>> + val = USBMODE_IDDIG_A;
>>>> + val |= USBMODE_ID_MUX_REG;
>>>
> I am going to so some tests today for this. I don't object to use the
> mode register, but am wondering why we have to play with it for
> host-only mode. The ID pin is grounded for host-only mode, which
> should cause the same as setting mode register.
I've been looking at the wiki page and it did not mention the ID pin
for the second port. If it is grounded then this piece can be removed
and the magic trick is just to skip the try_idle() call.
I haven't found anything saying that it is required to clear the
session bin in host mode, only in OTG. And then, I would assume to
receive a session interrupt once we have the proper VBUS level which
does not happen.
> -Bin.
Sebastian
Sebastian,
On Tue, Aug 13, 2013 at 8:17 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> On 08/13/2013 03:03 PM, Bin Liu wrote:
>> Sebastian,
>
> Hi Bin,
>
>>>>> + if (musb->port_mode == MUSB_PORT_MODE_HOST) {
>>>>> + val = USBMODE_IDDIG_A;
>>>>> + val |= USBMODE_ID_MUX_REG;
>>>>
>> I am going to so some tests today for this. I don't object to use the
>> mode register, but am wondering why we have to play with it for
>> host-only mode. The ID pin is grounded for host-only mode, which
>> should cause the same as setting mode register.
>
> I've been looking at the wiki page and it did not mention the ID pin
> for the second port. If it is grounded then this piece can be removed
I thought you have already tried that without setting the mode
register the session bit cannot stay set.
I am not sure if anywhere mentioned about the ID pin, but ASAIK all
the different boards using am335x have ID pin grounded for host port.
> and the magic trick is just to skip the try_idle() call.
Agreed.
>
> I haven't found anything saying that it is required to clear the
> session bin in host mode, only in OTG. And then, I would assume to
Agreed.
> receive a session interrupt once we have the proper VBUS level which
> does not happen.
The TI 3.2 kernel for am335x sets the session bit in musb_start() for
host-only mode. Maybe we can do something similar in here? (I noticed
mush_start() has gone in mainline, but have not got a chance to check
the details...)
>
>> -Bin.
>
> Sebastian
On 08/13/2013 03:33 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
>> I've been looking at the wiki page and it did not mention the ID pin
>> for the second port. If it is grounded then this piece can be removed
> I thought you have already tried that without setting the mode
> register the session bit cannot stay set.
This was a misunderstanding then. Sorry. I understood that the bin has
to be unset and then the controller set it once a device there.
> I am not sure if anywhere mentioned about the ID pin, but ASAIK all
> the different boards using am335x have ID pin grounded for host port.
evm is the only I am aware of. The evm-sk and beagle bone have just one
port. Beagle bone black is not mainline.
>> and the magic trick is just to skip the try_idle() call.
> Agreed.
>
>>
>> I haven't found anything saying that it is required to clear the
>> session bin in host mode, only in OTG. And then, I would assume to
> Agreed.
>
>> receive a session interrupt once we have the proper VBUS level which
>> does not happen.
> The TI 3.2 kernel for am335x sets the session bit in musb_start() for
> host-only mode. Maybe we can do something similar in here? (I noticed
> mush_start() has gone in mainline, but have not got a chance to check
> the details...)
This is the case already. From musb_start()
?
if (musb->port_mode != MUSB_PORT_MODE_HOST &&
(devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
musb->is_active = 1;
} else {
devctl |= MUSB_DEVCTL_SESSION;
}
?
>>> -Bin.
Sebastian
Sebastian,
On Tue, Aug 13, 2013 at 8:44 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> This was a misunderstanding then. Sorry. I understood that the bin has
> to be unset and then the controller set it once a device there.
You meant ID pin? I think it should be set all the time since the
driver initialized for host-only mode, if it is unset, the controller
has not way to know if a device is plugged or not.
>
>> I am not sure if anywhere mentioned about the ID pin, but ASAIK all
>> the different boards using am335x have ID pin grounded for host port.
> evm is the only I am aware of. The evm-sk and beagle bone have just one
> port. Beagle bone black is not mainline.
You meant the dts only supports one port for evm-sk and bone? The
boards physically have two ports, usb0 is device only, usb1 is host
only.
> This is the case already. From musb_start()
> ?
> if (musb->port_mode != MUSB_PORT_MODE_HOST &&
> (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
> musb->is_active = 1;
> } else {
> devctl |= MUSB_DEVCTL_SESSION;
> }
> ?
great! then the host port on gp evm should work now, right?
>
>>>> -Bin.
>
> Sebastian
On 08/13/2013 04:01 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
> On Tue, Aug 13, 2013 at 8:44 AM, Sebastian Andrzej Siewior
> <[email protected]> wrote:
>> This was a misunderstanding then. Sorry. I understood that the bin has
>> to be unset and then the controller set it once a device there.
> You meant ID pin? I think it should be set all the time since the
> driver initialized for host-only mode, if it is unset, the controller
> has not way to know if a device is plugged or not.
Okay.
>>> I am not sure if anywhere mentioned about the ID pin, but ASAIK all
>>> the different boards using am335x have ID pin grounded for host port.
>> evm is the only I am aware of. The evm-sk and beagle bone have just one
>> port. Beagle bone black is not mainline.
> You meant the dts only supports one port for evm-sk and bone? The
> boards physically have two ports, usb0 is device only, usb1 is host
> only.
Where is my memory going? So now I have a beagle bone in front of me
and I see a micro USB port a standard A connector. My memory was
different.
The micro USB is the UART and standard is most likely the first musb
instance. So this should run also in host mode and not in OTG mode.
Hmmm. Let me double check this.
>> This is the case already. From musb_start()
>> ?
>> if (musb->port_mode != MUSB_PORT_MODE_HOST &&
>> (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
>> musb->is_active = 1;
>> } else {
>> devctl |= MUSB_DEVCTL_SESSION;
>> }
>> ?
> great! then the host port on gp evm should work now, right?
With the change where don't can try_idle() in host mode, yes.
>
>>
>>>>> -Bin.
Sebastian
Sebastian,
On Tue, Aug 13, 2013 at 9:23 AM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> Where is my memory going? So now I have a beagle bone in front of me
> and I see a micro USB port a standard A connector. My memory was
> different.
> The micro USB is the UART and standard is most likely the first musb
> instance. So this should run also in host mode and not in OTG mode.
> Hmmm. Let me double check this.
I don't know how dts instances both in mainline, but I would think if
you create two musb instances, and load a gadget driver for this micro
USB port, the USB host should enumerate it. The standard port should
be the 2nd instance which has its ID pin grounded and work in
host-only mode.
This is how they work in TI 3.2 kernel.
>
>
> Sebastian
On 08/13/2013 04:32 PM, Bin Liu wrote:
> Sebastian,
Hi Bin,
> On Tue, Aug 13, 2013 at 9:23 AM, Sebastian Andrzej Siewior
> <[email protected]> wrote:
>> Where is my memory going? So now I have a beagle bone in front of me
>> and I see a micro USB port a standard A connector. My memory was
>> different.
>> The micro USB is the UART and standard is most likely the first musb
>> instance. So this should run also in host mode and not in OTG mode.
>> Hmmm. Let me double check this.
> I don't know how dts instances both in mainline, but I would think if
> you create two musb instances, and load a gadget driver for this micro
> USB port, the USB host should enumerate it. The standard port should
> be the 2nd instance which has its ID pin grounded and work in
> host-only mode.
>
> This is how they work in TI 3.2 kernel.
So I tried to boot my beagle bone board to figure out if they use the
first or the second port in host mode (but it doesn't boot). The tiny
micro USB plug is 100% for UART and not wired up to MUSB.
Any comments on that patch? I would remove the ID pin changes and
repost if you don't mind.
>> Sebastian
Sebastian
Sebastian,
On Wed, Aug 14, 2013 at 1:17 PM, Sebastian Andrzej Siewior
<[email protected]> wrote:
> So I tried to boot my beagle bone board to figure out if they use the
> first or the second port in host mode (but it doesn't boot). The tiny
> micro USB plug is 100% for UART and not wired up to MUSB.
I have not run the mainline kernel on beagle bone yet, so I cannot
comment how it works, and it does not surprise if something is broken
since this is what you are trying to fix ;)
But I just booted my beagle bone with the out-of-box SD card which has
Angstrom 3.2.34 kernel. The USB0 port is in device mode with
g_mass_storage.ko loaded, and USB1 is in host-only mode.
> Any comments on that patch? I would remove the ID pin changes and
> repost if you don't mind.
That is okay to me, as long as both USB ports on the GP evm work.
-Bin.