mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-22 07:01:24 +02:00
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:
commit
97b92f7d17
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
168
drivers/phy/socionext/phy-uniphier-usb3.c
Normal file
168
drivers/phy/socionext/phy-uniphier-usb3.c
Normal 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),
|
||||||
|
};
|
@ -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 */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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,54 +406,74 @@ 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)
|
||||||
{
|
{
|
||||||
|
const char *name = ofnode_get_name(node);
|
||||||
|
const char *driver = NULL;
|
||||||
|
enum usb_dr_mode dr_mode;
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
debug("%s: subnode name: %s\n", __func__, name);
|
||||||
|
|
||||||
|
/* if the parent node doesn't have a mode check the leaf */
|
||||||
|
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
|
||||||
|
if (!dr_mode)
|
||||||
|
dr_mode = usb_get_dr_mode(node);
|
||||||
|
|
||||||
|
switch (dr_mode) {
|
||||||
|
case USB_DR_MODE_PERIPHERAL:
|
||||||
|
case USB_DR_MODE_OTG:
|
||||||
|
#if CONFIG_IS_ENABLED(DM_USB_GADGET)
|
||||||
|
debug("%s: dr_mode: OTG or Peripheral\n", __func__);
|
||||||
|
driver = "dwc3-generic-peripheral";
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
|
||||||
|
case USB_DR_MODE_HOST:
|
||||||
|
debug("%s: dr_mode: HOST\n", __func__);
|
||||||
|
driver = "dwc3-generic-host";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
debug("%s: unsupported dr_mode\n", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!driver)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
ret = device_bind_driver_to_node(parent, driver, name,
|
||||||
|
node, &dev);
|
||||||
|
if (ret) {
|
||||||
|
debug("%s: not able to bind usb device mode\n",
|
||||||
|
__func__);
|
||||||
|
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;
|
ofnode node;
|
||||||
int ret;
|
int ret;
|
||||||
enum usb_dr_mode dr_mode;
|
|
||||||
|
|
||||||
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
|
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)) {
|
ofnode_for_each_subnode(node, dev_ofnode(parent)) {
|
||||||
const char *name = ofnode_get_name(node);
|
ret = dwc3_glue_bind_common(parent, node);
|
||||||
struct udevice *dev;
|
if (ret == -ENXIO)
|
||||||
const char *driver = NULL;
|
|
||||||
|
|
||||||
debug("%s: subnode name: %s\n", __func__, name);
|
|
||||||
|
|
||||||
/* if the parent node doesn't have a mode check the leaf */
|
|
||||||
if (!dr_mode)
|
|
||||||
dr_mode = usb_get_dr_mode(node);
|
|
||||||
|
|
||||||
switch (dr_mode) {
|
|
||||||
case USB_DR_MODE_PERIPHERAL:
|
|
||||||
case USB_DR_MODE_OTG:
|
|
||||||
#if CONFIG_IS_ENABLED(DM_USB_GADGET)
|
|
||||||
debug("%s: dr_mode: OTG or Peripheral\n", __func__);
|
|
||||||
driver = "dwc3-generic-peripheral";
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
|
|
||||||
case USB_DR_MODE_HOST:
|
|
||||||
debug("%s: dr_mode: HOST\n", __func__);
|
|
||||||
driver = "dwc3-generic-host";
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
debug("%s: unsupported dr_mode\n", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!driver)
|
|
||||||
continue;
|
continue;
|
||||||
|
if (ret)
|
||||||
ret = device_bind_driver_to_node(parent, driver, name,
|
|
||||||
node, &dev);
|
|
||||||
if (ret) {
|
|
||||||
debug("%s: not able to bind usb device mode\n",
|
|
||||||
__func__);
|
|
||||||
return 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);
|
||||||
|
|
||||||
|
33
drivers/usb/dwc3/dwc3-generic.h
Normal file
33
drivers/usb/dwc3/dwc3-generic.h
Normal 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
|
@ -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),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user