Merge branch 'next' of git://source.denx.de/u-boot-usb into next

- dwc3-generic rework and then switch uniphier to it
This commit is contained in:
Tom Rini 2023-02-22 18:21:40 -05:00
commit 97b92f7d17
11 changed files with 459 additions and 100 deletions

View File

@ -82,7 +82,6 @@ CONFIG_DM_SPI=y
CONFIG_UNIPHIER_SPI=y CONFIG_UNIPHIER_SPI=y
CONFIG_USB=y CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y CONFIG_USB_EHCI_GENERIC=y
CONFIG_USB_DWC3=y CONFIG_USB_DWC3=y

View File

@ -71,7 +71,6 @@ CONFIG_SYSRESET=y
CONFIG_SYSRESET_PSCI=y CONFIG_SYSRESET_PSCI=y
CONFIG_USB=y CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y CONFIG_USB_EHCI_GENERIC=y
CONFIG_USB_DWC3=y CONFIG_USB_DWC3=y

View File

@ -28,7 +28,10 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(14, 0x2104, 16), /* usb30 (Pro4, Pro5, PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(14, 0x2104, 16), /* usb30 (Pro4, Pro5, PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17), /* usb31 (Pro4, Pro5, PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17), /* usb31 (Pro4, Pro5, PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19), /* usb30-phy (PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19), /* usb30-phy (PXs2) */
UNIPHIER_CLK_RATE(17, 25000000), /* usb30-phy2 (PXs2) */
UNIPHIER_CLK_RATE(18, 25000000), /* usb30-phy3 (PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20), /* usb31-phy (PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20), /* usb31-phy (PXs2) */
UNIPHIER_CLK_RATE(21, 25000000), /* usb31-phy2 (PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2), /* pcie (Pro5) */ UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2), /* pcie (Pro5) */
{ /* sentinel */ } { /* sentinel */ }
#endif #endif
@ -44,6 +47,8 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14), /* usb30 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14), /* usb30 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12), /* usb30-phy0 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12), /* usb30-phy0 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13), /* usb30-phy1 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13), /* usb30-phy1 (LD20) */
UNIPHIER_CLK_RATE(18, 25000000), /* usb30-phy2 (LD20) */
UNIPHIER_CLK_RATE(19, 25000000), /* usb30-phy3 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4), /* pcie */ UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4), /* pcie */
{ /* sentinel */ } { /* sentinel */ }
#endif #endif

View File

@ -10,3 +10,11 @@ config PHY_UNIPHIER_PCIE
help help
Enable this to support PHY implemented in PCIe controller Enable this to support PHY implemented in PCIe controller
on UniPhier SoCs. on UniPhier SoCs.
config PHY_UNIPHIER_USB3
bool "UniPhier USB3 PHY driver"
depends on PHY && ARCH_UNIPHIER
imply REGMAP
help
Enable this to support PHY implemented in USB3 controller
on UniPhier SoCs.

View File

@ -4,3 +4,4 @@
# #
obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o
obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3.o

View File

@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* phy_uniphier_usb3.c - Socionext UniPhier Usb3 PHY driver
* Copyright 2019-2023 Socionext, Inc.
*/
#include <common.h>
#include <dm.h>
#include <generic-phy.h>
#include <clk.h>
#include <reset.h>
struct uniphier_usb3phy_priv {
struct clk *clk_link, *clk_phy, *clk_parent, *clk_phyext;
struct reset_ctl *rst_link, *rst_phy, *rst_parent;
};
static int uniphier_usb3phy_init(struct phy *phy)
{
struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
int ret;
ret = clk_enable(priv->clk_phy);
if (ret)
return ret;
ret = reset_deassert(priv->rst_phy);
if (ret)
goto out_clk;
if (priv->clk_phyext) {
ret = clk_enable(priv->clk_phyext);
if (ret)
goto out_rst;
}
return 0;
out_rst:
reset_assert(priv->rst_phy);
out_clk:
clk_disable(priv->clk_phy);
return ret;
}
static int uniphier_usb3phy_exit(struct phy *phy)
{
struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
if (priv->clk_phyext)
clk_disable(priv->clk_phyext);
reset_assert(priv->rst_phy);
clk_disable(priv->clk_phy);
return 0;
}
static int uniphier_usb3phy_probe(struct udevice *dev)
{
struct uniphier_usb3phy_priv *priv = dev_get_priv(dev);
int ret;
priv->clk_link = devm_clk_get(dev, "link");
if (IS_ERR(priv->clk_link)) {
printf("Failed to get link clock\n");
return PTR_ERR(priv->clk_link);
}
priv->clk_phy = devm_clk_get(dev, "phy");
if (IS_ERR(priv->clk_link)) {
printf("Failed to get phy clock\n");
return PTR_ERR(priv->clk_link);
}
priv->clk_parent = devm_clk_get_optional(dev, "gio");
if (IS_ERR(priv->clk_parent)) {
printf("Failed to get parent clock\n");
return PTR_ERR(priv->clk_parent);
}
priv->clk_phyext = devm_clk_get_optional(dev, "phy-ext");
if (IS_ERR(priv->clk_phyext)) {
printf("Failed to get external phy clock\n");
return PTR_ERR(priv->clk_phyext);
}
priv->rst_link = devm_reset_control_get(dev, "link");
if (IS_ERR(priv->rst_link)) {
printf("Failed to get link reset\n");
return PTR_ERR(priv->rst_link);
}
priv->rst_phy = devm_reset_control_get(dev, "phy");
if (IS_ERR(priv->rst_phy)) {
printf("Failed to get phy reset\n");
return PTR_ERR(priv->rst_phy);
}
priv->rst_parent = devm_reset_control_get_optional(dev, "gio");
if (IS_ERR(priv->rst_parent)) {
printf("Failed to get parent reset\n");
return PTR_ERR(priv->rst_parent);
}
if (priv->clk_parent) {
ret = clk_enable(priv->clk_parent);
if (ret)
return ret;
}
if (priv->rst_parent) {
ret = reset_deassert(priv->rst_parent);
if (ret)
goto out_clk_parent;
}
ret = clk_enable(priv->clk_link);
if (ret)
goto out_rst_parent;
ret = reset_deassert(priv->rst_link);
if (ret)
goto out_clk;
return 0;
out_clk:
clk_disable(priv->clk_link);
out_rst_parent:
if (priv->rst_parent)
reset_assert(priv->rst_parent);
out_clk_parent:
if (priv->clk_parent)
clk_disable(priv->clk_parent);
return ret;
}
static struct phy_ops uniphier_usb3phy_ops = {
.init = uniphier_usb3phy_init,
.exit = uniphier_usb3phy_exit,
};
static const struct udevice_id uniphier_usb3phy_ids[] = {
{ .compatible = "socionext,uniphier-pro4-usb3-ssphy" },
{ .compatible = "socionext,uniphier-pro5-usb3-hsphy" },
{ .compatible = "socionext,uniphier-pro5-usb3-ssphy" },
{ .compatible = "socionext,uniphier-pxs2-usb3-hsphy" },
{ .compatible = "socionext,uniphier-pxs2-usb3-ssphy" },
{ .compatible = "socionext,uniphier-ld20-usb3-hsphy" },
{ .compatible = "socionext,uniphier-ld20-usb3-ssphy" },
{ .compatible = "socionext,uniphier-pxs3-usb3-hsphy" },
{ .compatible = "socionext,uniphier-pxs3-usb3-ssphy" },
{ .compatible = "socionext,uniphier-nx1-usb3-hsphy" },
{ .compatible = "socionext,uniphier-nx1-usb3-ssphy" },
{ }
};
U_BOOT_DRIVER(uniphier_usb3_phy) = {
.name = "uniphier-usb3-phy",
.id = UCLASS_PHY,
.of_match = uniphier_usb3phy_ids,
.ops = &uniphier_usb3phy_ops,
.probe = uniphier_usb3phy_probe,
.priv_auto = sizeof(struct uniphier_usb3phy_priv),
};

View File

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2016 Socionext Inc. * Copyright (C) 2016 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
* Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
*/ */
#include <common.h> #include <common.h>
@ -9,6 +10,8 @@
#include <log.h> #include <log.h>
#include <malloc.h> #include <malloc.h>
#include <reset-uclass.h> #include <reset-uclass.h>
#include <clk.h>
#include <reset.h>
#include <dm/device_compat.h> #include <dm/device_compat.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/io.h> #include <linux/io.h>
@ -178,10 +181,17 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
UNIPHIER_RESET_END, UNIPHIER_RESET_END,
}; };
/* Glue reset data */
static const struct uniphier_reset_data uniphier_pro4_usb3_reset_data[] = {
UNIPHIER_RESETX(15, 0, 15)
};
/* core implementaton */ /* core implementaton */
struct uniphier_reset_priv { struct uniphier_reset_priv {
void __iomem *base; void __iomem *base;
const struct uniphier_reset_data *data; const struct uniphier_reset_data *data;
struct clk_bulk clks;
struct reset_ctl_bulk rsts;
}; };
static int uniphier_reset_update(struct reset_ctl *reset_ctl, int assert) static int uniphier_reset_update(struct reset_ctl *reset_ctl, int assert)
@ -233,10 +243,47 @@ static const struct reset_ops uniphier_reset_ops = {
.rst_deassert = uniphier_reset_deassert, .rst_deassert = uniphier_reset_deassert,
}; };
static int uniphier_reset_rst_init(struct udevice *dev)
{
struct uniphier_reset_priv *priv = dev_get_priv(dev);
int ret;
ret = reset_get_bulk(dev, &priv->rsts);
if (ret == -ENOSYS || ret == -ENOENT)
return 0;
else if (ret)
return ret;
ret = reset_deassert_bulk(&priv->rsts);
if (ret)
reset_release_bulk(&priv->rsts);
return ret;
}
static int uniphier_reset_clk_init(struct udevice *dev)
{
struct uniphier_reset_priv *priv = dev_get_priv(dev);
int ret;
ret = clk_get_bulk(dev, &priv->clks);
if (ret == -ENOSYS || ret == -ENOENT)
return 0;
if (ret)
return ret;
ret = clk_enable_bulk(&priv->clks);
if (ret)
clk_release_bulk(&priv->clks);
return ret;
}
static int uniphier_reset_probe(struct udevice *dev) static int uniphier_reset_probe(struct udevice *dev)
{ {
struct uniphier_reset_priv *priv = dev_get_priv(dev); struct uniphier_reset_priv *priv = dev_get_priv(dev);
fdt_addr_t addr; fdt_addr_t addr;
int ret;
addr = dev_read_addr(dev->parent); addr = dev_read_addr(dev->parent);
if (addr == FDT_ADDR_T_NONE) if (addr == FDT_ADDR_T_NONE)
@ -248,7 +295,11 @@ static int uniphier_reset_probe(struct udevice *dev)
priv->data = (void *)dev_get_driver_data(dev); priv->data = (void *)dev_get_driver_data(dev);
return 0; ret = uniphier_reset_clk_init(dev);
if (ret)
return ret;
return uniphier_reset_rst_init(dev);
} }
static const struct udevice_id uniphier_reset_match[] = { static const struct udevice_id uniphier_reset_match[] = {
@ -355,6 +406,31 @@ static const struct udevice_id uniphier_reset_match[] = {
.compatible = "socionext,uniphier-pxs3-peri-reset", .compatible = "socionext,uniphier-pxs3-peri-reset",
.data = (ulong)uniphier_pro4_peri_reset_data, .data = (ulong)uniphier_pro4_peri_reset_data,
}, },
/* USB glue reset */
{
.compatible = "socionext,uniphier-pro4-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{
.compatible = "socionext,uniphier-pro5-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{
.compatible = "socionext,uniphier-pxs2-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{
.compatible = "socionext,uniphier-ld20-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{
.compatible = "socionext,uniphier-pxs3-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{
.compatible = "socionext,uniphier-nx1-usb3-reset",
.data = (ulong)uniphier_pro4_usb3_reset_data,
},
{ /* sentinel */ } { /* sentinel */ }
}; };

View File

@ -55,7 +55,9 @@ config USB_DWC3_MESON_GXL
config USB_DWC3_UNIPHIER config USB_DWC3_UNIPHIER
bool "DesignWare USB3 Host Support on UniPhier Platforms" bool "DesignWare USB3 Host Support on UniPhier Platforms"
depends on ARCH_UNIPHIER && USB_XHCI_DWC3 depends on ARCH_UNIPHIER && USB_DWC3
select USB_DWC3_GENERIC
select PHY_UNIPHIER_USB3
help help
Support of USB2/3 functionality in Socionext UniPhier platforms. Support of USB2/3 functionality in Socionext UniPhier platforms.
Say 'Y' here if you have one such device. Say 'Y' here if you have one such device.

View File

@ -28,11 +28,7 @@
#include <usb/xhci.h> #include <usb/xhci.h>
#include <asm/gpio.h> #include <asm/gpio.h>
struct dwc3_glue_data { #include "dwc3-generic.h"
struct clk_bulk clks;
struct reset_ctl_bulk resets;
fdt_addr_t regs;
};
struct dwc3_generic_plat { struct dwc3_generic_plat {
fdt_addr_t base; fdt_addr_t base;
@ -68,10 +64,27 @@ static int dwc3_generic_probe(struct udevice *dev,
#if CONFIG_IS_ENABLED(OF_CONTROL) #if CONFIG_IS_ENABLED(OF_CONTROL)
dwc3_of_parse(dwc3); dwc3_of_parse(dwc3);
/*
* There are currently four disparate placement possibilities of DWC3
* reference clock phandle in SoC DTs:
* - in top level glue node, with generic subnode without clock (ZynqMP)
* - in top level generic node, with no subnode (i.MX8MQ)
* - in generic subnode, with other clock in top level node (i.MX8MP)
* - in both top level node and generic subnode (Rockchip)
* Cover all the possibilities here by looking into both nodes, start
* with the top level node as that seems to be used in majority of DTs
* to reference the clock.
*/
node = dev_ofnode(dev->parent); node = dev_ofnode(dev->parent);
index = ofnode_stringlist_search(node, "clock-names", "ref"); index = ofnode_stringlist_search(node, "clock-names", "ref");
if (index < 0) if (index < 0)
index = ofnode_stringlist_search(node, "clock-names", "ref_clk"); index = ofnode_stringlist_search(node, "clock-names", "ref_clk");
if (index < 0) {
node = dev_ofnode(dev);
index = ofnode_stringlist_search(node, "clock-names", "ref");
if (index < 0)
index = ofnode_stringlist_search(node, "clock-names", "ref_clk");
}
if (index >= 0) if (index >= 0)
dwc3->ref_clk = &glue->clks.clks[index]; dwc3->ref_clk = &glue->clks.clks[index];
#endif #endif
@ -258,11 +271,6 @@ U_BOOT_DRIVER(dwc3_generic_host) = {
}; };
#endif #endif
struct dwc3_glue_ops {
void (*glue_configure)(struct udevice *dev, int index,
enum usb_dr_mode mode);
};
void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, void dwc3_imx8mp_glue_configure(struct udevice *dev, int index,
enum usb_dr_mode mode) enum usb_dr_mode mode)
{ {
@ -398,22 +406,18 @@ struct dwc3_glue_ops ti_ops = {
.glue_configure = dwc3_ti_glue_configure, .glue_configure = dwc3_ti_glue_configure,
}; };
static int dwc3_glue_bind(struct udevice *parent) static int dwc3_glue_bind_common(struct udevice *parent, ofnode node)
{ {
ofnode node;
int ret;
enum usb_dr_mode dr_mode;
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
ofnode_for_each_subnode(node, dev_ofnode(parent)) {
const char *name = ofnode_get_name(node); const char *name = ofnode_get_name(node);
struct udevice *dev;
const char *driver = NULL; const char *driver = NULL;
enum usb_dr_mode dr_mode;
struct udevice *dev;
int ret;
debug("%s: subnode name: %s\n", __func__, name); debug("%s: subnode name: %s\n", __func__, name);
/* if the parent node doesn't have a mode check the leaf */ /* if the parent node doesn't have a mode check the leaf */
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
if (!dr_mode) if (!dr_mode)
dr_mode = usb_get_dr_mode(node); dr_mode = usb_get_dr_mode(node);
@ -437,7 +441,7 @@ static int dwc3_glue_bind(struct udevice *parent)
}; };
if (!driver) if (!driver)
continue; return -ENXIO;
ret = device_bind_driver_to_node(parent, driver, name, ret = device_bind_driver_to_node(parent, driver, name,
node, &dev); node, &dev);
@ -446,6 +450,30 @@ static int dwc3_glue_bind(struct udevice *parent)
__func__); __func__);
return ret; return ret;
} }
return 0;
}
int dwc3_glue_bind(struct udevice *parent)
{
struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(parent);
ofnode node;
int ret;
if (ops && ops->glue_get_ctrl_dev) {
ret = ops->glue_get_ctrl_dev(parent, &node);
if (ret)
return ret;
return dwc3_glue_bind_common(parent, node);
}
ofnode_for_each_subnode(node, dev_ofnode(parent)) {
ret = dwc3_glue_bind_common(parent, node);
if (ret == -ENXIO)
continue;
if (ret)
return ret;
} }
return 0; return 0;
@ -493,7 +521,7 @@ static int dwc3_glue_clk_init(struct udevice *dev,
return 0; return 0;
} }
static int dwc3_glue_probe(struct udevice *dev) int dwc3_glue_probe(struct udevice *dev)
{ {
struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
struct dwc3_glue_data *glue = dev_get_plat(dev); struct dwc3_glue_data *glue = dev_get_plat(dev);
@ -514,7 +542,7 @@ static int dwc3_glue_probe(struct udevice *dev)
phy.dev = NULL; phy.dev = NULL;
} }
glue->regs = dev_read_addr(dev); glue->regs = dev_read_addr_size_index(dev, 0, &glue->size);
ret = dwc3_glue_clk_init(dev, glue); ret = dwc3_glue_clk_init(dev, glue);
if (ret) if (ret)
@ -534,6 +562,12 @@ static int dwc3_glue_probe(struct udevice *dev)
if (ret) if (ret)
return ret; return ret;
if (glue->clks.count == 0) {
ret = dwc3_glue_clk_init(child, glue);
if (ret)
return ret;
}
if (glue->resets.count == 0) { if (glue->resets.count == 0) {
ret = dwc3_glue_reset_init(child, glue); ret = dwc3_glue_reset_init(child, glue);
if (ret) if (ret)
@ -553,7 +587,7 @@ static int dwc3_glue_probe(struct udevice *dev)
return 0; return 0;
} }
static int dwc3_glue_remove(struct udevice *dev) int dwc3_glue_remove(struct udevice *dev)
{ {
struct dwc3_glue_data *glue = dev_get_plat(dev); struct dwc3_glue_data *glue = dev_get_plat(dev);

View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* dwc3-generic.h - Generic DWC3 Glue layer header
*
* Copyright (C) 2016 - 2018 Xilinx, Inc.
* Copyright (C) 2023 Socionext Inc.
*/
#ifndef __DRIVERS_USB_DWC3_GENERIC_H
#define __DRIVERS_USB_DWC3_GENERIC_H
#include <clk.h>
#include <reset.h>
#include <dwc3-uboot.h>
struct dwc3_glue_data {
struct clk_bulk clks;
struct reset_ctl_bulk resets;
fdt_addr_t regs;
fdt_size_t size;
};
struct dwc3_glue_ops {
int (*glue_get_ctrl_dev)(struct udevice *parent, ofnode *node);
void (*glue_configure)(struct udevice *dev, int index,
enum usb_dr_mode mode);
};
int dwc3_glue_bind(struct udevice *parent);
int dwc3_glue_probe(struct udevice *dev);
int dwc3_glue_remove(struct udevice *dev);
#endif

View File

@ -4,14 +4,17 @@
* *
* Copyright (C) 2016-2017 Socionext Inc. * Copyright (C) 2016-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com> * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
* Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
*/ */
#include <dm.h> #include <dm.h>
#include <dm/device_compat.h> #include <dm/lists.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/errno.h> #include <linux/usb/gadget.h>
#include <linux/io.h>
#include <linux/sizes.h> #include "core.h"
#include "gadget.h"
#include "dwc3-generic.h"
#define UNIPHIER_PRO4_DWC3_RESET 0x40 #define UNIPHIER_PRO4_DWC3_RESET 0x40
#define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5) #define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5)
@ -27,8 +30,11 @@
#define UNIPHIER_PXS2_DWC3_RESET 0x00 #define UNIPHIER_PXS2_DWC3_RESET 0x00
#define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15) #define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15)
static int uniphier_pro4_dwc3_init(void __iomem *regs) static void uniphier_pro4_dwc3_init(struct udevice *dev, int index,
enum usb_dr_mode mode)
{ {
struct dwc3_glue_data *glue = dev_get_plat(dev);
void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
u32 tmp; u32 tmp;
tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET); tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
@ -36,11 +42,14 @@ static int uniphier_pro4_dwc3_init(void __iomem *regs)
tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK; tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET); writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
return 0; unmap_physmem(regs, MAP_NOCACHE);
} }
static int uniphier_pro5_dwc3_init(void __iomem *regs) static void uniphier_pro5_dwc3_init(struct udevice *dev, int index,
enum usb_dr_mode mode)
{ {
struct dwc3_glue_data *glue = dev_get_plat(dev);
void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
u32 tmp; u32 tmp;
tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET); tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
@ -49,72 +58,97 @@ static int uniphier_pro5_dwc3_init(void __iomem *regs)
tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU; tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET); writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
return 0; unmap_physmem(regs, MAP_NOCACHE);
} }
static int uniphier_pxs2_dwc3_init(void __iomem *regs) static void uniphier_pxs2_dwc3_init(struct udevice *dev, int index,
enum usb_dr_mode mode)
{ {
struct dwc3_glue_data *glue = dev_get_plat(dev);
void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
u32 tmp; u32 tmp;
tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET); tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK; tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET); writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
unmap_physmem(regs, MAP_NOCACHE);
}
static int dwc3_uniphier_glue_get_ctrl_dev(struct udevice *dev, ofnode *node)
{
struct udevice *child;
const char *name;
ofnode subnode;
/*
* "controller reset" belongs to glue logic, and it should be
* accessible in .glue_configure() before access to the controller
* begins.
*/
ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
name = ofnode_get_name(subnode);
if (!strncmp(name, "reset", 5))
device_bind_driver_to_node(dev, "uniphier-reset",
name, subnode, &child);
}
/* Get controller node that is placed separately from the glue node */
*node = ofnode_by_compatible(dev_ofnode(dev->parent),
"socionext,uniphier-dwc3");
return 0; return 0;
} }
static int uniphier_dwc3_probe(struct udevice *dev) static const struct dwc3_glue_ops uniphier_pro4_dwc3_ops = {
{ .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
fdt_addr_t base; .glue_configure = uniphier_pro4_dwc3_init,
void __iomem *regs; };
int (*init)(void __iomem *regs);
int ret;
base = dev_read_addr(dev); static const struct dwc3_glue_ops uniphier_pro5_dwc3_ops = {
if (base == FDT_ADDR_T_NONE) .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
return -EINVAL; .glue_configure = uniphier_pro5_dwc3_init,
};
regs = ioremap(base, SZ_32K); static const struct dwc3_glue_ops uniphier_pxs2_dwc3_ops = {
if (!regs) .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
return -ENOMEM; .glue_configure = uniphier_pxs2_dwc3_init,
};
init = (typeof(init))dev_get_driver_data(dev);
ret = init(regs);
if (ret)
dev_err(dev, "failed to init glue layer\n");
iounmap(regs);
return ret;
}
static const struct udevice_id uniphier_dwc3_match[] = { static const struct udevice_id uniphier_dwc3_match[] = {
{ {
.compatible = "socionext,uniphier-pro4-dwc3", .compatible = "socionext,uniphier-pro4-dwc3-glue",
.data = (ulong)uniphier_pro4_dwc3_init, .data = (ulong)&uniphier_pro4_dwc3_ops,
}, },
{ {
.compatible = "socionext,uniphier-pro5-dwc3", .compatible = "socionext,uniphier-pro5-dwc3-glue",
.data = (ulong)uniphier_pro5_dwc3_init, .data = (ulong)&uniphier_pro5_dwc3_ops,
}, },
{ {
.compatible = "socionext,uniphier-pxs2-dwc3", .compatible = "socionext,uniphier-pxs2-dwc3-glue",
.data = (ulong)uniphier_pxs2_dwc3_init, .data = (ulong)&uniphier_pxs2_dwc3_ops,
}, },
{ {
.compatible = "socionext,uniphier-ld20-dwc3", .compatible = "socionext,uniphier-ld20-dwc3-glue",
.data = (ulong)uniphier_pxs2_dwc3_init, .data = (ulong)&uniphier_pxs2_dwc3_ops,
}, },
{ {
.compatible = "socionext,uniphier-pxs3-dwc3", .compatible = "socionext,uniphier-pxs3-dwc3-glue",
.data = (ulong)uniphier_pxs2_dwc3_init, .data = (ulong)&uniphier_pxs2_dwc3_ops,
},
{
.compatible = "socionext,uniphier-nx1-dwc3-glue",
.data = (ulong)&uniphier_pxs2_dwc3_ops,
}, },
{ /* sentinel */ } { /* sentinel */ }
}; };
U_BOOT_DRIVER(usb_xhci) = { U_BOOT_DRIVER(dwc3_uniphier_wrapper) = {
.name = "uniphier-dwc3", .name = "uniphier-dwc3",
.id = UCLASS_SIMPLE_BUS, .id = UCLASS_SIMPLE_BUS,
.of_match = uniphier_dwc3_match, .of_match = uniphier_dwc3_match,
.probe = uniphier_dwc3_probe, .bind = dwc3_glue_bind,
.probe = dwc3_glue_probe,
.remove = dwc3_glue_remove,
.plat_auto = sizeof(struct dwc3_glue_data),
}; };