* [PATCH 01/16] usb: musb: dsps: init / shutdown the phy
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-25 14:32 ` Felipe Balbi
2013-07-22 18:09 ` [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY Sebastian Andrzej Siewior
` (14 subsequent siblings)
15 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 01/16] usb: musb: dsps: init / shutdown the phy
2013-07-22 18:09 ` [PATCH 01/16] usb: musb: dsps: init / shutdown the phy Sebastian Andrzej Siewior
@ 2013-07-25 14:32 ` Felipe Balbi
0 siblings, 0 replies; 71+ messages in thread
From: Felipe Balbi @ 2013-07-25 14:32 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi, george.cherian
[-- Attachment #1: Type: text/plain, Size: 408 bytes --]
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 <bigeasy@linutronix.de>
cool, eventually we should move these calls to musb_core.c though.
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 01/16] usb: musb: dsps: init / shutdown the phy Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-25 14:33 ` Felipe Balbi
2013-07-22 18:09 ` [PATCH 03/16] usb: musb: dsps: remove the hardcoded phy pieces Sebastian Andrzej Siewior
` (13 subsequent siblings)
15 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY
2013-07-22 18:09 ` [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY Sebastian Andrzej Siewior
@ 2013-07-25 14:33 ` Felipe Balbi
2013-07-25 14:45 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: Felipe Balbi @ 2013-07-25 14:33 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi, george.cherian
[-- Attachment #1: Type: text/plain, Size: 661 bytes --]
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 <bigeasy@linutronix.de>
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
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY
2013-07-25 14:33 ` Felipe Balbi
@ 2013-07-25 14:45 ` Sebastian Andrzej Siewior
2013-07-25 14:54 ` Felipe Balbi
0 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-25 14:45 UTC (permalink / raw)
To: Felipe Balbi; +Cc: linux-usb, linux-kernel, george.cherian
* 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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY
2013-07-25 14:45 ` Sebastian Andrzej Siewior
@ 2013-07-25 14:54 ` Felipe Balbi
0 siblings, 0 replies; 71+ messages in thread
From: Felipe Balbi @ 2013-07-25 14:54 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Felipe Balbi, linux-usb, linux-kernel, george.cherian
[-- Attachment #1: Type: text/plain, Size: 616 bytes --]
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
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 03/16] usb: musb: dsps: remove the hardcoded phy pieces
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 01/16] usb: musb: dsps: init / shutdown the phy Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 02/16] usb: phy: phy-nop: add support for am335x PHY Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 04/16] usb: musb: remove ti81xx pieces from musb Sebastian Andrzej Siewior
` (12 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 04/16] usb: musb: remove ti81xx pieces from musb
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (2 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 03/16] usb: musb: dsps: remove the hardcoded phy pieces Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 05/16] usb: musb: dsps: use proper child nodes Sebastian Andrzej Siewior
` (11 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 05/16] usb: musb: dsps: use proper child nodes
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (3 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 04/16] usb: musb: remove ti81xx pieces from musb Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-23 6:46 ` George Cherian
2013-07-22 18:09 ` [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data Sebastian Andrzej Siewior
` (10 subsequent siblings)
15 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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 <ravibabu@ti.com>");
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 05/16] usb: musb: dsps: use proper child nodes
2013-07-22 18:09 ` [PATCH 05/16] usb: musb: dsps: use proper child nodes Sebastian Andrzej Siewior
@ 2013-07-23 6:46 ` George Cherian
2013-07-23 9:15 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: George Cherian @ 2013-07-23 6:46 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi
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 <bigeasy@linutronix.de>
> ---
> 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 <ravibabu@ti.com>");
> MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
> 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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 05/16] usb: musb: dsps: use proper child nodes
2013-07-23 6:46 ` George Cherian
@ 2013-07-23 9:15 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-23 9:15 UTC (permalink / raw)
To: George Cherian; +Cc: linux-usb, linux-kernel, balbi
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (4 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 05/16] usb: musb: dsps: use proper child nodes Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-23 6:04 ` George Cherian
[not found] ` <CADYTM3avh7GFTDQW01FnojKZkmL0_hi+=K-VVwCw5peJL2hwTA@mail.gmail.com>
2013-07-22 18:09 ` [PATCH 07/16] usb: musb: replace ifndef with ifdef for CONFIG_MUSB_PIO_ONLY Sebastian Andrzej Siewior
` (9 subsequent siblings)
15 siblings, 2 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-22 18:09 ` [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data Sebastian Andrzej Siewior
@ 2013-07-23 6:04 ` George Cherian
2013-07-23 9:09 ` Sebastian Andrzej Siewior
[not found] ` <CADYTM3avh7GFTDQW01FnojKZkmL0_hi+=K-VVwCw5peJL2hwTA@mail.gmail.com>
1 sibling, 1 reply; 71+ messages in thread
From: George Cherian @ 2013-07-23 6:04 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-23 6:04 ` George Cherian
@ 2013-07-23 9:09 ` Sebastian Andrzej Siewior
2013-07-23 9:14 ` George Cherian
0 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-23 9:09 UTC (permalink / raw)
To: George Cherian; +Cc: linux-usb, linux-kernel, balbi
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-23 9:09 ` Sebastian Andrzej Siewior
@ 2013-07-23 9:14 ` George Cherian
0 siblings, 0 replies; 71+ messages in thread
From: George Cherian @ 2013-07-23 9:14 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi
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
^ permalink raw reply [flat|nested] 71+ messages in thread
[parent not found: <CADYTM3avh7GFTDQW01FnojKZkmL0_hi+=K-VVwCw5peJL2hwTA@mail.gmail.com>]
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
[not found] ` <CADYTM3avh7GFTDQW01FnojKZkmL0_hi+=K-VVwCw5peJL2hwTA@mail.gmail.com>
@ 2013-07-23 19:09 ` Bin Liu
2013-07-25 14:41 ` Sebastian Andrzej Siewior
1 sibling, 0 replies; 71+ messages in thread
From: Bin Liu @ 2013-07-23 19:09 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi, george.cherian
(re-send, due to last delivery failure to the mailing list...)
On Tue, Jul 23, 2013 at 1:23 PM, Bin Liu <binmlist@gmail.com> wrote:
> Hi Sebastian,
>
> On Mon, Jul 22, 2013 at 1:09 PM, Sebastian Andrzej Siewior
> <bigeasy@linutronix.de> 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.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
[not found] ` <CADYTM3avh7GFTDQW01FnojKZkmL0_hi+=K-VVwCw5peJL2hwTA@mail.gmail.com>
2013-07-23 19:09 ` Bin Liu
@ 2013-07-25 14:41 ` Sebastian Andrzej Siewior
2013-07-25 15:12 ` Bin Liu
1 sibling, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-25 14:41 UTC (permalink / raw)
To: Bin Liu; +Cc: linux-usb, linux-kernel, balbi, george.cherian
* 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 <
>bigeasy@linutronix.de> 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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 14:41 ` Sebastian Andrzej Siewior
@ 2013-07-25 15:12 ` Bin Liu
2013-07-25 15:16 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: Bin Liu @ 2013-07-25 15:12 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi, george.cherian
Sebastian,
On Thu, Jul 25, 2013 at 9:41 AM, Sebastian Andrzej Siewior
<bigeasy@linutronix.de> 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 <
>>bigeasy@linutronix.de> 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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 15:12 ` Bin Liu
@ 2013-07-25 15:16 ` Sebastian Andrzej Siewior
2013-07-25 15:28 ` Bin Liu
2013-07-25 15:37 ` [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data Felipe Balbi
0 siblings, 2 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-25 15:16 UTC (permalink / raw)
To: Bin Liu; +Cc: linux-usb, linux-kernel, balbi, george.cherian
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 15:16 ` Sebastian Andrzej Siewior
@ 2013-07-25 15:28 ` Bin Liu
2013-07-25 16:11 ` Felipe Balbi
2013-07-25 15:37 ` [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data Felipe Balbi
1 sibling, 1 reply; 71+ messages in thread
From: Bin Liu @ 2013-07-25 15:28 UTC (permalink / raw)
To: Sebastian Andrzej Siewior; +Cc: linux-usb, linux-kernel, balbi, george.cherian
Sebastian,
On Thu, Jul 25, 2013 at 10:16 AM, Sebastian Andrzej Siewior
<bigeasy@linutronix.de> 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.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 15:28 ` Bin Liu
@ 2013-07-25 16:11 ` Felipe Balbi
2013-07-26 9:11 ` [PATCH 06/16 => 1/2] " Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: Felipe Balbi @ 2013-07-25 16:11 UTC (permalink / raw)
To: Bin Liu
Cc: Sebastian Andrzej Siewior, linux-usb, linux-kernel, balbi,
george.cherian
[-- Attachment #1: Type: text/plain, Size: 1566 bytes --]
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
> <bigeasy@linutronix.de> 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
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 06/16 => 1/2] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 16:11 ` Felipe Balbi
@ 2013-07-26 9:11 ` Sebastian Andrzej Siewior
2013-07-26 9:11 ` [PATCH 06/16 => 2/2] usb: musb: dsps: remove EOI access Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-26 9:11 UTC (permalink / raw)
To: Felipe Balbi
Cc: Bin Liu, linux-usb, linux-kernel, george.cherian,
Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 06/16 => 2/2] usb: musb: dsps: remove EOI access
2013-07-26 9:11 ` [PATCH 06/16 => 1/2] " Sebastian Andrzej Siewior
@ 2013-07-26 9:11 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-26 9:11 UTC (permalink / raw)
To: Felipe Balbi
Cc: Bin Liu, linux-usb, linux-kernel, george.cherian,
Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data
2013-07-25 15:16 ` Sebastian Andrzej Siewior
2013-07-25 15:28 ` Bin Liu
@ 2013-07-25 15:37 ` Felipe Balbi
1 sibling, 0 replies; 71+ messages in thread
From: Felipe Balbi @ 2013-07-25 15:37 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Bin Liu, linux-usb, linux-kernel, balbi, george.cherian
[-- Attachment #1: Type: text/plain, Size: 1241 bytes --]
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
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 07/16] usb: musb: replace ifndef with ifdef for CONFIG_MUSB_PIO_ONLY
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (5 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 06/16] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-22 18:09 ` [PATCH 08/16] usb: musb: dma: merge ->start/stop into create/destroy Sebastian Andrzej Siewior
` (8 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
The ifdef reads somehow better than an ifndef
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 08/16] usb: musb: dma: merge ->start/stop into create/destroy
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (6 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 07/16] usb: musb: replace ifndef with ifdef for CONFIG_MUSB_PIO_ONLY Sebastian Andrzej Siewior
@ 2013-07-22 18:09 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 09/16] usb: musb: provide empty dma_controller_create() in PIO mode Sebastian Andrzej Siewior
` (7 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:09 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 09/16] usb: musb: provide empty dma_controller_create() in PIO mode
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (7 preceding siblings ...)
2013-07-22 18:09 ` [PATCH 08/16] usb: musb: dma: merge ->start/stop into create/destroy Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 10/16] usb: musb: remove a few is_dma_capable() in init/exit code Sebastian Andrzej Siewior
` (6 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
Add a dma_controller_create() returning NULL so a few ifdefs can
dropped.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 10/16] usb: musb: remove a few is_dma_capable() in init/exit code
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (8 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 09/16] usb: musb: provide empty dma_controller_create() in PIO mode Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 11/16] usb: musb: core: call dma_controller_destroy() in the err path Sebastian Andrzej Siewior
` (5 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 11/16] usb: musb: core: call dma_controller_destroy() in the err path
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (9 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 10/16] usb: musb: remove a few is_dma_capable() in init/exit code Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 12/16] usb: musb: unmap reqs in musb_gadget_queue()'s error case Sebastian Andrzej Siewior
` (4 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 12/16] usb: musb: unmap reqs in musb_gadget_queue()'s error case
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (10 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 11/16] usb: musb: core: call dma_controller_destroy() in the err path Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 13/16] usb: musb: do not change dev's dma_mask Sebastian Andrzej Siewior
` (3 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 13/16] usb: musb: do not change dev's dma_mask
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (11 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 12/16] usb: musb: unmap reqs in musb_gadget_queue()'s error case Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 14/16] usb: musb: dsps: add MUSB_DEVCTL_SESSION back after removal Sebastian Andrzej Siewior
` (2 subsequent siblings)
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 14/16] usb: musb: dsps: add MUSB_DEVCTL_SESSION back after removal
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (12 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 13/16] usb: musb: do not change dev's dma_mask Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
[not found] ` <CADYTM3a5xzs+-VCTeKLGiRjo7JOqOJ5H4EWDACpTMovY5_ooRA@mail.gmail.com>
2013-07-22 18:10 ` [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor Sebastian Andrzej Siewior
2013-07-22 18:10 ` [PATCH 16/16] usb/musb dma: add cppi41 dma driver Sebastian Andrzej Siewior
15 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel; +Cc: balbi, george.cherian, Sebastian Andrzej Siewior
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 <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (13 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 14/16] usb: musb: dsps: add MUSB_DEVCTL_SESSION back after removal Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
2013-07-22 18:52 ` Sergei Shtylyov
` (2 more replies)
2013-07-22 18:10 ` [PATCH 16/16] usb/musb dma: add cppi41 dma driver Sebastian Andrzej Siewior
15 siblings, 3 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel
Cc: balbi, george.cherian, Sebastian Andrzej Siewior, Vinod Koul,
Dan Williams
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 <vinod.koul@intel.com>
Cc: Dan Williams <djbw@fb.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
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
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-22 18:10 ` [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor Sebastian Andrzej Siewior
@ 2013-07-22 18:52 ` Sergei Shtylyov
2013-07-23 17:12 ` Sebastian Andrzej Siewior
2013-07-25 14:57 ` Lars-Peter Clausen
2013-07-29 11:39 ` Vinod Koul
2 siblings, 1 reply; 71+ messages in thread
From: Sergei Shtylyov @ 2013-07-22 18:52 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-usb, linux-kernel, balbi, george.cherian, Vinod Koul, Dan Williams
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 <vinod.koul@intel.com>
> Cc: Dan Williams <djbw@fb.com>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> 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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-22 18:52 ` Sergei Shtylyov
@ 2013-07-23 17:12 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-23 17:12 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: linux-usb, linux-kernel, balbi, george.cherian, Vinod Koul, Dan Williams
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-22 18:10 ` [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor Sebastian Andrzej Siewior
2013-07-22 18:52 ` Sergei Shtylyov
@ 2013-07-25 14:57 ` Lars-Peter Clausen
2013-07-25 15:12 ` Sebastian Andrzej Siewior
2013-07-29 11:39 ` Vinod Koul
2 siblings, 1 reply; 71+ messages in thread
From: Lars-Peter Clausen @ 2013-07-25 14:57 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-usb, linux-kernel, balbi, george.cherian, Vinod Koul, Dan Williams
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-25 14:57 ` Lars-Peter Clausen
@ 2013-07-25 15:12 ` Sebastian Andrzej Siewior
2013-07-25 15:32 ` Lars-Peter Clausen
0 siblings, 1 reply; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-25 15:12 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: linux-usb, linux-kernel, balbi, george.cherian, Vinod Koul, Dan Williams
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-25 15:12 ` Sebastian Andrzej Siewior
@ 2013-07-25 15:32 ` Lars-Peter Clausen
2013-07-26 9:30 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 71+ messages in thread
From: Lars-Peter Clausen @ 2013-07-25 15:32 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-usb, linux-kernel, balbi, george.cherian, Vinod Koul, Dan Williams
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.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-25 15:32 ` Lars-Peter Clausen
@ 2013-07-26 9:30 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-26 9:30 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Sebastian Andrzej Siewior, linux-usb, linux-kernel, balbi,
george.cherian, Vinod Koul, Dan Williams
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-22 18:10 ` [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor Sebastian Andrzej Siewior
2013-07-22 18:52 ` Sergei Shtylyov
2013-07-25 14:57 ` Lars-Peter Clausen
@ 2013-07-29 11:39 ` Vinod Koul
2013-07-29 12:33 ` Sebastian Andrzej Siewior
2 siblings, 1 reply; 71+ messages in thread
From: Vinod Koul @ 2013-07-29 11:39 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-usb, linux-kernel, balbi, george.cherian, Dan Williams
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 <vinod.koul@intel.com>
> Cc: Dan Williams <djbw@fb.com>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> 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
--
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor
2013-07-29 11:39 ` Vinod Koul
@ 2013-07-29 12:33 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-29 12:33 UTC (permalink / raw)
To: Vinod Koul; +Cc: linux-usb, linux-kernel, balbi, george.cherian, Dan Williams
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
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH 16/16] usb/musb dma: add cppi41 dma driver
2013-07-22 18:09 am33x: multiple instances and dma support, v2 Sebastian Andrzej Siewior
` (14 preceding siblings ...)
2013-07-22 18:10 ` [PATCH 15/16] dmaengine: add transfered member to dma_async_tx_descriptor Sebastian Andrzej Siewior
@ 2013-07-22 18:10 ` Sebastian Andrzej Siewior
15 siblings, 0 replies; 71+ messages in thread
From: Sebastian Andrzej Siewior @ 2013-07-22 18:10 UTC (permalink / raw)
To: linux-usb, linux-kernel
Cc: balbi, george.cherian, Sebastian Andrzej Siewior, Vinod Koul,
Dan Williams
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 <vinod.koul@intel.com>
Cc: Dan Williams <djbw@fb.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
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 <bigeasy@linutronix.de>");
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
^ permalink raw reply related [flat|nested] 71+ messages in thread