mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 23:51:33 +00:00
usb: dwc3: add layerscape support
Add support for the proper dwc3 device tree binding support as specified in the offical device tree spec. Initially, add support for the LS1028A support. Other SoCs should be easy to add by just adding the corresponding compatible string. Unfortunately, the device trees of all other layerscape SoCs are not converted and uses a wrong compatible string only known in u-boot. To maintain backwards compatibility with current u-boot device trees, add the generic "fsl,layerscape-dwc3" compatible string. OTG mode is not supported yet. The dr_mode in the devicetree will either have to be set to peripheral or host. Signed-off-by: Michael Walle <michael@walle.cc> Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
This commit is contained in:
parent
f150b8d28b
commit
2b0b51d0be
3 changed files with 233 additions and 0 deletions
|
@ -53,6 +53,16 @@ config USB_DWC3_UNIPHIER
|
|||
Support of USB2/3 functionality in Socionext UniPhier platforms.
|
||||
Say 'Y' here if you have one such device.
|
||||
|
||||
config USB_DWC3_LAYERSCAPE
|
||||
bool "Freescale Layerscape platform support"
|
||||
depends on DM_USB && USB_DWC3
|
||||
depends on !USB_XHCI_FSL
|
||||
help
|
||||
Select this for Freescale Layerscape Platforms.
|
||||
|
||||
Host and Peripheral operation modes are supported. OTG is not
|
||||
supported.
|
||||
|
||||
menu "PHY Subsystem"
|
||||
|
||||
config USB_DWC3_PHY_OMAP
|
||||
|
|
|
@ -11,5 +11,6 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
|
|||
obj-$(CONFIG_USB_DWC3_MESON_GXL) += dwc3-meson-gxl.o
|
||||
obj-$(CONFIG_USB_DWC3_GENERIC) += dwc3-generic.o
|
||||
obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o
|
||||
obj-$(CONFIG_USB_DWC3_LAYERSCAPE) += dwc3-layerscape.o
|
||||
obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o
|
||||
obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o
|
||||
|
|
222
drivers/usb/dwc3/dwc3-layerscape.c
Normal file
222
drivers/usb/dwc3/dwc3-layerscape.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Layerscape DWC3 Glue layer
|
||||
*
|
||||
* Copyright (C) 2021 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* Based on dwc3-generic.c.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dwc3-uboot.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <usb.h>
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include <usb/xhci.h>
|
||||
|
||||
struct dwc3_layerscape_plat {
|
||||
fdt_addr_t base;
|
||||
u32 maximum_speed;
|
||||
enum usb_dr_mode dr_mode;
|
||||
};
|
||||
|
||||
struct dwc3_layerscape_priv {
|
||||
void *base;
|
||||
struct dwc3 dwc3;
|
||||
struct phy_bulk phys;
|
||||
};
|
||||
|
||||
struct dwc3_layerscape_host_priv {
|
||||
struct xhci_ctrl xhci_ctrl;
|
||||
struct dwc3_layerscape_priv gen_priv;
|
||||
};
|
||||
|
||||
static int dwc3_layerscape_probe(struct udevice *dev,
|
||||
struct dwc3_layerscape_priv *priv)
|
||||
{
|
||||
int rc;
|
||||
struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
|
||||
struct dwc3 *dwc3 = &priv->dwc3;
|
||||
|
||||
dwc3->dev = dev;
|
||||
dwc3->maximum_speed = plat->maximum_speed;
|
||||
dwc3->dr_mode = plat->dr_mode;
|
||||
if (CONFIG_IS_ENABLED(OF_CONTROL))
|
||||
dwc3_of_parse(dwc3);
|
||||
|
||||
rc = dwc3_setup_phy(dev, &priv->phys);
|
||||
if (rc && rc != -ENOTSUPP)
|
||||
return rc;
|
||||
|
||||
priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
|
||||
dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
|
||||
|
||||
rc = dwc3_init(dwc3);
|
||||
if (rc) {
|
||||
unmap_physmem(priv->base, MAP_NOCACHE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_layerscape_remove(struct udevice *dev,
|
||||
struct dwc3_layerscape_priv *priv)
|
||||
{
|
||||
struct dwc3 *dwc3 = &priv->dwc3;
|
||||
|
||||
dwc3_remove(dwc3);
|
||||
dwc3_shutdown_phy(dev, &priv->phys);
|
||||
unmap_physmem(dwc3->regs, MAP_NOCACHE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_layerscape_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
|
||||
ofnode node = dev_ofnode(dev);
|
||||
|
||||
plat->base = dev_read_addr(dev);
|
||||
|
||||
plat->maximum_speed = usb_get_maximum_speed(node);
|
||||
if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
|
||||
dev_dbg(dev, "No USB maximum speed specified. Using super speed\n");
|
||||
plat->maximum_speed = USB_SPEED_SUPER;
|
||||
}
|
||||
|
||||
plat->dr_mode = usb_get_dr_mode(node);
|
||||
if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
|
||||
dev_err(dev, "Invalid usb mode setup\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_USB_GADGET)
|
||||
int dm_usb_gadget_handle_interrupts(struct udevice *dev)
|
||||
{
|
||||
struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
|
||||
|
||||
dwc3_gadget_uboot_handle_interrupt(&priv->dwc3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_layerscape_peripheral_probe(struct udevice *dev)
|
||||
{
|
||||
struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return dwc3_layerscape_probe(dev, priv);
|
||||
}
|
||||
|
||||
static int dwc3_layerscape_peripheral_remove(struct udevice *dev)
|
||||
{
|
||||
struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return dwc3_layerscape_remove(dev, priv);
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(dwc3_layerscape_peripheral) = {
|
||||
.name = "dwc3-layerscape-peripheral",
|
||||
.id = UCLASS_USB_GADGET_GENERIC,
|
||||
.of_to_plat = dwc3_layerscape_of_to_plat,
|
||||
.probe = dwc3_layerscape_peripheral_probe,
|
||||
.remove = dwc3_layerscape_peripheral_remove,
|
||||
.priv_auto = sizeof(struct dwc3_layerscape_priv),
|
||||
.plat_auto = sizeof(struct dwc3_layerscape_plat),
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
|
||||
!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)
|
||||
static int dwc3_layerscape_host_probe(struct udevice *dev)
|
||||
{
|
||||
struct xhci_hcor *hcor;
|
||||
struct xhci_hccr *hccr;
|
||||
struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
|
||||
int rc;
|
||||
|
||||
rc = dwc3_layerscape_probe(dev, &priv->gen_priv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
hccr = priv->gen_priv.base;
|
||||
hcor = priv->gen_priv.base + HC_LENGTH(xhci_readl(&hccr->cr_capbase));
|
||||
|
||||
return xhci_register(dev, hccr, hcor);
|
||||
}
|
||||
|
||||
static int dwc3_layerscape_host_remove(struct udevice *dev)
|
||||
{
|
||||
struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
|
||||
int rc;
|
||||
|
||||
rc = xhci_deregister(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return dwc3_layerscape_remove(dev, &priv->gen_priv);
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(dwc3_layerscape_host) = {
|
||||
.name = "dwc3-layerscape-host",
|
||||
.id = UCLASS_USB,
|
||||
.of_to_plat = dwc3_layerscape_of_to_plat,
|
||||
.probe = dwc3_layerscape_host_probe,
|
||||
.remove = dwc3_layerscape_host_remove,
|
||||
.priv_auto = sizeof(struct dwc3_layerscape_host_priv),
|
||||
.plat_auto = sizeof(struct dwc3_layerscape_plat),
|
||||
.ops = &xhci_usb_ops,
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int dwc3_layerscape_bind(struct udevice *dev)
|
||||
{
|
||||
ofnode node = dev_ofnode(dev);
|
||||
const char *name = ofnode_get_name(node);
|
||||
enum usb_dr_mode dr_mode;
|
||||
char *driver;
|
||||
|
||||
dr_mode = usb_get_dr_mode(node);
|
||||
|
||||
switch (dr_mode) {
|
||||
#if CONFIG_IS_ENABLED(DM_USB_GADGET)
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dev_dbg(dev, "Using peripheral mode\n");
|
||||
driver = "dwc3-layerscape-peripheral";
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
|
||||
case USB_DR_MODE_HOST:
|
||||
dev_dbg(dev, "Using host mode\n");
|
||||
driver = "dwc3-layerscape-host";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dev_dbg(dev, "Unsupported dr_mode\n");
|
||||
return -ENODEV;
|
||||
};
|
||||
|
||||
return device_bind_driver_to_node(dev, driver, name, node, NULL);
|
||||
}
|
||||
|
||||
static const struct udevice_id dwc3_layerscape_ids[] = {
|
||||
{ .compatible = "fsl,layerscape-dwc3" },
|
||||
{ .compatible = "fsl,ls1028a-dwc3" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(dwc3_layerscape_wrapper) = {
|
||||
.name = "dwc3-layerscape-wrapper",
|
||||
.id = UCLASS_NOP,
|
||||
.of_match = dwc3_layerscape_ids,
|
||||
.bind = dwc3_layerscape_bind,
|
||||
};
|
Loading…
Reference in a new issue