avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
57
u-boot/drivers/usb/dwc3/Kconfig
Normal file
57
u-boot/drivers/usb/dwc3/Kconfig
Normal file
@@ -0,0 +1,57 @@
|
||||
config USB_DWC3
|
||||
bool "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB && USB_GADGET)
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Say Y here if your system has a Dual Role SuperSpeed
|
||||
USB controller based on the DesignWare USB3 IP Core.
|
||||
|
||||
if USB_DWC3
|
||||
|
||||
choice
|
||||
bool "DWC3 Mode Selection"
|
||||
|
||||
config USB_DWC3_HOST
|
||||
bool "Host only mode"
|
||||
depends on USB
|
||||
help
|
||||
Select this when you want to use DWC3 in host mode only,
|
||||
thereby the gadget feature will be regressed.
|
||||
|
||||
config USB_DWC3_GADGET
|
||||
bool "Gadget only mode"
|
||||
depends on USB_GADGET
|
||||
help
|
||||
Select this when you want to use DWC3 in gadget mode only,
|
||||
thereby the host feature will be regressed.
|
||||
|
||||
endchoice
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
13
u-boot/drivers/usb/dwc3/Makefile
Normal file
13
u-boot/drivers/usb/dwc3/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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_PHY_OMAP) += ti_usb_phy.o
|
||||
obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o
|
||||
786
u-boot/drivers/usb/dwc3/core.c
Normal file
786
u-boot/drivers/usb/dwc3/core.c
Normal file
@@ -0,0 +1,786 @@
|
||||
/**
|
||||
* core.c - DesignWare USB3 DRD Controller Core file
|
||||
*
|
||||
* 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/core.c) and ported
|
||||
* to uboot.
|
||||
*
|
||||
* commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <dwc3-uboot.h>
|
||||
#include <asm/dma-mapping.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
#include "linux-compat.h"
|
||||
|
||||
static LIST_HEAD(dwc3_list);
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
|
||||
reg |= DWC3_GCTL_PRTCAPDIR(mode);
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
|
||||
* @dwc: pointer to our context structure
|
||||
*/
|
||||
static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Before Resetting PHY, put Core in Reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg |= DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
/* Assert USB3 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
/* Assert USB2 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
/* Clear USB3 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
/* Clear USB2 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
/* After PHYs are stable we can take Core out of reset state */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_free_one_event_buffer - Frees one event buffer
|
||||
* @dwc: Pointer to our controller context structure
|
||||
* @evt: Pointer to event buffer to be freed
|
||||
*/
|
||||
static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
|
||||
struct dwc3_event_buffer *evt)
|
||||
{
|
||||
dma_free_coherent(evt->buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_alloc_one_event_buffer - Allocates one event buffer structure
|
||||
* @dwc: Pointer to our controller context structure
|
||||
* @length: size of the event buffer
|
||||
*
|
||||
* Returns a pointer to the allocated event buffer structure on success
|
||||
* otherwise ERR_PTR(errno).
|
||||
*/
|
||||
static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
|
||||
unsigned length)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
|
||||
if (!evt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
evt->dwc = dwc;
|
||||
evt->length = length;
|
||||
evt->buf = dma_alloc_coherent(length,
|
||||
(unsigned long *)&evt->dma);
|
||||
if (!evt->buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_free_event_buffers - frees all allocated event buffers
|
||||
* @dwc: Pointer to our controller context structure
|
||||
*/
|
||||
static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
evt = dwc->ev_buffs[i];
|
||||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
|
||||
* @dwc: pointer to our controller context structure
|
||||
* @length: size of event buffer
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno. In the error case, dwc
|
||||
* may contain some buffers allocated but not all which were requested.
|
||||
*/
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
int num;
|
||||
int i;
|
||||
|
||||
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
|
||||
dwc->num_event_buffers = num;
|
||||
|
||||
dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE,
|
||||
sizeof(*dwc->ev_buffs) * num);
|
||||
if (!dwc->ev_buffs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buffs[i] = evt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_event_buffers_setup - setup our allocated event buffers
|
||||
* @dwc: pointer to our controller context structure
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
|
||||
| DWC3_GEVNTSIZ_SIZE(0));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
|
||||
DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
|
||||
if (!dwc->scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
dma_addr_t scratch_addr;
|
||||
u32 param;
|
||||
int ret;
|
||||
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
scratch_addr = dma_map_single(dwc->scratchbuf,
|
||||
dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(dwc->dev, scratch_addr)) {
|
||||
dev_err(dwc->dev, "failed to map scratch buffer\n");
|
||||
ret = -EFAULT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->scratch_addr = scratch_addr;
|
||||
|
||||
param = lower_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
param = upper_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return;
|
||||
|
||||
dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
kfree(dwc->scratchbuf);
|
||||
}
|
||||
|
||||
static void dwc3_core_num_eps(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
||||
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
|
||||
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
|
||||
|
||||
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
|
||||
dwc->num_in_eps, dwc->num_out_eps);
|
||||
}
|
||||
|
||||
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
||||
parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
|
||||
parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
|
||||
parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
|
||||
parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
|
||||
parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
|
||||
parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
|
||||
parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
|
||||
parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
|
||||
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
*/
|
||||
static void dwc3_phy_setup(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
|
||||
/*
|
||||
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
|
||||
* to '0' during coreConsultant configuration. So default value
|
||||
* will be '0' when the core is reset. Application needs to set it
|
||||
* to '1' after the core initialization is completed.
|
||||
*/
|
||||
if (dwc->revision > DWC3_REVISION_194A)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
if (dwc->u2ss_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
|
||||
|
||||
if (dwc->req_p1p2p3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
|
||||
|
||||
if (dwc->del_p1p2p3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
|
||||
|
||||
if (dwc->del_phy_power_chg_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
|
||||
|
||||
if (dwc->lfps_filter_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
|
||||
|
||||
if (dwc->rx_detect_poll_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
|
||||
|
||||
if (dwc->tx_de_emphasis_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
|
||||
|
||||
if (dwc->dis_u3_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
|
||||
/*
|
||||
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
|
||||
* '0' during coreConsultant configuration. So default value will
|
||||
* be '0' when the core is reset. Application needs to set it to
|
||||
* '1' after the core initialization is completed.
|
||||
*/
|
||||
if (dwc->revision > DWC3_REVISION_194A)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_u2_susphy_quirk)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int dwc3_core_init(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 hwparams4 = dwc->hwparams.hwparams4;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
|
||||
/* This should read as U3 followed by revision number */
|
||||
if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
ret = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
dwc->revision = reg;
|
||||
|
||||
/* Handle USB2.0-only core configuration */
|
||||
if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
|
||||
DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
|
||||
if (dwc->maximum_speed == USB_SPEED_SUPER)
|
||||
dwc->maximum_speed = USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
/* issue device SoftReset too */
|
||||
timeout = 5000;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
|
||||
while (timeout--) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (!(reg & DWC3_DCTL_CSFTRST))
|
||||
break;
|
||||
};
|
||||
|
||||
if (!timeout) {
|
||||
dev_err(dwc->dev, "Reset Timed Out\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ret = dwc3_core_soft_reset(dwc);
|
||||
if (ret)
|
||||
goto err0;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
||||
|
||||
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
||||
/**
|
||||
* WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
|
||||
* issue which would cause xHCI compliance tests to fail.
|
||||
*
|
||||
* Because of that we cannot enable clock gating on such
|
||||
* configurations.
|
||||
*
|
||||
* Refers to:
|
||||
*
|
||||
* STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
|
||||
* SOF/ITP Mode Used
|
||||
*/
|
||||
if ((dwc->dr_mode == USB_DR_MODE_HOST ||
|
||||
dwc->dr_mode == USB_DR_MODE_OTG) &&
|
||||
(dwc->revision >= DWC3_REVISION_210A &&
|
||||
dwc->revision <= DWC3_REVISION_250A))
|
||||
reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
|
||||
else
|
||||
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
||||
break;
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
|
||||
/* enable hibernation here */
|
||||
dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
|
||||
|
||||
/*
|
||||
* REVISIT Enabling this bit so that host-mode hibernation
|
||||
* will work. Device-mode hibernation is not yet implemented.
|
||||
*/
|
||||
reg |= DWC3_GCTL_GBLHIBERNATIONEN;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dwc->dev, "No power optimization available\n");
|
||||
}
|
||||
|
||||
/* check if current dwc3 is on simulation board */
|
||||
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
|
||||
dev_dbg(dwc->dev, "it is on FPGA board\n");
|
||||
dwc->is_fpga = true;
|
||||
}
|
||||
|
||||
if(dwc->disable_scramble_quirk && !dwc->is_fpga)
|
||||
WARN(true,
|
||||
"disable_scramble cannot be used on non-FPGA builds\n");
|
||||
|
||||
if (dwc->disable_scramble_quirk && dwc->is_fpga)
|
||||
reg |= DWC3_GCTL_DISSCRAMBLE;
|
||||
else
|
||||
reg &= ~DWC3_GCTL_DISSCRAMBLE;
|
||||
|
||||
if (dwc->u2exit_lfps_quirk)
|
||||
reg |= DWC3_GCTL_U2EXIT_LFPS;
|
||||
|
||||
/*
|
||||
* WORKAROUND: DWC3 revisions <1.90a have a bug
|
||||
* where the device can fail to connect at SuperSpeed
|
||||
* and falls back to high-speed mode which causes
|
||||
* the device to enter a Connect/Disconnect loop
|
||||
*/
|
||||
if (dwc->revision < DWC3_REVISION_190A)
|
||||
reg |= DWC3_GCTL_U2RSTECN;
|
||||
|
||||
dwc3_core_num_eps(dwc);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
dwc3_phy_setup(dwc);
|
||||
|
||||
ret = dwc3_alloc_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err0;
|
||||
|
||||
ret = dwc3_setup_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
}
|
||||
|
||||
static int dwc3_core_init_mode(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize gadget\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize gadget\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
||||
{
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_gadget_exit(dwc);
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc3_host_exit(dwc);
|
||||
break;
|
||||
case USB_DR_MODE_OTG:
|
||||
dwc3_host_exit(dwc);
|
||||
dwc3_gadget_exit(dwc);
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define DWC3_ALIGN_MASK (16 - 1)
|
||||
|
||||
/**
|
||||
* dwc3_uboot_init - dwc3 core uboot initialization code
|
||||
* @dwc3_dev: struct dwc3_device containing initialization data
|
||||
*
|
||||
* Entry point for dwc3 driver (equivalent to dwc3_probe in linux
|
||||
* kernel driver). Pointer to dwc3_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_uboot_init(struct dwc3_device *dwc3_dev)
|
||||
{
|
||||
struct dwc3 *dwc;
|
||||
struct device *dev = NULL;
|
||||
u8 lpm_nyet_threshold;
|
||||
u8 tx_de_emphasis;
|
||||
u8 hird_threshold;
|
||||
|
||||
int ret;
|
||||
|
||||
void *mem;
|
||||
|
||||
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
|
||||
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
|
||||
dwc->mem = mem;
|
||||
|
||||
dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
|
||||
DWC3_GLOBALS_REGS_START);
|
||||
|
||||
/* default to highest possible threshold */
|
||||
lpm_nyet_threshold = 0xff;
|
||||
|
||||
/* default to -3.5dB de-emphasis */
|
||||
tx_de_emphasis = 1;
|
||||
|
||||
/*
|
||||
* default to assert utmi_sleep_n and use maximum allowed HIRD
|
||||
* threshold value of 0b1100
|
||||
*/
|
||||
hird_threshold = 12;
|
||||
|
||||
dwc->maximum_speed = dwc3_dev->maximum_speed;
|
||||
dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
|
||||
if (dwc3_dev->lpm_nyet_threshold)
|
||||
lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold;
|
||||
dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend;
|
||||
if (dwc3_dev->hird_threshold)
|
||||
hird_threshold = dwc3_dev->hird_threshold;
|
||||
|
||||
dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize;
|
||||
dwc->dr_mode = dwc3_dev->dr_mode;
|
||||
|
||||
dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk;
|
||||
dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk;
|
||||
dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk;
|
||||
dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk;
|
||||
dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk;
|
||||
dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk;
|
||||
dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk;
|
||||
dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
|
||||
dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
|
||||
dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
|
||||
|
||||
dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
|
||||
if (dwc3_dev->tx_de_emphasis)
|
||||
tx_de_emphasis = dwc3_dev->tx_de_emphasis;
|
||||
|
||||
/* default to superspeed if no maximum_speed passed */
|
||||
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
|
||||
dwc->maximum_speed = USB_SPEED_SUPER;
|
||||
|
||||
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
|
||||
dwc->tx_de_emphasis = tx_de_emphasis;
|
||||
|
||||
dwc->hird_threshold = hird_threshold
|
||||
| (dwc->is_utmi_l1_suspend << 4);
|
||||
|
||||
dwc->index = dwc3_dev->index;
|
||||
|
||||
dwc3_cache_hwparams(dwc);
|
||||
|
||||
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to allocate event buffers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
|
||||
dwc->dr_mode = USB_DR_MODE_HOST;
|
||||
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
||||
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
|
||||
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
dwc->dr_mode = USB_DR_MODE_OTG;
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize core\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = dwc3_core_init_mode(dwc);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
list_add_tail(&dwc->list, &dwc3_list);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
err1:
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
err0:
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_uboot_exit - dwc3 core uboot cleanup code
|
||||
* @index: index of this controller
|
||||
*
|
||||
* Performs cleanup of memory allocated in dwc3_uboot_init and other misc
|
||||
* cleanups (equivalent to dwc3_remove in linux). index of _this_ controller
|
||||
* should be passed and should match with the index passed in
|
||||
* dwc3_device during init.
|
||||
*
|
||||
* Generally called from board file.
|
||||
*/
|
||||
void dwc3_uboot_exit(int index)
|
||||
{
|
||||
struct dwc3 *dwc;
|
||||
|
||||
list_for_each_entry(dwc, &dwc3_list, list) {
|
||||
if (dwc->index != index)
|
||||
continue;
|
||||
|
||||
dwc3_core_exit_mode(dwc);
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
dwc3_free_event_buffers(dwc);
|
||||
dwc3_core_exit(dwc);
|
||||
list_del(&dwc->list);
|
||||
kfree(dwc->mem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_uboot_handle_interrupt - handle dwc3 core interrupt
|
||||
* @index: index of this controller
|
||||
*
|
||||
* Invokes dwc3 gadget interrupts.
|
||||
*
|
||||
* Generally called from board file.
|
||||
*/
|
||||
void dwc3_uboot_handle_interrupt(int index)
|
||||
{
|
||||
struct dwc3 *dwc = NULL;
|
||||
|
||||
list_for_each_entry(dwc, &dwc3_list, list) {
|
||||
if (dwc->index != index)
|
||||
continue;
|
||||
|
||||
dwc3_gadget_uboot_handle_interrupt(dwc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:dwc3");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
|
||||
1032
u-boot/drivers/usb/dwc3/core.h
Normal file
1032
u-boot/drivers/usb/dwc3/core.h
Normal file
File diff suppressed because it is too large
Load Diff
451
u-boot/drivers/usb/dwc3/dwc3-omap.c
Normal file
451
u-boot/drivers/usb/dwc3/dwc3-omap.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/**
|
||||
* 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()
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.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(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");
|
||||
1112
u-boot/drivers/usb/dwc3/ep0.c
Normal file
1112
u-boot/drivers/usb/dwc3/ep0.c
Normal file
File diff suppressed because it is too large
Load Diff
2679
u-boot/drivers/usb/dwc3/gadget.c
Normal file
2679
u-boot/drivers/usb/dwc3/gadget.c
Normal file
File diff suppressed because it is too large
Load Diff
108
u-boot/drivers/usb/dwc3/gadget.h
Normal file
108
u-boot/drivers/usb/dwc3/gadget.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#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 */
|
||||
55
u-boot/drivers/usb/dwc3/io.h
Normal file
55
u-boot/drivers/usb/dwc3/io.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_USB_DWC3_IO_H
|
||||
#define __DRIVERS_USB_DWC3_IO_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(int addr, int length)
|
||||
{
|
||||
flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE));
|
||||
}
|
||||
#endif /* __DRIVERS_USB_DWC3_IO_H */
|
||||
31
u-boot/drivers/usb/dwc3/linux-compat.h
Normal file
31
u-boot/drivers/usb/dwc3/linux-compat.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DWC3_LINUX_COMPAT__
|
||||
#define __DWC3_LINUX_COMPAT__
|
||||
|
||||
#define pr_debug(format) debug(format)
|
||||
#define WARN(val, format, arg...) debug(format, ##arg)
|
||||
#define dev_WARN(dev, format, arg...) debug(format, ##arg)
|
||||
#define WARN_ON_ONCE(val) debug("Error %d\n", val)
|
||||
|
||||
static inline size_t strlcat(char *dest, const char *src, size_t n)
|
||||
{
|
||||
strcat(dest, src);
|
||||
return strlen(dest) + strlen(src);
|
||||
}
|
||||
|
||||
static inline void *devm_kzalloc(struct device *dev, unsigned int size,
|
||||
unsigned int flags)
|
||||
{
|
||||
return kzalloc(size, flags);
|
||||
}
|
||||
#endif
|
||||
78
u-boot/drivers/usb/dwc3/samsung_usb_phy.c
Normal file
78
u-boot/drivers/usb/dwc3/samsung_usb_phy.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* samsung_usb_phy.c - DesignWare USB3 (DWC3) PHY handling file
|
||||
*
|
||||
* Copyright (C) 2015 Samsung Electronics
|
||||
*
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
316
u-boot/drivers/usb/dwc3/ti_usb_phy.c
Normal file
316
u-boot/drivers/usb/dwc3/ti_usb_phy.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <ti-usb-phy-uboot.h>
|
||||
#include <usb/lin_gadget_compat.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sys_proto.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) || defined(CONFIG_AM57XX)
|
||||
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) || defined(CONFIG_AM57XX)
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user