GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,65 @@
config USB_DWC3
bool "DesignWare USB3 DRD Core Support"
depends on USB_HOST || USB_GADGET
help
Say Y here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
if USB_DWC3
config USB_DWC3_GADGET
bool "USB Gadget support for DWC3"
default y
depends on USB_GADGET
select USB_GADGET_DUALSPEED
comment "Platform Glue Driver Support"
config USB_DWC3_OMAP
bool "Texas Instruments OMAP5 and similar Platforms"
help
Some platforms from Texas Instruments like OMAP5, DRA7xxx and
AM437x use this IP for USB2/3 functionality.
Say 'Y' here if you have one such device
config USB_DWC3_GENERIC
bool "Generic implementation of a DWC3 wrapper (aka dwc3 glue)"
depends on DM_USB && USB_DWC3 && MISC
help
Select this for Xilinx ZynqMP and similar Platforms.
This wrapper supports Host and Peripheral operation modes.
config USB_DWC3_MESON_G12A
bool "Amlogic Meson G12A USB wrapper"
depends on DM_USB && USB_DWC3 && ARCH_MESON
imply PHY
help
Select this for Amlogic Meson G12A Platforms.
This wrapper supports Host and Peripheral operation modes.
config USB_DWC3_UNIPHIER
bool "DesignWare USB3 Host Support on UniPhier Platforms"
depends on ARCH_UNIPHIER && USB_XHCI_DWC3
help
Support of USB2/3 functionality in Socionext UniPhier platforms.
Say 'Y' here if you have one such device.
menu "PHY Subsystem"
config USB_DWC3_PHY_OMAP
bool "TI OMAP SoC series USB DRD PHY driver"
help
Enable single driver for both USB2 PHY programming and USB3 PHY
programming for TI SoCs.
config USB_DWC3_PHY_SAMSUNG
bool "Exynos5 SoC series USB DRD PHY driver"
help
Enable USB DRD PHY support for Exynos 5 SoC series.
This driver provides PHY interface for USB 3.0 DRD controller
present on Exynos5 SoC series.
endmenu
endif
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
obj-$(CONFIG_USB_DWC3_GENERIC) += dwc3-generic.o
obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o
obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o
obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,441 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Generic DWC3 Glue layer
*
* Copyright (C) 2016 - 2018 Xilinx, Inc.
*
* Based on dwc3-omap.c.
*/
#include <common.h>
#include <cpu_func.h>
#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dwc3-uboot.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <malloc.h>
#include <usb.h>
#include "core.h"
#include "gadget.h"
#include <reset.h>
#include <clk.h>
#include <usb/xhci.h>
struct dwc3_generic_plat {
fdt_addr_t base;
u32 maximum_speed;
enum usb_dr_mode dr_mode;
};
struct dwc3_generic_priv {
void *base;
struct dwc3 dwc3;
struct phy *phys;
int num_phys;
};
struct dwc3_generic_host_priv {
struct xhci_ctrl xhci_ctrl;
struct dwc3_generic_priv gen_priv;
};
static int dwc3_generic_probe(struct udevice *dev,
struct dwc3_generic_priv *priv)
{
int rc;
struct dwc3_generic_plat *plat = dev_get_platdata(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);
#endif
rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
if (rc)
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_generic_remove(struct udevice *dev,
struct dwc3_generic_priv *priv)
{
struct dwc3 *dwc3 = &priv->dwc3;
dwc3_remove(dwc3);
dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
unmap_physmem(dwc3->regs, MAP_NOCACHE);
return 0;
}
static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
{
struct dwc3_generic_plat *plat = dev_get_platdata(dev);
int node = dev_of_offset(dev);
plat->base = devfdt_get_addr(dev);
plat->maximum_speed = usb_get_maximum_speed(node);
if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
pr_info("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) {
pr_err("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_generic_priv *priv = dev_get_priv(dev);
struct dwc3 *dwc3 = &priv->dwc3;
dwc3_gadget_uboot_handle_interrupt(dwc3);
return 0;
}
static int dwc3_generic_peripheral_probe(struct udevice *dev)
{
struct dwc3_generic_priv *priv = dev_get_priv(dev);
return dwc3_generic_probe(dev, priv);
}
static int dwc3_generic_peripheral_remove(struct udevice *dev)
{
struct dwc3_generic_priv *priv = dev_get_priv(dev);
return dwc3_generic_remove(dev, priv);
}
U_BOOT_DRIVER(dwc3_generic_peripheral) = {
.name = "dwc3-generic-peripheral",
.id = UCLASS_USB_GADGET_GENERIC,
.ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
.probe = dwc3_generic_peripheral_probe,
.remove = dwc3_generic_peripheral_remove,
.priv_auto_alloc_size = sizeof(struct dwc3_generic_priv),
.platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
};
#endif
#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
static int dwc3_generic_host_probe(struct udevice *dev)
{
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
int rc;
rc = dwc3_generic_probe(dev, &priv->gen_priv);
if (rc)
return rc;
hccr = (struct xhci_hccr *)priv->gen_priv.base;
hcor = (struct xhci_hcor *)(priv->gen_priv.base +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
return xhci_register(dev, hccr, hcor);
}
static int dwc3_generic_host_remove(struct udevice *dev)
{
struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
int rc;
rc = xhci_deregister(dev);
if (rc)
return rc;
return dwc3_generic_remove(dev, &priv->gen_priv);
}
U_BOOT_DRIVER(dwc3_generic_host) = {
.name = "dwc3-generic-host",
.id = UCLASS_USB,
.ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
.probe = dwc3_generic_host_probe,
.remove = dwc3_generic_host_remove,
.priv_auto_alloc_size = sizeof(struct dwc3_generic_host_priv),
.platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
.ops = &xhci_usb_ops,
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
#endif
struct dwc3_glue_data {
struct clk_bulk clks;
struct reset_ctl_bulk resets;
fdt_addr_t regs;
};
struct dwc3_glue_ops {
void (*select_dr_mode)(struct udevice *dev, int index,
enum usb_dr_mode mode);
};
void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
enum usb_dr_mode mode)
{
#define USBOTGSS_UTMI_OTG_STATUS 0x0084
#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
/* UTMI_OTG_STATUS REGISTER */
#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
#define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
#define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
enum dwc3_omap_utmi_mode {
DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
DWC3_OMAP_UTMI_MODE_HW,
DWC3_OMAP_UTMI_MODE_SW,
};
u32 use_id_pin;
u32 host_mode;
u32 reg;
u32 utmi_mode;
u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
struct dwc3_glue_data *glue = dev_get_platdata(dev);
void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
if (device_is_compatible(dev, "ti,am437x-dwc3"))
utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
utmi_mode = dev_read_u32_default(dev, "utmi-mode",
DWC3_OMAP_UTMI_MODE_UNKNOWN);
if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
dev->name);
mode = USB_DR_MODE_PERIPHERAL;
}
switch (mode) {
case USB_DR_MODE_PERIPHERAL:
use_id_pin = 0;
host_mode = 0;
break;
case USB_DR_MODE_HOST:
use_id_pin = 0;
host_mode = 1;
break;
case USB_DR_MODE_OTG:
default:
use_id_pin = 1;
host_mode = 0;
break;
}
reg = readl(base + utmi_status_offset);
reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
if (!use_id_pin)
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
writel(reg, base + utmi_status_offset);
reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
USBOTGSS_UTMI_OTG_STATUS_IDDIG);
reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
if (!host_mode)
reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
writel(reg, base + utmi_status_offset);
unmap_physmem(base, MAP_NOCACHE);
}
struct dwc3_glue_ops ti_ops = {
.select_dr_mode = dwc3_ti_select_dr_mode,
};
static int dwc3_glue_bind(struct udevice *parent)
{
const void *fdt = gd->fdt_blob;
int node;
int ret;
for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
node = fdt_next_subnode(fdt, node)) {
const char *name = fdt_get_name(fdt, node, NULL);
enum usb_dr_mode dr_mode;
struct udevice *dev;
const char *driver = NULL;
debug("%s: subnode name: %s\n", __func__, name);
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_SUPPORT) || !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;
ret = device_bind_driver_to_node(parent, driver, name,
offset_to_ofnode(node), &dev);
if (ret) {
debug("%s: not able to bind usb device mode\n",
__func__);
return ret;
}
}
return 0;
}
static int dwc3_glue_reset_init(struct udevice *dev,
struct dwc3_glue_data *glue)
{
int ret;
ret = reset_get_bulk(dev, &glue->resets);
if (ret == -ENOTSUPP || ret == -ENOENT)
return 0;
else if (ret)
return ret;
ret = reset_deassert_bulk(&glue->resets);
if (ret) {
reset_release_bulk(&glue->resets);
return ret;
}
return 0;
}
static int dwc3_glue_clk_init(struct udevice *dev,
struct dwc3_glue_data *glue)
{
int ret;
ret = clk_get_bulk(dev, &glue->clks);
if (ret == -ENOSYS || ret == -ENOENT)
return 0;
if (ret)
return ret;
#if CONFIG_IS_ENABLED(CLK)
ret = clk_enable_bulk(&glue->clks);
if (ret) {
clk_release_bulk(&glue->clks);
return ret;
}
#endif
return 0;
}
static int dwc3_glue_probe(struct udevice *dev)
{
struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
struct dwc3_glue_data *glue = dev_get_platdata(dev);
struct udevice *child = NULL;
int index = 0;
int ret;
glue->regs = dev_read_addr(dev);
ret = dwc3_glue_clk_init(dev, glue);
if (ret)
return ret;
ret = dwc3_glue_reset_init(dev, glue);
if (ret)
return ret;
ret = device_find_first_child(dev, &child);
if (ret)
return ret;
while (child) {
enum usb_dr_mode dr_mode;
dr_mode = usb_get_dr_mode(dev_of_offset(child));
device_find_next_child(&child);
if (ops && ops->select_dr_mode)
ops->select_dr_mode(dev, index, dr_mode);
index++;
}
return 0;
}
static int dwc3_glue_remove(struct udevice *dev)
{
struct dwc3_glue_data *glue = dev_get_platdata(dev);
reset_release_bulk(&glue->resets);
clk_release_bulk(&glue->clks);
return 0;
}
static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "ti,keystone-dwc3"},
{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
{ }
};
U_BOOT_DRIVER(dwc3_generic_wrapper) = {
.name = "dwc3-generic-wrapper",
.id = UCLASS_NOP,
.of_match = dwc3_glue_ids,
.bind = dwc3_glue_bind,
.probe = dwc3_glue_probe,
.remove = dwc3_glue_remove,
.platdata_auto_alloc_size = sizeof(struct dwc3_glue_data),
};
@@ -0,0 +1,456 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Amlogic G12A DWC3 Glue layer
*
* Copyright (C) 2019 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*/
#include <common.h>
#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dwc3-uboot.h>
#include <generic-phy.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <malloc.h>
#include <regmap.h>
#include <usb.h>
#include "core.h"
#include "gadget.h"
#include <reset.h>
#include <clk.h>
#include <power/regulator.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/compat.h>
/* USB2 Ports Control Registers */
#define U2P_REG_SIZE 0x20
#define U2P_R0 0x0
#define U2P_R0_HOST_DEVICE BIT(0)
#define U2P_R0_POWER_OK BIT(1)
#define U2P_R0_HAST_MODE BIT(2)
#define U2P_R0_POWER_ON_RESET BIT(3)
#define U2P_R0_ID_PULLUP BIT(4)
#define U2P_R0_DRV_VBUS BIT(5)
#define U2P_R1 0x4
#define U2P_R1_PHY_READY BIT(0)
#define U2P_R1_ID_DIG BIT(1)
#define U2P_R1_OTG_SESSION_VALID BIT(2)
#define U2P_R1_VBUS_VALID BIT(3)
/* USB Glue Control Registers */
#define USB_R0 0x80
#define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
#define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
#define USB_R0_U2D_ACT BIT(31)
#define USB_R1 0x84
#define USB_R1_U3H_BIGENDIAN_GS BIT(0)
#define USB_R1_U3H_PME_ENABLE BIT(1)
#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2)
#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7)
#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12)
#define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
#define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
#define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
#define USB_R2 0x88
#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
#define USB_R3 0x8c
#define USB_R3_P30_SSC_ENABLE BIT(0)
#define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
#define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
#define USB_R3_P30_REF_SSP_EN BIT(13)
#define USB_R4 0x90
#define USB_R4_P21_PORT_RESET_0 BIT(0)
#define USB_R4_P21_SLEEP_M0 BIT(1)
#define USB_R4_MEM_PD_MASK GENMASK(3, 2)
#define USB_R4_P21_ONLY BIT(4)
#define USB_R5 0x94
#define USB_R5_ID_DIG_SYNC BIT(0)
#define USB_R5_ID_DIG_REG BIT(1)
#define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
#define USB_R5_ID_DIG_EN_0 BIT(4)
#define USB_R5_ID_DIG_EN_1 BIT(5)
#define USB_R5_ID_DIG_CURR BIT(6)
#define USB_R5_ID_DIG_IRQ BIT(7)
#define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
#define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
enum {
USB2_HOST_PHY = 0,
USB2_OTG_PHY,
USB3_HOST_PHY,
PHY_COUNT,
};
static const char *phy_names[PHY_COUNT] = {
"usb2-phy0", "usb2-phy1", "usb3-phy0",
};
struct dwc3_meson_g12a {
struct udevice *dev;
struct regmap *regmap;
struct clk clk;
struct reset_ctl reset;
struct phy phys[PHY_COUNT];
enum usb_dr_mode otg_mode;
enum usb_dr_mode otg_phy_mode;
unsigned int usb2_ports;
unsigned int usb3_ports;
#if CONFIG_IS_ENABLED(DM_REGULATOR)
struct udevice *vbus_supply;
#endif
};
#define U2P_REG_SIZE 0x20
#define USB_REG_OFFSET 0x80
static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
int i, enum usb_dr_mode mode)
{
switch (mode) {
case USB_DR_MODE_HOST:
case USB_DR_MODE_OTG:
case USB_DR_MODE_UNKNOWN:
regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
U2P_R0_HOST_DEVICE,
U2P_R0_HOST_DEVICE);
break;
case USB_DR_MODE_PERIPHERAL:
regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
U2P_R0_HOST_DEVICE, 0);
break;
}
}
static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
{
int i;
if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
priv->otg_phy_mode = USB_DR_MODE_PERIPHERAL;
else
priv->otg_phy_mode = USB_DR_MODE_HOST;
for (i = 0 ; i < USB3_HOST_PHY ; ++i) {
if (!priv->phys[i].dev)
continue;
regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
U2P_R0_POWER_ON_RESET,
U2P_R0_POWER_ON_RESET);
if (i == USB2_OTG_PHY) {
regmap_update_bits(priv->regmap,
U2P_R0 + (U2P_REG_SIZE * i),
U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
dwc3_meson_g12a_usb2_set_mode(priv, i,
priv->otg_phy_mode);
} else
dwc3_meson_g12a_usb2_set_mode(priv, i,
USB_DR_MODE_HOST);
regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i),
U2P_R0_POWER_ON_RESET, 0);
}
return 0;
}
static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
{
regmap_update_bits(priv->regmap, USB_R3,
USB_R3_P30_SSC_RANGE_MASK |
USB_R3_P30_REF_SSP_EN,
USB_R3_P30_SSC_ENABLE |
FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
USB_R3_P30_REF_SSP_EN);
udelay(2);
regmap_update_bits(priv->regmap, USB_R2,
USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
regmap_update_bits(priv->regmap, USB_R2,
USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
udelay(2);
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_P30_PCS_TX_SWING_FULL_MASK,
FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
}
static void dwc3_meson_g12a_usb_init_mode(struct dwc3_meson_g12a *priv)
{
if (priv->otg_phy_mode == USB_DR_MODE_PERIPHERAL) {
regmap_update_bits(priv->regmap, USB_R0,
USB_R0_U2D_ACT, USB_R0_U2D_ACT);
regmap_update_bits(priv->regmap, USB_R0,
USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
regmap_update_bits(priv->regmap, USB_R4,
USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
} else {
regmap_update_bits(priv->regmap, USB_R0,
USB_R0_U2D_ACT, 0);
regmap_update_bits(priv->regmap, USB_R4,
USB_R4_P21_SLEEP_M0, 0);
}
}
static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
{
int ret;
ret = dwc3_meson_g12a_usb2_init(priv);
if (ret)
return ret;
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
regmap_update_bits(priv->regmap, USB_R5,
USB_R5_ID_DIG_EN_0,
USB_R5_ID_DIG_EN_0);
regmap_update_bits(priv->regmap, USB_R5,
USB_R5_ID_DIG_EN_1,
USB_R5_ID_DIG_EN_1);
regmap_update_bits(priv->regmap, USB_R5,
USB_R5_ID_DIG_TH_MASK,
FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
/* If we have an actual SuperSpeed port, initialize it */
if (priv->usb3_ports)
dwc3_meson_g12a_usb3_init(priv);
dwc3_meson_g12a_usb_init_mode(priv);
return 0;
}
int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
{
struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
if (!priv)
return -EINVAL;
if (mode != USB_DR_MODE_HOST && mode != USB_DR_MODE_PERIPHERAL)
return -EINVAL;
if (!priv->phys[USB2_OTG_PHY].dev)
return -EINVAL;
if (mode == priv->otg_mode)
return 0;
if (mode == USB_DR_MODE_HOST)
debug("%s: switching to Host Mode\n", __func__);
else
debug("%s: switching to Device Mode\n", __func__);
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply) {
int ret = regulator_set_enable(priv->vbus_supply,
(mode == USB_DR_MODE_PERIPHERAL));
if (ret)
return ret;
}
#endif
priv->otg_phy_mode = mode;
dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode);
dwc3_meson_g12a_usb_init_mode(priv);
return 0;
}
static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
{
int i, ret;
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = generic_phy_get_by_name(priv->dev, phy_names[i],
&priv->phys[i]);
if (ret == -ENOENT)
continue;
if (ret)
return ret;
if (i == USB3_HOST_PHY)
priv->usb3_ports++;
else
priv->usb2_ports++;
}
debug("%s: usb2 ports: %d\n", __func__, priv->usb2_ports);
debug("%s: usb3 ports: %d\n", __func__, priv->usb3_ports);
return 0;
}
static int dwc3_meson_g12a_reset_init(struct dwc3_meson_g12a *priv)
{
int ret;
ret = reset_get_by_index(priv->dev, 0, &priv->reset);
if (ret)
return ret;
ret = reset_assert(&priv->reset);
udelay(1);
ret |= reset_deassert(&priv->reset);
if (ret) {
reset_free(&priv->reset);
return ret;
}
return 0;
}
static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
{
int ret;
ret = clk_get_by_index(priv->dev, 0, &priv->clk);
if (ret)
return ret;
#if CONFIG_IS_ENABLED(CLK)
ret = clk_enable(&priv->clk);
if (ret) {
clk_free(&priv->clk);
return ret;
}
#endif
return 0;
}
static int dwc3_meson_g12a_probe(struct udevice *dev)
{
struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
int ret, i;
priv->dev = dev;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
if (ret)
return ret;
ret = dwc3_meson_g12a_clk_init(priv);
if (ret)
return ret;
ret = dwc3_meson_g12a_reset_init(priv);
if (ret)
return ret;
ret = dwc3_meson_g12a_get_phys(priv);
if (ret)
return ret;
#if CONFIG_IS_ENABLED(DM_REGULATOR)
ret = device_get_supply_regulator(dev, "vbus-supply",
&priv->vbus_supply);
if (ret && ret != -ENOENT) {
pr_err("Failed to get PHY regulator\n");
return ret;
}
if (priv->vbus_supply) {
ret = regulator_set_enable(priv->vbus_supply, true);
if (ret)
return ret;
}
#endif
priv->otg_mode = usb_get_dr_mode(dev_of_offset(dev));
ret = dwc3_meson_g12a_usb_init(priv);
if (ret)
return ret;
for (i = 0 ; i < PHY_COUNT ; ++i) {
if (!priv->phys[i].dev)
continue;
ret = generic_phy_init(&priv->phys[i]);
if (ret)
goto err_phy_init;
}
return 0;
err_phy_init:
for (i = 0 ; i < PHY_COUNT ; ++i) {
if (!priv->phys[i].dev)
continue;
generic_phy_exit(&priv->phys[i]);
}
return ret;
}
static int dwc3_meson_g12a_remove(struct udevice *dev)
{
struct dwc3_meson_g12a *priv = dev_get_platdata(dev);
int i;
reset_release_all(&priv->reset, 1);
clk_release_all(&priv->clk, 1);
for (i = 0 ; i < PHY_COUNT ; ++i) {
if (!priv->phys[i].dev)
continue;
generic_phy_exit(&priv->phys[i]);
}
return dm_scan_fdt_dev(dev);
}
static const struct udevice_id dwc3_meson_g12a_ids[] = {
{ .compatible = "amlogic,meson-g12a-usb-ctrl" },
{ }
};
U_BOOT_DRIVER(dwc3_generic_wrapper) = {
.name = "dwc3-meson-g12a",
.id = UCLASS_SIMPLE_BUS,
.of_match = dwc3_meson_g12a_ids,
.probe = dwc3_meson_g12a_probe,
.remove = dwc3_meson_g12a_remove,
.platdata_auto_alloc_size = sizeof(struct dwc3_meson_g12a),
};
@@ -0,0 +1,451 @@
// SPDX-License-Identifier: GPL-2.0
/**
* dwc3-omap.c - OMAP Specific Glue layer
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/dwc3-omap.c) and ported
* to uboot.
*
* commit 7ee2566ff5 : usb: dwc3: dwc3-omap: get rid of ->prepare()/->complete()
*/
#include <common.h>
#include <malloc.h>
#include <asm/io.h>
#include <dm.h>
#include <dwc3-omap-uboot.h>
#include <linux/usb/dwc3-omap.h>
#include <linux/ioport.h>
#include <linux/usb/otg.h>
#include <linux/compat.h>
#include "linux-compat.h"
/*
* All these registers belong to OMAP's Wrapper around the
* DesignWare USB3 Core.
*/
#define USBOTGSS_REVISION 0x0000
#define USBOTGSS_SYSCONFIG 0x0010
#define USBOTGSS_IRQ_EOI 0x0020
#define USBOTGSS_EOI_OFFSET 0x0008
#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
#define USBOTGSS_IRQSTATUS_0 0x0028
#define USBOTGSS_IRQENABLE_SET_0 0x002c
#define USBOTGSS_IRQENABLE_CLR_0 0x0030
#define USBOTGSS_IRQ0_OFFSET 0x0004
#define USBOTGSS_IRQSTATUS_RAW_1 0x0030
#define USBOTGSS_IRQSTATUS_1 0x0034
#define USBOTGSS_IRQENABLE_SET_1 0x0038
#define USBOTGSS_IRQENABLE_CLR_1 0x003c
#define USBOTGSS_IRQSTATUS_RAW_2 0x0040
#define USBOTGSS_IRQSTATUS_2 0x0044
#define USBOTGSS_IRQENABLE_SET_2 0x0048
#define USBOTGSS_IRQENABLE_CLR_2 0x004c
#define USBOTGSS_IRQSTATUS_RAW_3 0x0050
#define USBOTGSS_IRQSTATUS_3 0x0054
#define USBOTGSS_IRQENABLE_SET_3 0x0058
#define USBOTGSS_IRQENABLE_CLR_3 0x005c
#define USBOTGSS_IRQSTATUS_EOI_MISC 0x0030
#define USBOTGSS_IRQSTATUS_RAW_MISC 0x0034
#define USBOTGSS_IRQSTATUS_MISC 0x0038
#define USBOTGSS_IRQENABLE_SET_MISC 0x003c
#define USBOTGSS_IRQENABLE_CLR_MISC 0x0040
#define USBOTGSS_IRQMISC_OFFSET 0x03fc
#define USBOTGSS_UTMI_OTG_CTRL 0x0080
#define USBOTGSS_UTMI_OTG_STATUS 0x0084
#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
#define USBOTGSS_TXFIFO_DEPTH 0x0508
#define USBOTGSS_RXFIFO_DEPTH 0x050c
#define USBOTGSS_MMRAM_OFFSET 0x0100
#define USBOTGSS_FLADJ 0x0104
#define USBOTGSS_DEBUG_CFG 0x0108
#define USBOTGSS_DEBUG_DATA 0x010c
#define USBOTGSS_DEV_EBC_EN 0x0110
#define USBOTGSS_DEBUG_OFFSET 0x0600
/* SYSCONFIG REGISTER */
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
/* IRQ_EOI REGISTER */
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
/* IRQS0 BITS */
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
/* IRQMISC BITS */
#define USBOTGSS_IRQMISC_DMADISABLECLR (1 << 17)
#define USBOTGSS_IRQMISC_OEVT (1 << 16)
#define USBOTGSS_IRQMISC_DRVVBUS_RISE (1 << 13)
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE (1 << 12)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE (1 << 11)
#define USBOTGSS_IRQMISC_IDPULLUP_RISE (1 << 8)
#define USBOTGSS_IRQMISC_DRVVBUS_FALL (1 << 5)
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL (1 << 4)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3)
#define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0)
#define USBOTGSS_INTERRUPTS (USBOTGSS_IRQMISC_OEVT | \
USBOTGSS_IRQMISC_DRVVBUS_RISE | \
USBOTGSS_IRQMISC_CHRGVBUS_RISE | \
USBOTGSS_IRQMISC_DISCHRGVBUS_RISE | \
USBOTGSS_IRQMISC_IDPULLUP_RISE | \
USBOTGSS_IRQMISC_DRVVBUS_FALL | \
USBOTGSS_IRQMISC_CHRGVBUS_FALL | \
USBOTGSS_IRQMISC_DISCHRGVBUS_FALL | \
USBOTGSS_IRQMISC_IDPULLUP_FALL)
/* UTMI_OTG_CTRL REGISTER */
#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4)
#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3)
#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0)
/* UTMI_OTG_STATUS REGISTER */
#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31)
#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9)
#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4)
#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3)
#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2)
#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
struct dwc3_omap {
struct device *dev;
void __iomem *base;
u32 utmi_otg_status;
u32 utmi_otg_offset;
u32 irqmisc_offset;
u32 irq_eoi_offset;
u32 debug_offset;
u32 irq0_offset;
u32 dma_status:1;
struct list_head list;
u32 index;
};
static LIST_HEAD(dwc3_omap_list);
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
return readl(base + offset);
}
static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
{
writel(value, base + offset);
}
static u32 dwc3_omap_read_utmi_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS +
omap->utmi_otg_offset);
}
static void dwc3_omap_write_utmi_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS +
omap->utmi_otg_offset, value);
}
static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 -
omap->irq0_offset);
}
static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0 -
omap->irq0_offset, value);
}
static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC +
omap->irqmisc_offset);
}
static void dwc3_omap_write_irqmisc_status(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_MISC +
omap->irqmisc_offset, value);
}
static void dwc3_omap_write_irqmisc_set(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_MISC +
omap->irqmisc_offset, value);
}
static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0 -
omap->irq0_offset, value);
}
static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC +
omap->irqmisc_offset, value);
}
static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value)
{
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 -
omap->irq0_offset, value);
}
static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
enum omap_dwc3_vbus_id_status status)
{
u32 val;
switch (status) {
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_SESSEND);
val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
dwc3_omap_write_utmi_status(omap, val);
break;
case OMAP_DWC3_VBUS_VALID:
dev_dbg(omap->dev, "VBUS Connect\n");
val = dwc3_omap_read_utmi_status(omap);
val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
dwc3_omap_write_utmi_status(omap, val);
break;
case OMAP_DWC3_ID_FLOAT:
case OMAP_DWC3_VBUS_OFF:
dev_dbg(omap->dev, "VBUS Disconnect\n");
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
| USBOTGSS_UTMI_OTG_STATUS_IDDIG;
dwc3_omap_write_utmi_status(omap, val);
break;
default:
dev_dbg(omap->dev, "invalid state\n");
}
}
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
u32 reg;
reg = dwc3_omap_read_irqmisc_status(omap);
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
omap->dma_status = false;
}
if (reg & USBOTGSS_IRQMISC_OEVT)
dev_dbg(omap->dev, "OTG Event\n");
if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE)
dev_dbg(omap->dev, "DRVVBUS Rise\n");
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE)
dev_dbg(omap->dev, "CHRGVBUS Rise\n");
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE)
dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE)
dev_dbg(omap->dev, "IDPULLUP Rise\n");
if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL)
dev_dbg(omap->dev, "DRVVBUS Fall\n");
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL)
dev_dbg(omap->dev, "CHRGVBUS Fall\n");
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL)
dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
dwc3_omap_write_irqmisc_status(omap, reg);
reg = dwc3_omap_read_irq0_status(omap);
dwc3_omap_write_irq0_status(omap, reg);
return IRQ_HANDLED;
}
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{
/* enable all IRQs */
dwc3_omap_write_irq0_set(omap, USBOTGSS_IRQO_COREIRQ_ST);
dwc3_omap_write_irqmisc_set(omap, USBOTGSS_INTERRUPTS);
}
static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
{
/* disable all IRQs */
dwc3_omap_write_irq0_clr(omap, USBOTGSS_IRQO_COREIRQ_ST);
dwc3_omap_write_irqmisc_clr(omap, USBOTGSS_INTERRUPTS);
}
static void dwc3_omap_map_offset(struct dwc3_omap *omap)
{
/*
* Differentiate between OMAP5 and AM437x.
*
* For OMAP5(ES2.0) and AM437x wrapper revision is same, even
* though there are changes in wrapper register offsets.
*
* Using dt compatible to differentiate AM437x.
*/
#ifdef CONFIG_AM43XX
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
#endif
}
static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap, int utmi_mode)
{
u32 reg;
reg = dwc3_omap_read_utmi_status(omap);
switch (utmi_mode) {
case DWC3_OMAP_UTMI_MODE_SW:
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
case DWC3_OMAP_UTMI_MODE_HW:
reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
break;
default:
dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
}
dwc3_omap_write_utmi_status(omap, reg);
}
/**
* dwc3_omap_uboot_init - dwc3 omap uboot initialization code
* @dev: struct dwc3_omap_device containing initialization data
*
* Entry point for dwc3 omap driver (equivalent to dwc3_omap_probe in linux
* kernel driver). Pointer to dwc3_omap_device should be passed containing
* base address and other initialization data. Returns '0' on success and
* a negative value on failure.
*
* Generally called from board_usb_init() implemented in board file.
*/
int dwc3_omap_uboot_init(struct dwc3_omap_device *omap_dev)
{
u32 reg;
struct device *dev = NULL;
struct dwc3_omap *omap;
omap = devm_kzalloc((struct udevice *)dev, sizeof(*omap), GFP_KERNEL);
if (!omap)
return -ENOMEM;
omap->base = omap_dev->base;
omap->index = omap_dev->index;
dwc3_omap_map_offset(omap);
dwc3_omap_set_utmi_mode(omap, omap_dev->utmi_mode);
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
dwc3_omap_set_mailbox(omap, omap_dev->vbus_id_status);
dwc3_omap_enable_irqs(omap);
list_add_tail(&omap->list, &dwc3_omap_list);
return 0;
}
/**
* dwc3_omap_uboot_exit - dwc3 omap uboot cleanup code
* @index: index of this controller
*
* Performs cleanup of memory allocated in dwc3_omap_uboot_init
* (equivalent to dwc3_omap_remove in linux). index of _this_ controller
* should be passed and should match with the index passed in
* dwc3_omap_device during init.
*
* Generally called from board file.
*/
void dwc3_omap_uboot_exit(int index)
{
struct dwc3_omap *omap = NULL;
list_for_each_entry(omap, &dwc3_omap_list, list) {
if (omap->index != index)
continue;
dwc3_omap_disable_irqs(omap);
list_del(&omap->list);
kfree(omap);
break;
}
}
/**
* dwc3_omap_uboot_interrupt_status - check the status of interrupt
* @index: index of this controller
*
* Checks the status of interrupts and returns true if an interrupt
* is detected or false otherwise.
*
* Generally called from board file.
*/
int dwc3_omap_uboot_interrupt_status(int index)
{
struct dwc3_omap *omap = NULL;
list_for_each_entry(omap, &dwc3_omap_list, list)
if (omap->index == index)
return dwc3_omap_interrupt(-1, omap);
return 0;
}
MODULE_ALIAS("platform:omap-dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* UniPhier Specific Glue Layer for DWC3
*
* Copyright (C) 2016-2017 Socionext Inc.
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <dm.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/sizes.h>
#define UNIPHIER_PRO4_DWC3_RESET 0x40
#define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5)
#define UNIPHIER_PRO4_DWC3_RESET_XLINK BIT(4)
#define UNIPHIER_PRO4_DWC3_RESET_PHY_SS BIT(2)
#define UNIPHIER_PRO5_DWC3_RESET 0x00
#define UNIPHIER_PRO5_DWC3_RESET_PHY_S1 BIT(17)
#define UNIPHIER_PRO5_DWC3_RESET_PHY_S0 BIT(16)
#define UNIPHIER_PRO5_DWC3_RESET_XLINK BIT(15)
#define UNIPHIER_PRO5_DWC3_RESET_XIOMMU BIT(14)
#define UNIPHIER_PXS2_DWC3_RESET 0x00
#define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15)
static int uniphier_pro4_dwc3_init(void __iomem *regs)
{
u32 tmp;
tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS;
tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
return 0;
}
static int uniphier_pro5_dwc3_init(void __iomem *regs)
{
u32 tmp;
tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 |
UNIPHIER_PRO5_DWC3_RESET_PHY_S0);
tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
return 0;
}
static int uniphier_pxs2_dwc3_init(void __iomem *regs)
{
u32 tmp;
tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
return 0;
}
static int uniphier_dwc3_probe(struct udevice *dev)
{
fdt_addr_t base;
void __iomem *regs;
int (*init)(void __iomem *regs);
int ret;
base = devfdt_get_addr(dev);
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
regs = ioremap(base, SZ_32K);
if (!regs)
return -ENOMEM;
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[] = {
{
.compatible = "socionext,uniphier-pro4-dwc3",
.data = (ulong)uniphier_pro4_dwc3_init,
},
{
.compatible = "socionext,uniphier-pro5-dwc3",
.data = (ulong)uniphier_pro5_dwc3_init,
},
{
.compatible = "socionext,uniphier-pxs2-dwc3",
.data = (ulong)uniphier_pxs2_dwc3_init,
},
{
.compatible = "socionext,uniphier-ld20-dwc3",
.data = (ulong)uniphier_pxs2_dwc3_init,
},
{
.compatible = "socionext,uniphier-pxs3-dwc3",
.data = (ulong)uniphier_pxs2_dwc3_init,
},
{ /* sentinel */ }
};
U_BOOT_DRIVER(usb_xhci) = {
.name = "uniphier-dwc3",
.id = UCLASS_SIMPLE_BUS,
.of_match = uniphier_dwc3_match,
.probe = uniphier_dwc3_probe,
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
* gadget.h - DesignWare USB3 DRD Gadget Header
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/gadget.h) and ported
* to uboot.
*
* commit 7a60855972 : usb: dwc3: gadget: fix set_halt() bug with pending
transfers
*
*/
#ifndef __DRIVERS_USB_DWC3_GADGET_H
#define __DRIVERS_USB_DWC3_GADGET_H
#include <linux/list.h>
#include <linux/usb/gadget.h>
#include "io.h"
struct dwc3;
#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
/* DEPCFG parameter 1 */
#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
/* DEPCFG parameter 0 */
#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
/* This applies for core versions earlier than 1.94a */
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
/* These apply for core versions 1.94a and later */
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30)
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
/* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
static inline struct dwc3_request *next_request(struct list_head *list)
{
if (list_empty(list))
return NULL;
return list_first_entry(list, struct dwc3_request, list);
}
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
{
struct dwc3_ep *dep = req->dep;
req->queued = true;
list_move_tail(&req->list, &dep->req_queued);
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
* @dwc: DesignWare USB3 Pointer
* @number: DWC endpoint number
*
* Caller should take care of locking
*/
static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
{
u32 res_id;
res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
return DWC3_DEPCMD_GET_RSC_IDX(res_id);
}
#endif /* __DRIVERS_USB_DWC3_GADGET_H */
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
* io.h - DesignWare USB3 DRD IO Header
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/io.h) and ported
* to uboot.
*
* commit 2c4cbe6e5a : usb: dwc3: add tracepoints to aid debugging
*
*/
#ifndef __DRIVERS_USB_DWC3_IO_H
#define __DRIVERS_USB_DWC3_IO_H
#include <cpu_func.h>
#include <asm/io.h>
#define CACHELINE_SIZE CONFIG_SYS_CACHELINE_SIZE
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
u32 value;
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
value = readl(base + offs);
return value;
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
unsigned long offs = offset - DWC3_GLOBALS_REGS_START;
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
writel(value, base + offs);
}
static inline void dwc3_flush_cache(uintptr_t addr, int length)
{
flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
* linux-compat.h - DesignWare USB3 Linux Compatibiltiy Adapter Header
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Kishon Vijay Abraham I <kishon@ti.com>
*
*/
#ifndef __DWC3_LINUX_COMPAT__
#define __DWC3_LINUX_COMPAT__
#define dev_WARN(dev, format, arg...) debug(format, ##arg)
static inline size_t strlcat(char *dest, const char *src, size_t n)
{
strcat(dest, src);
return strlen(dest) + strlen(src);
}
#endif
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-2.0
/**
* samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file
*
* Copyright (C) 2015 Samsung Electronics
*
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*/
#include <common.h>
#include <asm/arch/power.h>
#include <asm/arch/xhci-exynos.h>
void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy)
{
u32 reg;
/* Reset USB 3.0 PHY */
writel(0x0, &phy->phy_reg0);
clrbits_le32(&phy->phy_param0,
/* Select PHY CLK source */
PHYPARAM0_REF_USE_PAD |
/* Set Loss-of-Signal Detector sensitivity */
PHYPARAM0_REF_LOSLEVEL_MASK);
setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL);
writel(0x0, &phy->phy_resume);
/*
* Setting the Frame length Adj value[6:1] to default 0x20
* See xHCI 1.0 spec, 5.2.4
*/
setbits_le32(&phy->link_system,
LINKSYSTEM_XHCI_VERSION_CONTROL |
LINKSYSTEM_FLADJ(0x20));
/* Set Tx De-Emphasis level */
clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK);
setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH);
setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL);
/* PHYTEST POWERDOWN Control */
clrbits_le32(&phy->phy_test,
PHYTEST_POWERDOWN_SSP |
PHYTEST_POWERDOWN_HSP);
/* UTMI Power Control */
writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi);
/* Use core clock from main PLL */
reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
/* Default 24Mhz crystal clock */
PHYCLKRST_FSEL(FSEL_CLKSEL_24M) |
PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
PHYCLKRST_SSC_REFCLKSEL(0) |
/* Force PortReset of PHY */
PHYCLKRST_PORTRESET |
/* Digital power supply in normal operating mode */
PHYCLKRST_RETENABLEN |
/* Enable ref clock for SS function */
PHYCLKRST_REF_SSP_EN |
/* Enable spread spectrum */
PHYCLKRST_SSC_EN |
/* Power down HS Bias and PLL blocks in suspend mode */
PHYCLKRST_COMMONONN;
writel(reg, &phy->phy_clk_rst);
/* giving time to Phy clock to settle before resetting */
udelay(10);
reg &= ~PHYCLKRST_PORTRESET;
writel(reg, &phy->phy_clk_rst);
}
@@ -0,0 +1,315 @@
// SPDX-License-Identifier: GPL-2.0+
/**
* ti_usb_phy.c - USB3 and USB3 PHY programming for dwc3
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*
* Taken from Linux Kernel v3.16 (drivers/phy/phy-ti-pipe3.c and
* drivers/phy/phy-omap-usb2.c) and ported to uboot.
*
* "commit 56042e : phy: ti-pipe3: Fix suspend/resume and module reload" for
* phy-ti-pipe3.c
*
* "commit eb82a3 : phy: omap-usb2: Balance pm_runtime_enable() on probe failure
* and remove" for phy-omap-usb2.c
*/
#include <common.h>
#include <malloc.h>
#include <ti-usb-phy-uboot.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/arch/sys_proto.h>
#include <dm.h>
#include "linux-compat.h"
#define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008
#define PLL_CONFIGURATION1 0x0000000C
#define PLL_CONFIGURATION2 0x00000010
#define PLL_CONFIGURATION3 0x00000014
#define PLL_CONFIGURATION4 0x00000020
#define PLL_REGM_MASK 0x001FFE00
#define PLL_REGM_SHIFT 0x9
#define PLL_REGM_F_MASK 0x0003FFFF
#define PLL_REGM_F_SHIFT 0x0
#define PLL_REGN_MASK 0x000001FE
#define PLL_REGN_SHIFT 0x1
#define PLL_SELFREQDCO_MASK 0x0000000E
#define PLL_SELFREQDCO_SHIFT 0x1
#define PLL_SD_MASK 0x0003FC00
#define PLL_SD_SHIFT 10
#define SET_PLL_GO 0x1
#define PLL_LDOPWDN BIT(15)
#define PLL_TICOPWDN BIT(16)
#define PLL_LOCK 0x2
#define PLL_IDLE 0x1
#define OMAP_CTRL_DEV_PHY_PD BIT(0)
#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000
#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT 0xE
#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000
#define OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_SHIFT 0x16
#define OMAP_CTRL_USB3_PHY_TX_RX_POWERON 0x3
#define OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF 0x0
#define OMAP_CTRL_USB2_PHY_PD BIT(28)
#define AM437X_CTRL_USB2_PHY_PD BIT(0)
#define AM437X_CTRL_USB2_OTG_PD BIT(1)
#define AM437X_CTRL_USB2_OTGVDET_EN BIT(19)
#define AM437X_CTRL_USB2_OTGSESSEND_EN BIT(20)
static LIST_HEAD(ti_usb_phy_list);
typedef unsigned int u32;
struct usb3_dpll_params {
u16 m;
u8 n;
u8 freq:3;
u8 sd;
u32 mf;
};
struct usb3_dpll_map {
unsigned long rate;
struct usb3_dpll_params params;
struct usb3_dpll_map *dpll_map;
};
struct ti_usb_phy {
void __iomem *pll_ctrl_base;
void __iomem *usb2_phy_power;
void __iomem *usb3_phy_power;
struct usb3_dpll_map *dpll_map;
struct list_head list;
int index;
};
static struct usb3_dpll_map dpll_map_usb[] = {
{12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
{16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
{19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
{20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
{26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
{38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
{ }, /* Terminator */
};
static inline unsigned int ti_usb3_readl(void __iomem *base, u32 offset)
{
return readl(base + offset);
}
static inline void ti_usb3_writel(void __iomem *base, u32 offset, u32 value)
{
writel(value, base + offset);
}
#ifndef CONFIG_AM43XX
static struct usb3_dpll_params *ti_usb3_get_dpll_params(struct ti_usb_phy *phy)
{
unsigned long rate;
struct usb3_dpll_map *dpll_map = phy->dpll_map;
rate = get_sys_clk_freq();
for (; dpll_map->rate; dpll_map++) {
if (rate == dpll_map->rate)
return &dpll_map->params;
}
dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
return NULL;
}
static int ti_usb3_dpll_wait_lock(struct ti_usb_phy *phy)
{
u32 val;
do {
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_STATUS);
if (val & PLL_LOCK)
break;
} while (1);
return 0;
}
static int ti_usb3_dpll_program(struct ti_usb_phy *phy)
{
u32 val;
struct usb3_dpll_params *dpll_params;
if (!phy->pll_ctrl_base)
return -EINVAL;
dpll_params = ti_usb3_get_dpll_params(phy);
if (!dpll_params)
return -EINVAL;
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGN_MASK;
val |= dpll_params->n << PLL_REGN_SHIFT;
ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
val &= ~PLL_SELFREQDCO_MASK;
val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGM_MASK;
val |= dpll_params->m << PLL_REGM_SHIFT;
ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
val &= ~PLL_REGM_F_MASK;
val |= dpll_params->mf << PLL_REGM_F_SHIFT;
ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
val = ti_usb3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
val &= ~PLL_SD_MASK;
val |= dpll_params->sd << PLL_SD_SHIFT;
ti_usb3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
ti_usb3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
return ti_usb3_dpll_wait_lock(phy);
}
#endif
void ti_usb2_phy_power(struct ti_usb_phy *phy, int on)
{
u32 val;
val = readl(phy->usb2_phy_power);
if (on) {
#if defined(CONFIG_DRA7XX)
if (phy->index == 1)
val &= ~OMAP_CTRL_USB2_PHY_PD;
else
val &= ~OMAP_CTRL_DEV_PHY_PD;
#elif defined(CONFIG_AM43XX)
val &= ~(AM437X_CTRL_USB2_PHY_PD |
AM437X_CTRL_USB2_OTG_PD);
val |= (AM437X_CTRL_USB2_OTGVDET_EN |
AM437X_CTRL_USB2_OTGSESSEND_EN);
#endif
} else {
#if defined(CONFIG_DRA7XX)
if (phy->index == 1)
val |= OMAP_CTRL_USB2_PHY_PD;
else
val |= OMAP_CTRL_DEV_PHY_PD;
#elif defined(CONFIG_AM43XX)
val &= ~(AM437X_CTRL_USB2_OTGVDET_EN |
AM437X_CTRL_USB2_OTGSESSEND_EN);
val |= (AM437X_CTRL_USB2_PHY_PD |
AM437X_CTRL_USB2_OTG_PD);
#endif
}
writel(val, phy->usb2_phy_power);
}
#ifndef CONFIG_AM43XX
void ti_usb3_phy_power(struct ti_usb_phy *phy, int on)
{
u32 val;
u32 rate;
rate = get_sys_clk_freq();
rate = rate/1000000;
if (!phy->usb3_phy_power)
return;
val = readl(phy->usb3_phy_power);
if (on) {
val &= ~(OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK |
OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_MASK);
val |= (OMAP_CTRL_USB3_PHY_TX_RX_POWERON) <<
OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT;
val |= rate <<
OMAP_CTRL_USB3_PHY_PWRCTL_CLK_FREQ_SHIFT;
} else {
val &= ~OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_MASK;
val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
OMAP_CTRL_USB3_PHY_PWRCTL_CLK_CMD_SHIFT;
}
writel(val, phy->usb3_phy_power);
}
#endif
/**
* ti_usb_phy_uboot_init - usb phy uboot initialization code
* @dev: struct ti_usb_phy_device containing initialization data
*
* Entry point for ti usb phy driver. This driver handles initialization
* of both usb2 phy and usb3 phy. Pointer to ti_usb_phy_device should be
* passed containing base address and other initialization data.
* Returns '0' on success and a negative value on failure.
*
* Generally called from board_usb_init() implemented in board file.
*/
int ti_usb_phy_uboot_init(struct ti_usb_phy_device *dev)
{
struct ti_usb_phy *phy;
phy = devm_kzalloc(NULL, sizeof(*phy), GFP_KERNEL);
if (!phy) {
dev_err(NULL, "unable to alloc mem for TI USB3 PHY\n");
return -ENOMEM;
}
phy->dpll_map = dpll_map_usb;
phy->index = dev->index;
phy->pll_ctrl_base = dev->pll_ctrl_base;
phy->usb2_phy_power = dev->usb2_phy_power;
phy->usb3_phy_power = dev->usb3_phy_power;
#ifndef CONFIG_AM43XX
ti_usb3_dpll_program(phy);
ti_usb3_phy_power(phy, 1);
#endif
ti_usb2_phy_power(phy, 1);
mdelay(150);
list_add_tail(&phy->list, &ti_usb_phy_list);
return 0;
}
/**
* ti_usb_phy_uboot_exit - usb phy uboot cleanup code
* @index: index of this controller
*
* Performs cleanup of memory allocated in ti_usb_phy_uboot_init.
* index of _this_ controller should be passed and should match with
* the index passed in ti_usb_phy_device during init.
*
* Generally called from board file.
*/
void ti_usb_phy_uboot_exit(int index)
{
struct ti_usb_phy *phy = NULL;
list_for_each_entry(phy, &ti_usb_phy_list, list) {
if (phy->index != index)
continue;
ti_usb2_phy_power(phy, 0);
#ifndef CONFIG_AM43XX
ti_usb3_phy_power(phy, 0);
#endif
list_del(&phy->list);
kfree(phy);
break;
}
}