2020-02-24 01:40:45

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 1/5] dt-bindings: usb: Convert jz4740-musb doc to YAML

Convert ingenic,jz4740-musb.txt to ingenic,musb.yaml, and add the
new ingenic,jz4770-musb compatible string in the process.

Signed-off-by: Paul Cercueil <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---

Notes:
v2: Changed oneOf+const to enum

.../bindings/usb/ingenic,jz4740-musb.txt | 32 ---------
.../devicetree/bindings/usb/ingenic,musb.yaml | 72 +++++++++++++++++++
2 files changed, 72 insertions(+), 32 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt
create mode 100644 Documentation/devicetree/bindings/usb/ingenic,musb.yaml

diff --git a/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt b/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt
deleted file mode 100644
index 16808721f3ff..000000000000
--- a/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Ingenic JZ4740 MUSB driver
-
-Required properties:
-
-- compatible: Must be "ingenic,jz4740-musb"
-- reg: Address range of the UDC register set
-- interrupts: IRQ number related to the UDC hardware
-- interrupt-names: must be "mc"
-- clocks: phandle to the "udc" clock
-- clock-names: must be "udc"
-- phys: phandle to the USB PHY
-
-Example:
-
-usb_phy: usb-phy@0 {
- compatible = "usb-nop-xceiv";
- #phy-cells = <0>;
-};
-
-udc: usb@13040000 {
- compatible = "ingenic,jz4740-musb";
- reg = <0x13040000 0x10000>;
-
- interrupt-parent = <&intc>;
- interrupts = <24>;
- interrupt-names = "mc";
-
- clocks = <&cgu JZ4740_CLK_UDC>;
- clock-names = "udc";
-
- phys = <&usb_phy>;
-};
diff --git a/Documentation/devicetree/bindings/usb/ingenic,musb.yaml b/Documentation/devicetree/bindings/usb/ingenic,musb.yaml
new file mode 100644
index 000000000000..7f33d3caa214
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ingenic,musb.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ingenic,musb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ingenic JZ47xx USB IP DT bindings
+
+maintainers:
+ - Paul Cercueil <[email protected]>
+
+properties:
+ $nodename:
+ pattern: '^usb@.*'
+
+ compatible:
+ enum:
+ - ingenic,jz4770-musb
+ - ingenic,jz4740-musb
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: udc
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-names:
+ items:
+ - const: mc
+
+ phys:
+ description: PHY specifier for the USB PHY
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - interrupts
+ - interrupt-names
+ - phys
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/jz4740-cgu.h>
+ usb_phy: usb-phy@0 {
+ compatible = "usb-nop-xceiv";
+ #phy-cells = <0>;
+ };
+
+ udc: usb@13040000 {
+ compatible = "ingenic,jz4740-musb";
+ reg = <0x13040000 0x10000>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <24>;
+ interrupt-names = "mc";
+
+ clocks = <&cgu JZ4740_CLK_UDC>;
+ clock-names = "udc";
+
+ phys = <&usb_phy>;
+ };
--
2.25.0


2020-02-24 01:40:53

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 2/5] usb: musb: jz4740: Add support for DMA

Add support for using the DMA channels built into the Inventra IP.

Signed-off-by: Paul Cercueil <[email protected]>
Tested-by: Artur Rojek <[email protected]>
---

Notes:
v2: No change

drivers/usb/musb/Kconfig | 2 +-
drivers/usb/musb/jz4740.c | 20 ++++++++++++++------
2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index eb2ded1026ee..c4b349e074c1 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -144,7 +144,7 @@ config USB_UX500_DMA

config USB_INVENTRA_DMA
bool 'Inventra'
- depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK
+ depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK || USB_MUSB_JZ4740
help
Enable DMA transfers using Mentor's engine.

diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index bc0109f4700b..aa32b5af0c1f 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -24,11 +24,14 @@ struct jz4740_glue {
static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
- irqreturn_t retval = IRQ_NONE;
+ irqreturn_t retval = IRQ_NONE, retval_dma = IRQ_NONE;
struct musb *musb = __hci;

spin_lock_irqsave(&musb->lock, flags);

+ if (IS_ENABLED(CONFIG_USB_INVENTRA_DMA) && musb->dma_controller)
+ retval_dma = dma_controller_irq(irq, musb->dma_controller);
+
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
@@ -46,7 +49,10 @@ static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)

spin_unlock_irqrestore(&musb->lock, flags);

- return retval;
+ if (retval == IRQ_HANDLED || retval_dma == IRQ_HANDLED)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
}

static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
@@ -93,14 +99,14 @@ static int jz4740_musb_init(struct musb *musb)
return 0;
}

-/*
- * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA,
- * so let's not set up the dma function pointers yet.
- */
static const struct musb_platform_ops jz4740_musb_ops = {
.quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
.fifo_mode = 2,
.init = jz4740_musb_init,
+#ifdef CONFIG_USB_INVENTRA_DMA
+ .dma_init = musbhs_dma_controller_create_noirq,
+ .dma_exit = musbhs_dma_controller_destroy,
+#endif
};

static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
@@ -142,6 +148,8 @@ static int jz4740_probe(struct platform_device *pdev)
}

musb->dev.parent = dev;
+ musb->dev.dma_mask = &musb->dev.coherent_dma_mask;
+ musb->dev.coherent_dma_mask = DMA_BIT_MASK(32);

glue->pdev = musb;
glue->clk = clk;
--
2.25.0

2020-02-24 01:41:07

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 3/5] usb: musb: jz4740: Register USB role switch

Register a USB role switch, in order to get notified by the connector
driver when the USB role changes. The notification is then transmitted
to the PHY.

Signed-off-by: Paul Cercueil <[email protected]>
---

Notes:
v2: No change

drivers/usb/musb/Kconfig | 1 +
drivers/usb/musb/jz4740.c | 46 +++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index c4b349e074c1..3268adb7d7cf 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -113,6 +113,7 @@ config USB_MUSB_JZ4740
depends on MIPS || COMPILE_TEST
depends on USB_MUSB_GADGET
depends on USB=n || USB_OTG_BLACKLIST_HUB
+ select USB_ROLE_SWITCH

config USB_MUSB_MEDIATEK
tristate "MediaTek platforms"
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index aa32b5af0c1f..bbfeb9881788 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -12,13 +12,16 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/usb/role.h>
#include <linux/usb/usb_phy_generic.h>

#include "musb_core.h"

struct jz4740_glue {
struct platform_device *pdev;
+ struct musb *musb;
struct clk *clk;
+ struct usb_role_switch *role_sw;
};

static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
@@ -72,11 +75,38 @@ static const struct musb_hdrc_config jz4740_musb_config = {
.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg),
};

+static int jz4740_musb_role_switch_set(struct device *dev, enum usb_role role)
+{
+ struct jz4740_glue *glue = dev_get_drvdata(dev);
+ struct usb_phy *phy = glue->musb->xceiv;
+
+ switch (role) {
+ case USB_ROLE_NONE:
+ atomic_notifier_call_chain(&phy->notifier, USB_EVENT_NONE, phy);
+ break;
+ case USB_ROLE_DEVICE:
+ atomic_notifier_call_chain(&phy->notifier, USB_EVENT_VBUS, phy);
+ break;
+ case USB_ROLE_HOST:
+ atomic_notifier_call_chain(&phy->notifier, USB_EVENT_ID, phy);
+ break;
+ }
+
+ return 0;
+}
+
static int jz4740_musb_init(struct musb *musb)
{
struct device *dev = musb->controller->parent;
+ struct jz4740_glue *glue = dev_get_drvdata(dev);
+ struct usb_role_switch_desc role_sw_desc = {
+ .set = jz4740_musb_role_switch_set,
+ .fwnode = dev_fwnode(dev),
+ };
int err;

+ glue->musb = musb;
+
if (dev->of_node)
musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
else
@@ -88,6 +118,12 @@ static int jz4740_musb_init(struct musb *musb)
return err;
}

+ glue->role_sw = usb_role_switch_register(dev, &role_sw_desc);
+ if (IS_ERR(glue->role_sw)) {
+ dev_err(dev, "Failed to register USB role switch");
+ return PTR_ERR(glue->role_sw);
+ }
+
/*
* Silicon does not implement ConfigData register.
* Set dyn_fifo to avoid reading EP config from hardware.
@@ -99,10 +135,20 @@ static int jz4740_musb_init(struct musb *musb)
return 0;
}

+static int jz4740_musb_exit(struct musb *musb)
+{
+ struct jz4740_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ usb_role_switch_unregister(glue->role_sw);
+
+ return 0;
+}
+
static const struct musb_platform_ops jz4740_musb_ops = {
.quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
.fifo_mode = 2,
.init = jz4740_musb_init,
+ .exit = jz4740_musb_exit,
#ifdef CONFIG_USB_INVENTRA_DMA
.dma_init = musbhs_dma_controller_create_noirq,
.dma_exit = musbhs_dma_controller_destroy,
--
2.25.0

2020-02-24 01:42:11

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 4/5] usb: musb: jz4740: Unconditionally depend on devicetree

The jz4740-musb driver is unconditionally probed from devicetree, so we
can add a hard dependency on devicetree. This makes the code a bit
cleaner, and is more future-proof as the platform data is now retrieved
using of_device_get_match_data().

Signed-off-by: Paul Cercueil <[email protected]>
---

Notes:
v2: No change

drivers/usb/musb/Kconfig | 1 +
drivers/usb/musb/jz4740.c | 14 +++++++++-----
2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 3268adb7d7cf..3b0d1c20ebe6 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -110,6 +110,7 @@ config USB_MUSB_UX500

config USB_MUSB_JZ4740
tristate "JZ4740"
+ depends on OF
depends on MIPS || COMPILE_TEST
depends on USB_MUSB_GADGET
depends on USB=n || USB_OTG_BLACKLIST_HUB
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index bbfeb9881788..b6747bad4fb2 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -164,7 +164,7 @@ static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
static int jz4740_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct musb_hdrc_platform_data *pdata = &jz4740_musb_pdata;
+ const struct musb_hdrc_platform_data *pdata;
struct platform_device *musb;
struct jz4740_glue *glue;
struct clk *clk;
@@ -174,6 +174,12 @@ static int jz4740_probe(struct platform_device *pdev)
if (!glue)
return -ENOMEM;

+ pdata = of_device_get_match_data(dev);
+ if (!pdata) {
+ dev_err(dev, "missing platform data");
+ return -EINVAL;
+ }
+
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(dev, "failed to allocate musb device");
@@ -240,20 +246,18 @@ static int jz4740_remove(struct platform_device *pdev)
return 0;
}

-#ifdef CONFIG_OF
static const struct of_device_id jz4740_musb_of_match[] = {
- { .compatible = "ingenic,jz4740-musb" },
+ { .compatible = "ingenic,jz4740-musb", .data = &jz4740_musb_pdata },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
-#endif

static struct platform_driver jz4740_driver = {
.probe = jz4740_probe,
.remove = jz4740_remove,
.driver = {
.name = "musb-jz4740",
- .of_match_table = of_match_ptr(jz4740_musb_of_match),
+ .of_match_table = jz4740_musb_of_match,
},
};

--
2.25.0

2020-02-24 01:42:31

by Paul Cercueil

[permalink] [raw]
Subject: [PATCH v2 5/5] usb: musb: jz4740: Add support for the JZ4770

Add support for probing the jz4740-musb driver on the JZ4770 SoC.

The USB IP in the JZ4770 works the same Inventra IP as for the JZ4740,
but it features more endpoints, and officially supports OTG.

Signed-off-by: Paul Cercueil <[email protected]>
---

Notes:
v2: No change

drivers/usb/musb/jz4740.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index b6747bad4fb2..8c52a1fa6fbc 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -161,6 +161,33 @@ static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
.platform_ops = &jz4740_musb_ops,
};

+static struct musb_fifo_cfg jz4770_musb_fifo_cfg[] = {
+ { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+ { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+ { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+ { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+ { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+ { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+ { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+ { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+ { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+ { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+};
+
+static struct musb_hdrc_config jz4770_musb_config = {
+ .multipoint = 1,
+ .num_eps = 11,
+ .ram_bits = 11,
+ .fifo_cfg = jz4770_musb_fifo_cfg,
+ .fifo_cfg_size = ARRAY_SIZE(jz4770_musb_fifo_cfg),
+};
+
+static const struct musb_hdrc_platform_data jz4770_musb_pdata = {
+ .mode = MUSB_PERIPHERAL, /* TODO: support OTG */
+ .config = &jz4770_musb_config,
+ .platform_ops = &jz4740_musb_ops,
+};
+
static int jz4740_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -248,6 +275,7 @@ static int jz4740_remove(struct platform_device *pdev)

static const struct of_device_id jz4740_musb_of_match[] = {
{ .compatible = "ingenic,jz4740-musb", .data = &jz4740_musb_pdata },
+ { .compatible = "ingenic,jz4770-musb", .data = &jz4770_musb_pdata },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
--
2.25.0

2020-03-09 15:40:53

by Bin Liu

[permalink] [raw]
Subject: Re: [PATCH v2 3/5] usb: musb: jz4740: Register USB role switch

Hi,

On Sun, Feb 23, 2020 at 10:40:06PM -0300, Paul Cercueil wrote:
> Register a USB role switch, in order to get notified by the connector
> driver when the USB role changes. The notification is then transmitted
> to the PHY.
>
> Signed-off-by: Paul Cercueil <[email protected]>
> ---
>
> Notes:
> v2: No change
>
> drivers/usb/musb/Kconfig | 1 +
> drivers/usb/musb/jz4740.c | 46 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 47 insertions(+)
>
> diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
> index c4b349e074c1..3268adb7d7cf 100644
> --- a/drivers/usb/musb/Kconfig
> +++ b/drivers/usb/musb/Kconfig
> @@ -113,6 +113,7 @@ config USB_MUSB_JZ4740
> depends on MIPS || COMPILE_TEST
> depends on USB_MUSB_GADGET
> depends on USB=n || USB_OTG_BLACKLIST_HUB
> + select USB_ROLE_SWITCH
>
> config USB_MUSB_MEDIATEK
> tristate "MediaTek platforms"
> diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
> index aa32b5af0c1f..bbfeb9881788 100644
> --- a/drivers/usb/musb/jz4740.c
> +++ b/drivers/usb/musb/jz4740.c
> @@ -12,13 +12,16 @@
> #include <linux/module.h>
> #include <linux/of_device.h>
> #include <linux/platform_device.h>
> +#include <linux/usb/role.h>
> #include <linux/usb/usb_phy_generic.h>
>
> #include "musb_core.h"
>
> struct jz4740_glue {
> struct platform_device *pdev;
> + struct musb *musb;
> struct clk *clk;
> + struct usb_role_switch *role_sw;
> };
>
> static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
> @@ -72,11 +75,38 @@ static const struct musb_hdrc_config jz4740_musb_config = {
> .fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg),
> };
>
> +static int jz4740_musb_role_switch_set(struct device *dev, enum usb_role role)

The prototype has been changed by bce3052f0c16 ("usb: roles: Provide the
switch drivers handle to the switch in the API"). Please update.

Thanks,
-Bin.