185d5e707SKishon Vijay Abraham I /** 285d5e707SKishon Vijay Abraham I * core.c - DesignWare USB3 DRD Controller Core file 385d5e707SKishon Vijay Abraham I * 430c31d58SKishon Vijay Abraham I * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com 585d5e707SKishon Vijay Abraham I * 685d5e707SKishon Vijay Abraham I * Authors: Felipe Balbi <balbi@ti.com>, 785d5e707SKishon Vijay Abraham I * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 885d5e707SKishon Vijay Abraham I * 930c31d58SKishon Vijay Abraham I * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.c) and ported 1030c31d58SKishon Vijay Abraham I * to uboot. 1185d5e707SKishon Vijay Abraham I * 1230c31d58SKishon Vijay Abraham I * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA 1385d5e707SKishon Vijay Abraham I * 1430c31d58SKishon Vijay Abraham I * SPDX-License-Identifier: GPL-2.0 1585d5e707SKishon Vijay Abraham I */ 1685d5e707SKishon Vijay Abraham I 1771744d0dSKishon Vijay Abraham I #include <common.h> 1871744d0dSKishon Vijay Abraham I #include <malloc.h> 1941933c04SKever Yang #include <fdtdec.h> 208e1906a8SKishon Vijay Abraham I #include <dwc3-uboot.h> 2171744d0dSKishon Vijay Abraham I #include <asm/dma-mapping.h> 2285d5e707SKishon Vijay Abraham I #include <linux/ioport.h> 23b6985a21SMugunthan V N #include <dm.h> 2472d48a52SJean-Jacques Hiblot #include <generic-phy.h> 2585d5e707SKishon Vijay Abraham I #include <linux/usb/ch9.h> 2685d5e707SKishon Vijay Abraham I #include <linux/usb/gadget.h> 2785d5e707SKishon Vijay Abraham I 2885d5e707SKishon Vijay Abraham I #include "core.h" 2985d5e707SKishon Vijay Abraham I #include "gadget.h" 3085d5e707SKishon Vijay Abraham I #include "io.h" 3185d5e707SKishon Vijay Abraham I 3271744d0dSKishon Vijay Abraham I #include "linux-compat.h" 33*36c87911Swilliam.wu #include "rockusb.h" 3485d5e707SKishon Vijay Abraham I 3541933c04SKever Yang DECLARE_GLOBAL_DATA_PTR; 3641933c04SKever Yang 37793d347fSKishon Vijay Abraham I static LIST_HEAD(dwc3_list); 3885d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 3985d5e707SKishon Vijay Abraham I 407e9cb796SJoonyoung Shim static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) 4185d5e707SKishon Vijay Abraham I { 4285d5e707SKishon Vijay Abraham I u32 reg; 4385d5e707SKishon Vijay Abraham I 4485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 4585d5e707SKishon Vijay Abraham I reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); 4685d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_PRTCAPDIR(mode); 4785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 4885d5e707SKishon Vijay Abraham I } 4985d5e707SKishon Vijay Abraham I 5085d5e707SKishon Vijay Abraham I /** 5185d5e707SKishon Vijay Abraham I * dwc3_core_soft_reset - Issues core soft reset and PHY reset 5285d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 5385d5e707SKishon Vijay Abraham I */ 5485d5e707SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc) 5585d5e707SKishon Vijay Abraham I { 5685d5e707SKishon Vijay Abraham I u32 reg; 5785d5e707SKishon Vijay Abraham I 5885d5e707SKishon Vijay Abraham I /* Before Resetting PHY, put Core in Reset */ 5985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 6085d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_CORESOFTRESET; 6185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 6285d5e707SKishon Vijay Abraham I 6385d5e707SKishon Vijay Abraham I /* Assert USB3 PHY reset */ 6485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 6585d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; 6685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 6785d5e707SKishon Vijay Abraham I 6885d5e707SKishon Vijay Abraham I /* Assert USB2 PHY reset */ 6985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 7085d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; 7185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 7285d5e707SKishon Vijay Abraham I 7385d5e707SKishon Vijay Abraham I mdelay(100); 7485d5e707SKishon Vijay Abraham I 7585d5e707SKishon Vijay Abraham I /* Clear USB3 PHY reset */ 7685d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 7785d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; 7885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 7985d5e707SKishon Vijay Abraham I 8085d5e707SKishon Vijay Abraham I /* Clear USB2 PHY reset */ 8185d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 8285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; 8385d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 8485d5e707SKishon Vijay Abraham I 8585d5e707SKishon Vijay Abraham I mdelay(100); 8685d5e707SKishon Vijay Abraham I 8785d5e707SKishon Vijay Abraham I /* After PHYs are stable we can take Core out of reset state */ 8885d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 8985d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_CORESOFTRESET; 9085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 9185d5e707SKishon Vijay Abraham I 9285d5e707SKishon Vijay Abraham I return 0; 9385d5e707SKishon Vijay Abraham I } 9485d5e707SKishon Vijay Abraham I 9585d5e707SKishon Vijay Abraham I /** 9685d5e707SKishon Vijay Abraham I * dwc3_free_one_event_buffer - Frees one event buffer 9785d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 9885d5e707SKishon Vijay Abraham I * @evt: Pointer to event buffer to be freed 9985d5e707SKishon Vijay Abraham I */ 10085d5e707SKishon Vijay Abraham I static void dwc3_free_one_event_buffer(struct dwc3 *dwc, 10185d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt) 10285d5e707SKishon Vijay Abraham I { 10371744d0dSKishon Vijay Abraham I dma_free_coherent(evt->buf); 10485d5e707SKishon Vijay Abraham I } 10585d5e707SKishon Vijay Abraham I 10685d5e707SKishon Vijay Abraham I /** 10785d5e707SKishon Vijay Abraham I * dwc3_alloc_one_event_buffer - Allocates one event buffer structure 10885d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 10985d5e707SKishon Vijay Abraham I * @length: size of the event buffer 11085d5e707SKishon Vijay Abraham I * 11185d5e707SKishon Vijay Abraham I * Returns a pointer to the allocated event buffer structure on success 11285d5e707SKishon Vijay Abraham I * otherwise ERR_PTR(errno). 11385d5e707SKishon Vijay Abraham I */ 11485d5e707SKishon Vijay Abraham I static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, 11585d5e707SKishon Vijay Abraham I unsigned length) 11685d5e707SKishon Vijay Abraham I { 11785d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 11885d5e707SKishon Vijay Abraham I 119b6985a21SMugunthan V N evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt), 120b6985a21SMugunthan V N GFP_KERNEL); 12185d5e707SKishon Vijay Abraham I if (!evt) 12285d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 12385d5e707SKishon Vijay Abraham I 12485d5e707SKishon Vijay Abraham I evt->dwc = dwc; 12585d5e707SKishon Vijay Abraham I evt->length = length; 12671744d0dSKishon Vijay Abraham I evt->buf = dma_alloc_coherent(length, 12771744d0dSKishon Vijay Abraham I (unsigned long *)&evt->dma); 12885d5e707SKishon Vijay Abraham I if (!evt->buf) 12985d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 13085d5e707SKishon Vijay Abraham I 131889239d6SPhilipp Tomsich dwc3_flush_cache((uintptr_t)evt->buf, evt->length); 132889239d6SPhilipp Tomsich 13385d5e707SKishon Vijay Abraham I return evt; 13485d5e707SKishon Vijay Abraham I } 13585d5e707SKishon Vijay Abraham I 13685d5e707SKishon Vijay Abraham I /** 13785d5e707SKishon Vijay Abraham I * dwc3_free_event_buffers - frees all allocated event buffers 13885d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 13985d5e707SKishon Vijay Abraham I */ 14085d5e707SKishon Vijay Abraham I static void dwc3_free_event_buffers(struct dwc3 *dwc) 14185d5e707SKishon Vijay Abraham I { 14285d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 14385d5e707SKishon Vijay Abraham I int i; 14485d5e707SKishon Vijay Abraham I 14585d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) { 14685d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[i]; 14785d5e707SKishon Vijay Abraham I if (evt) 14885d5e707SKishon Vijay Abraham I dwc3_free_one_event_buffer(dwc, evt); 14985d5e707SKishon Vijay Abraham I } 15085d5e707SKishon Vijay Abraham I } 15185d5e707SKishon Vijay Abraham I 15285d5e707SKishon Vijay Abraham I /** 15385d5e707SKishon Vijay Abraham I * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length 15485d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 15585d5e707SKishon Vijay Abraham I * @length: size of event buffer 15685d5e707SKishon Vijay Abraham I * 15785d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. In the error case, dwc 15885d5e707SKishon Vijay Abraham I * may contain some buffers allocated but not all which were requested. 15985d5e707SKishon Vijay Abraham I */ 16085d5e707SKishon Vijay Abraham I static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) 16185d5e707SKishon Vijay Abraham I { 16285d5e707SKishon Vijay Abraham I int num; 16385d5e707SKishon Vijay Abraham I int i; 16485d5e707SKishon Vijay Abraham I 16585d5e707SKishon Vijay Abraham I num = DWC3_NUM_INT(dwc->hwparams.hwparams1); 16685d5e707SKishon Vijay Abraham I dwc->num_event_buffers = num; 16785d5e707SKishon Vijay Abraham I 168526a50f8SKishon Vijay Abraham I dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE, 169526a50f8SKishon Vijay Abraham I sizeof(*dwc->ev_buffs) * num); 17085d5e707SKishon Vijay Abraham I if (!dwc->ev_buffs) 17185d5e707SKishon Vijay Abraham I return -ENOMEM; 17285d5e707SKishon Vijay Abraham I 17385d5e707SKishon Vijay Abraham I for (i = 0; i < num; i++) { 17485d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 17585d5e707SKishon Vijay Abraham I 17685d5e707SKishon Vijay Abraham I evt = dwc3_alloc_one_event_buffer(dwc, length); 17785d5e707SKishon Vijay Abraham I if (IS_ERR(evt)) { 17885d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "can't allocate event buffer\n"); 17985d5e707SKishon Vijay Abraham I return PTR_ERR(evt); 18085d5e707SKishon Vijay Abraham I } 18185d5e707SKishon Vijay Abraham I dwc->ev_buffs[i] = evt; 18285d5e707SKishon Vijay Abraham I } 18385d5e707SKishon Vijay Abraham I 18485d5e707SKishon Vijay Abraham I return 0; 18585d5e707SKishon Vijay Abraham I } 18685d5e707SKishon Vijay Abraham I 18785d5e707SKishon Vijay Abraham I /** 18885d5e707SKishon Vijay Abraham I * dwc3_event_buffers_setup - setup our allocated event buffers 18985d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 19085d5e707SKishon Vijay Abraham I * 19185d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 19285d5e707SKishon Vijay Abraham I */ 19385d5e707SKishon Vijay Abraham I static int dwc3_event_buffers_setup(struct dwc3 *dwc) 19485d5e707SKishon Vijay Abraham I { 19585d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 19685d5e707SKishon Vijay Abraham I int n; 19785d5e707SKishon Vijay Abraham I 19885d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 19985d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 20085d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", 20185d5e707SKishon Vijay Abraham I evt->buf, (unsigned long long) evt->dma, 20285d5e707SKishon Vijay Abraham I evt->length); 20385d5e707SKishon Vijay Abraham I 20485d5e707SKishon Vijay Abraham I evt->lpos = 0; 20585d5e707SKishon Vijay Abraham I 20685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 20785d5e707SKishon Vijay Abraham I lower_32_bits(evt->dma)); 20885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 20985d5e707SKishon Vijay Abraham I upper_32_bits(evt->dma)); 21085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 21185d5e707SKishon Vijay Abraham I DWC3_GEVNTSIZ_SIZE(evt->length)); 21285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 21385d5e707SKishon Vijay Abraham I } 21485d5e707SKishon Vijay Abraham I 21585d5e707SKishon Vijay Abraham I return 0; 21685d5e707SKishon Vijay Abraham I } 21785d5e707SKishon Vijay Abraham I 21885d5e707SKishon Vijay Abraham I static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) 21985d5e707SKishon Vijay Abraham I { 22085d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 22185d5e707SKishon Vijay Abraham I int n; 22285d5e707SKishon Vijay Abraham I 22385d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 22485d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 22585d5e707SKishon Vijay Abraham I 22685d5e707SKishon Vijay Abraham I evt->lpos = 0; 22785d5e707SKishon Vijay Abraham I 22885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); 22985d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); 23085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK 23185d5e707SKishon Vijay Abraham I | DWC3_GEVNTSIZ_SIZE(0)); 23285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 23385d5e707SKishon Vijay Abraham I } 23485d5e707SKishon Vijay Abraham I } 23585d5e707SKishon Vijay Abraham I 23685d5e707SKishon Vijay Abraham I static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) 23785d5e707SKishon Vijay Abraham I { 23885d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 23985d5e707SKishon Vijay Abraham I return 0; 24085d5e707SKishon Vijay Abraham I 24185d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 24285d5e707SKishon Vijay Abraham I return 0; 24385d5e707SKishon Vijay Abraham I 24485d5e707SKishon Vijay Abraham I dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, 24585d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); 24685d5e707SKishon Vijay Abraham I if (!dwc->scratchbuf) 24785d5e707SKishon Vijay Abraham I return -ENOMEM; 24885d5e707SKishon Vijay Abraham I 24985d5e707SKishon Vijay Abraham I return 0; 25085d5e707SKishon Vijay Abraham I } 25185d5e707SKishon Vijay Abraham I 25285d5e707SKishon Vijay Abraham I static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) 25385d5e707SKishon Vijay Abraham I { 25485d5e707SKishon Vijay Abraham I dma_addr_t scratch_addr; 25585d5e707SKishon Vijay Abraham I u32 param; 25685d5e707SKishon Vijay Abraham I int ret; 25785d5e707SKishon Vijay Abraham I 25885d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 25985d5e707SKishon Vijay Abraham I return 0; 26085d5e707SKishon Vijay Abraham I 26185d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 26285d5e707SKishon Vijay Abraham I return 0; 26385d5e707SKishon Vijay Abraham I 26471744d0dSKishon Vijay Abraham I scratch_addr = dma_map_single(dwc->scratchbuf, 26585d5e707SKishon Vijay Abraham I dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, 26685d5e707SKishon Vijay Abraham I DMA_BIDIRECTIONAL); 26785d5e707SKishon Vijay Abraham I if (dma_mapping_error(dwc->dev, scratch_addr)) { 26885d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to map scratch buffer\n"); 26985d5e707SKishon Vijay Abraham I ret = -EFAULT; 27085d5e707SKishon Vijay Abraham I goto err0; 27185d5e707SKishon Vijay Abraham I } 27285d5e707SKishon Vijay Abraham I 27385d5e707SKishon Vijay Abraham I dwc->scratch_addr = scratch_addr; 27485d5e707SKishon Vijay Abraham I 27585d5e707SKishon Vijay Abraham I param = lower_32_bits(scratch_addr); 27685d5e707SKishon Vijay Abraham I 27785d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 27885d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); 27985d5e707SKishon Vijay Abraham I if (ret < 0) 28085d5e707SKishon Vijay Abraham I goto err1; 28185d5e707SKishon Vijay Abraham I 28285d5e707SKishon Vijay Abraham I param = upper_32_bits(scratch_addr); 28385d5e707SKishon Vijay Abraham I 28485d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 28585d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); 28685d5e707SKishon Vijay Abraham I if (ret < 0) 28785d5e707SKishon Vijay Abraham I goto err1; 28885d5e707SKishon Vijay Abraham I 28985d5e707SKishon Vijay Abraham I return 0; 29085d5e707SKishon Vijay Abraham I 29185d5e707SKishon Vijay Abraham I err1: 29201c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 29385d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 29485d5e707SKishon Vijay Abraham I 29585d5e707SKishon Vijay Abraham I err0: 29685d5e707SKishon Vijay Abraham I return ret; 29785d5e707SKishon Vijay Abraham I } 29885d5e707SKishon Vijay Abraham I 29985d5e707SKishon Vijay Abraham I static void dwc3_free_scratch_buffers(struct dwc3 *dwc) 30085d5e707SKishon Vijay Abraham I { 30185d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 30285d5e707SKishon Vijay Abraham I return; 30385d5e707SKishon Vijay Abraham I 30485d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 30585d5e707SKishon Vijay Abraham I return; 30685d5e707SKishon Vijay Abraham I 30701c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 30885d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 30985d5e707SKishon Vijay Abraham I kfree(dwc->scratchbuf); 31085d5e707SKishon Vijay Abraham I } 31185d5e707SKishon Vijay Abraham I 31285d5e707SKishon Vijay Abraham I static void dwc3_core_num_eps(struct dwc3 *dwc) 31385d5e707SKishon Vijay Abraham I { 31485d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 31585d5e707SKishon Vijay Abraham I 31685d5e707SKishon Vijay Abraham I dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); 31785d5e707SKishon Vijay Abraham I dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; 31885d5e707SKishon Vijay Abraham I 31985d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", 32085d5e707SKishon Vijay Abraham I dwc->num_in_eps, dwc->num_out_eps); 32185d5e707SKishon Vijay Abraham I } 32285d5e707SKishon Vijay Abraham I 32385d5e707SKishon Vijay Abraham I static void dwc3_cache_hwparams(struct dwc3 *dwc) 32485d5e707SKishon Vijay Abraham I { 32585d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 32685d5e707SKishon Vijay Abraham I 32785d5e707SKishon Vijay Abraham I parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); 32885d5e707SKishon Vijay Abraham I parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); 32985d5e707SKishon Vijay Abraham I parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); 33085d5e707SKishon Vijay Abraham I parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); 33185d5e707SKishon Vijay Abraham I parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); 33285d5e707SKishon Vijay Abraham I parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); 33385d5e707SKishon Vijay Abraham I parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); 33485d5e707SKishon Vijay Abraham I parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); 33585d5e707SKishon Vijay Abraham I parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); 33685d5e707SKishon Vijay Abraham I } 33785d5e707SKishon Vijay Abraham I 33873d7b075SFrank Wang static void dwc3_hsphy_mode_setup(struct dwc3 *dwc) 33973d7b075SFrank Wang { 34073d7b075SFrank Wang enum usb_phy_interface hsphy_mode = dwc->hsphy_mode; 34173d7b075SFrank Wang u32 reg; 34273d7b075SFrank Wang 34373d7b075SFrank Wang /* Set dwc3 usb2 phy config */ 34473d7b075SFrank Wang reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 34573d7b075SFrank Wang 34673d7b075SFrank Wang switch (hsphy_mode) { 34773d7b075SFrank Wang case USBPHY_INTERFACE_MODE_UTMI: 34873d7b075SFrank Wang reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 34973d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 35073d7b075SFrank Wang reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | 35173d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); 35273d7b075SFrank Wang break; 35373d7b075SFrank Wang case USBPHY_INTERFACE_MODE_UTMIW: 35473d7b075SFrank Wang reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 35573d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 35673d7b075SFrank Wang reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | 35773d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); 35873d7b075SFrank Wang break; 35973d7b075SFrank Wang default: 36073d7b075SFrank Wang break; 36173d7b075SFrank Wang } 36273d7b075SFrank Wang 36373d7b075SFrank Wang dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 36473d7b075SFrank Wang } 36573d7b075SFrank Wang 36685d5e707SKishon Vijay Abraham I /** 36785d5e707SKishon Vijay Abraham I * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core 36885d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 36985d5e707SKishon Vijay Abraham I */ 37085d5e707SKishon Vijay Abraham I static void dwc3_phy_setup(struct dwc3 *dwc) 37185d5e707SKishon Vijay Abraham I { 37285d5e707SKishon Vijay Abraham I u32 reg; 37385d5e707SKishon Vijay Abraham I 37485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 37585d5e707SKishon Vijay Abraham I 37685d5e707SKishon Vijay Abraham I /* 37785d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY 37885d5e707SKishon Vijay Abraham I * to '0' during coreConsultant configuration. So default value 37985d5e707SKishon Vijay Abraham I * will be '0' when the core is reset. Application needs to set it 38085d5e707SKishon Vijay Abraham I * to '1' after the core initialization is completed. 38185d5e707SKishon Vijay Abraham I */ 38285d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 38385d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_SUSPHY; 38485d5e707SKishon Vijay Abraham I 38585d5e707SKishon Vijay Abraham I if (dwc->u2ss_inp3_quirk) 38685d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; 38785d5e707SKishon Vijay Abraham I 38885d5e707SKishon Vijay Abraham I if (dwc->req_p1p2p3_quirk) 38985d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; 39085d5e707SKishon Vijay Abraham I 39185d5e707SKishon Vijay Abraham I if (dwc->del_p1p2p3_quirk) 39285d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; 39385d5e707SKishon Vijay Abraham I 39485d5e707SKishon Vijay Abraham I if (dwc->del_phy_power_chg_quirk) 39585d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; 39685d5e707SKishon Vijay Abraham I 39785d5e707SKishon Vijay Abraham I if (dwc->lfps_filter_quirk) 39885d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_LFPSFILT; 39985d5e707SKishon Vijay Abraham I 40085d5e707SKishon Vijay Abraham I if (dwc->rx_detect_poll_quirk) 40185d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; 40285d5e707SKishon Vijay Abraham I 40385d5e707SKishon Vijay Abraham I if (dwc->tx_de_emphasis_quirk) 40485d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); 40585d5e707SKishon Vijay Abraham I 406a770203cSFrank Wang /* 407a770203cSFrank Wang * For some Rokchip SoCs like RK3588, if the USB3 PHY is suspended 408a770203cSFrank Wang * in U-Boot would cause the PHY initialize abortively in Linux Kernel, 409a770203cSFrank Wang * so disable the DWC3_GUSB3PIPECTL_SUSPHY feature here to fix it. 410a770203cSFrank Wang */ 411a770203cSFrank Wang if (dwc->dis_u3_susphy_quirk || CONFIG_IS_ENABLED(ARCH_ROCKCHIP)) 41285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 41385d5e707SKishon Vijay Abraham I 41485d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 41585d5e707SKishon Vijay Abraham I 41673d7b075SFrank Wang dwc3_hsphy_mode_setup(dwc); 41773d7b075SFrank Wang 41885d5e707SKishon Vijay Abraham I mdelay(100); 41985d5e707SKishon Vijay Abraham I 42085d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 42185d5e707SKishon Vijay Abraham I 42285d5e707SKishon Vijay Abraham I /* 42385d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to 42485d5e707SKishon Vijay Abraham I * '0' during coreConsultant configuration. So default value will 42585d5e707SKishon Vijay Abraham I * be '0' when the core is reset. Application needs to set it to 42685d5e707SKishon Vijay Abraham I * '1' after the core initialization is completed. 42785d5e707SKishon Vijay Abraham I */ 42885d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 42985d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_SUSPHY; 43085d5e707SKishon Vijay Abraham I 43185d5e707SKishon Vijay Abraham I if (dwc->dis_u2_susphy_quirk) 43285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 43385d5e707SKishon Vijay Abraham I 434f4acaed3SFrank Wang if (dwc->dis_enblslpm_quirk) 435f4acaed3SFrank Wang reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 436f4acaed3SFrank Wang 437efc9f556SFrank Wang if (dwc->dis_u2_freeclk_exists_quirk) 438efc9f556SFrank Wang reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; 439efc9f556SFrank Wang 44041933c04SKever Yang if (dwc->usb2_phyif_utmi_width == 16) { 4412136741eSJagan Teki reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 4422136741eSJagan Teki DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 4432136741eSJagan Teki reg |= DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); 4442136741eSJagan Teki reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT); 44541933c04SKever Yang } 44685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 44785d5e707SKishon Vijay Abraham I 44885d5e707SKishon Vijay Abraham I mdelay(100); 44985d5e707SKishon Vijay Abraham I } 45085d5e707SKishon Vijay Abraham I 45185d5e707SKishon Vijay Abraham I /** 45285d5e707SKishon Vijay Abraham I * dwc3_core_init - Low-level initialization of DWC3 Core 45385d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 45485d5e707SKishon Vijay Abraham I * 45585d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 45685d5e707SKishon Vijay Abraham I */ 45785d5e707SKishon Vijay Abraham I static int dwc3_core_init(struct dwc3 *dwc) 45885d5e707SKishon Vijay Abraham I { 45985d5e707SKishon Vijay Abraham I unsigned long timeout; 46085d5e707SKishon Vijay Abraham I u32 hwparams4 = dwc->hwparams.hwparams4; 46185d5e707SKishon Vijay Abraham I u32 reg; 46285d5e707SKishon Vijay Abraham I int ret; 46385d5e707SKishon Vijay Abraham I 46485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); 46585d5e707SKishon Vijay Abraham I /* This should read as U3 followed by revision number */ 46685d5e707SKishon Vijay Abraham I if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { 46785d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); 46885d5e707SKishon Vijay Abraham I ret = -ENODEV; 46985d5e707SKishon Vijay Abraham I goto err0; 47085d5e707SKishon Vijay Abraham I } 47185d5e707SKishon Vijay Abraham I dwc->revision = reg; 47285d5e707SKishon Vijay Abraham I 47385d5e707SKishon Vijay Abraham I /* Handle USB2.0-only core configuration */ 47485d5e707SKishon Vijay Abraham I if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == 47585d5e707SKishon Vijay Abraham I DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { 47685d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_SUPER) 47785d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_HIGH; 47885d5e707SKishon Vijay Abraham I } 47985d5e707SKishon Vijay Abraham I 48085d5e707SKishon Vijay Abraham I /* issue device SoftReset too */ 48171744d0dSKishon Vijay Abraham I timeout = 5000; 48285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); 48371744d0dSKishon Vijay Abraham I while (timeout--) { 48485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 48585d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DCTL_CSFTRST)) 48685d5e707SKishon Vijay Abraham I break; 48771744d0dSKishon Vijay Abraham I }; 48885d5e707SKishon Vijay Abraham I 48971744d0dSKishon Vijay Abraham I if (!timeout) { 49085d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Reset Timed Out\n"); 49185d5e707SKishon Vijay Abraham I ret = -ETIMEDOUT; 49285d5e707SKishon Vijay Abraham I goto err0; 49385d5e707SKishon Vijay Abraham I } 49485d5e707SKishon Vijay Abraham I 49585d5e707SKishon Vijay Abraham I ret = dwc3_core_soft_reset(dwc); 49685d5e707SKishon Vijay Abraham I if (ret) 49785d5e707SKishon Vijay Abraham I goto err0; 49885d5e707SKishon Vijay Abraham I 4993b2dd5deSWilliam Wu if (dwc->revision >= DWC3_REVISION_250A) { 5003b2dd5deSWilliam Wu reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); 5013b2dd5deSWilliam Wu 5023b2dd5deSWilliam Wu if (dwc->maximum_speed == USB_SPEED_HIGH || 5033b2dd5deSWilliam Wu dwc->maximum_speed == USB_SPEED_FULL) 5043b2dd5deSWilliam Wu reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; 5053b2dd5deSWilliam Wu 5063b2dd5deSWilliam Wu dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); 5073b2dd5deSWilliam Wu } 5083b2dd5deSWilliam Wu 50985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 51085d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 51185d5e707SKishon Vijay Abraham I 51285d5e707SKishon Vijay Abraham I switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { 51385d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 51485d5e707SKishon Vijay Abraham I /** 51585d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an 51685d5e707SKishon Vijay Abraham I * issue which would cause xHCI compliance tests to fail. 51785d5e707SKishon Vijay Abraham I * 51885d5e707SKishon Vijay Abraham I * Because of that we cannot enable clock gating on such 51985d5e707SKishon Vijay Abraham I * configurations. 52085d5e707SKishon Vijay Abraham I * 52185d5e707SKishon Vijay Abraham I * Refers to: 52285d5e707SKishon Vijay Abraham I * 52385d5e707SKishon Vijay Abraham I * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based 52485d5e707SKishon Vijay Abraham I * SOF/ITP Mode Used 52585d5e707SKishon Vijay Abraham I */ 52685d5e707SKishon Vijay Abraham I if ((dwc->dr_mode == USB_DR_MODE_HOST || 52785d5e707SKishon Vijay Abraham I dwc->dr_mode == USB_DR_MODE_OTG) && 52885d5e707SKishon Vijay Abraham I (dwc->revision >= DWC3_REVISION_210A && 52985d5e707SKishon Vijay Abraham I dwc->revision <= DWC3_REVISION_250A)) 53085d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 53185d5e707SKishon Vijay Abraham I else 53285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DSBLCLKGTNG; 53385d5e707SKishon Vijay Abraham I break; 53485d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 53585d5e707SKishon Vijay Abraham I /* enable hibernation here */ 53685d5e707SKishon Vijay Abraham I dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); 53785d5e707SKishon Vijay Abraham I 53885d5e707SKishon Vijay Abraham I /* 53985d5e707SKishon Vijay Abraham I * REVISIT Enabling this bit so that host-mode hibernation 54085d5e707SKishon Vijay Abraham I * will work. Device-mode hibernation is not yet implemented. 54185d5e707SKishon Vijay Abraham I */ 54285d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_GBLHIBERNATIONEN; 54385d5e707SKishon Vijay Abraham I break; 54485d5e707SKishon Vijay Abraham I default: 54585d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "No power optimization available\n"); 54685d5e707SKishon Vijay Abraham I } 54785d5e707SKishon Vijay Abraham I 54885d5e707SKishon Vijay Abraham I /* check if current dwc3 is on simulation board */ 54985d5e707SKishon Vijay Abraham I if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { 55085d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "it is on FPGA board\n"); 55185d5e707SKishon Vijay Abraham I dwc->is_fpga = true; 55285d5e707SKishon Vijay Abraham I } 55385d5e707SKishon Vijay Abraham I 55471744d0dSKishon Vijay Abraham I if(dwc->disable_scramble_quirk && !dwc->is_fpga) 55571744d0dSKishon Vijay Abraham I WARN(true, 55685d5e707SKishon Vijay Abraham I "disable_scramble cannot be used on non-FPGA builds\n"); 55785d5e707SKishon Vijay Abraham I 55885d5e707SKishon Vijay Abraham I if (dwc->disable_scramble_quirk && dwc->is_fpga) 55985d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DISSCRAMBLE; 56085d5e707SKishon Vijay Abraham I else 56185d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DISSCRAMBLE; 56285d5e707SKishon Vijay Abraham I 56385d5e707SKishon Vijay Abraham I if (dwc->u2exit_lfps_quirk) 56485d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2EXIT_LFPS; 56585d5e707SKishon Vijay Abraham I 56685d5e707SKishon Vijay Abraham I /* 56785d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.90a have a bug 56885d5e707SKishon Vijay Abraham I * where the device can fail to connect at SuperSpeed 56985d5e707SKishon Vijay Abraham I * and falls back to high-speed mode which causes 57085d5e707SKishon Vijay Abraham I * the device to enter a Connect/Disconnect loop 57185d5e707SKishon Vijay Abraham I */ 57285d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_190A) 57385d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2RSTECN; 57485d5e707SKishon Vijay Abraham I 57585d5e707SKishon Vijay Abraham I dwc3_core_num_eps(dwc); 57685d5e707SKishon Vijay Abraham I 57785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 57885d5e707SKishon Vijay Abraham I 5797ce213e7SFrank Wang dwc3_phy_setup(dwc); 5807ce213e7SFrank Wang 58185d5e707SKishon Vijay Abraham I ret = dwc3_alloc_scratch_buffers(dwc); 58285d5e707SKishon Vijay Abraham I if (ret) 58371744d0dSKishon Vijay Abraham I goto err0; 58485d5e707SKishon Vijay Abraham I 58585d5e707SKishon Vijay Abraham I ret = dwc3_setup_scratch_buffers(dwc); 58685d5e707SKishon Vijay Abraham I if (ret) 58771744d0dSKishon Vijay Abraham I goto err1; 58885d5e707SKishon Vijay Abraham I 58985d5e707SKishon Vijay Abraham I return 0; 59085d5e707SKishon Vijay Abraham I 59185d5e707SKishon Vijay Abraham I err1: 59271744d0dSKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 59385d5e707SKishon Vijay Abraham I 59485d5e707SKishon Vijay Abraham I err0: 59585d5e707SKishon Vijay Abraham I return ret; 59685d5e707SKishon Vijay Abraham I } 59785d5e707SKishon Vijay Abraham I 59885d5e707SKishon Vijay Abraham I static void dwc3_core_exit(struct dwc3 *dwc) 59985d5e707SKishon Vijay Abraham I { 60085d5e707SKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 60185d5e707SKishon Vijay Abraham I } 60285d5e707SKishon Vijay Abraham I 60385d5e707SKishon Vijay Abraham I static int dwc3_core_init_mode(struct dwc3 *dwc) 60485d5e707SKishon Vijay Abraham I { 60585d5e707SKishon Vijay Abraham I int ret; 60685d5e707SKishon Vijay Abraham I 60785d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 60885d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 60985d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 61085d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 61185d5e707SKishon Vijay Abraham I if (ret) { 61285d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 61385d5e707SKishon Vijay Abraham I return ret; 61485d5e707SKishon Vijay Abraham I } 61585d5e707SKishon Vijay Abraham I break; 61685d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 61785d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); 61885d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 61985d5e707SKishon Vijay Abraham I if (ret) { 62085d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 62185d5e707SKishon Vijay Abraham I return ret; 62285d5e707SKishon Vijay Abraham I } 62385d5e707SKishon Vijay Abraham I break; 62485d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 62585d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); 62685d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 62785d5e707SKishon Vijay Abraham I if (ret) { 62885d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 62985d5e707SKishon Vijay Abraham I return ret; 63085d5e707SKishon Vijay Abraham I } 63185d5e707SKishon Vijay Abraham I 63285d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 63385d5e707SKishon Vijay Abraham I if (ret) { 63485d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 63585d5e707SKishon Vijay Abraham I return ret; 63685d5e707SKishon Vijay Abraham I } 63785d5e707SKishon Vijay Abraham I break; 63885d5e707SKishon Vijay Abraham I default: 63985d5e707SKishon Vijay Abraham I dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); 64085d5e707SKishon Vijay Abraham I return -EINVAL; 64185d5e707SKishon Vijay Abraham I } 64285d5e707SKishon Vijay Abraham I 64385d5e707SKishon Vijay Abraham I return 0; 64485d5e707SKishon Vijay Abraham I } 64585d5e707SKishon Vijay Abraham I 6462f6edaaeSJean-Jacques Hiblot static void dwc3_gadget_run(struct dwc3 *dwc) 6472f6edaaeSJean-Jacques Hiblot { 6482f6edaaeSJean-Jacques Hiblot dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP); 6492f6edaaeSJean-Jacques Hiblot mdelay(100); 6502f6edaaeSJean-Jacques Hiblot } 6512f6edaaeSJean-Jacques Hiblot 65285d5e707SKishon Vijay Abraham I static void dwc3_core_exit_mode(struct dwc3 *dwc) 65385d5e707SKishon Vijay Abraham I { 65485d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 65585d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 65685d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 65785d5e707SKishon Vijay Abraham I break; 65885d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 65985d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 66085d5e707SKishon Vijay Abraham I break; 66185d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 66285d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 66385d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 66485d5e707SKishon Vijay Abraham I break; 66585d5e707SKishon Vijay Abraham I default: 66685d5e707SKishon Vijay Abraham I /* do nothing */ 66785d5e707SKishon Vijay Abraham I break; 66885d5e707SKishon Vijay Abraham I } 6692f6edaaeSJean-Jacques Hiblot 6702f6edaaeSJean-Jacques Hiblot /* 6712f6edaaeSJean-Jacques Hiblot * switch back to peripheral mode 6722f6edaaeSJean-Jacques Hiblot * This enables the phy to enter idle and then, if enabled, suspend. 6732f6edaaeSJean-Jacques Hiblot */ 6742f6edaaeSJean-Jacques Hiblot dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 6752f6edaaeSJean-Jacques Hiblot dwc3_gadget_run(dwc); 67685d5e707SKishon Vijay Abraham I } 67785d5e707SKishon Vijay Abraham I 67885d5e707SKishon Vijay Abraham I #define DWC3_ALIGN_MASK (16 - 1) 67985d5e707SKishon Vijay Abraham I 6808e1906a8SKishon Vijay Abraham I /** 6818e1906a8SKishon Vijay Abraham I * dwc3_uboot_init - dwc3 core uboot initialization code 6828e1906a8SKishon Vijay Abraham I * @dwc3_dev: struct dwc3_device containing initialization data 6838e1906a8SKishon Vijay Abraham I * 6848e1906a8SKishon Vijay Abraham I * Entry point for dwc3 driver (equivalent to dwc3_probe in linux 6858e1906a8SKishon Vijay Abraham I * kernel driver). Pointer to dwc3_device should be passed containing 6868e1906a8SKishon Vijay Abraham I * base address and other initialization data. Returns '0' on success and 6878e1906a8SKishon Vijay Abraham I * a negative value on failure. 6888e1906a8SKishon Vijay Abraham I * 6898e1906a8SKishon Vijay Abraham I * Generally called from board_usb_init() implemented in board file. 6908e1906a8SKishon Vijay Abraham I */ 6918e1906a8SKishon Vijay Abraham I int dwc3_uboot_init(struct dwc3_device *dwc3_dev) 69285d5e707SKishon Vijay Abraham I { 693793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 694c2ad4e1bSFelipe Balbi struct device *dev = NULL; 69585d5e707SKishon Vijay Abraham I u8 lpm_nyet_threshold; 69685d5e707SKishon Vijay Abraham I u8 tx_de_emphasis; 69785d5e707SKishon Vijay Abraham I u8 hird_threshold; 69885d5e707SKishon Vijay Abraham I 69985d5e707SKishon Vijay Abraham I int ret; 70085d5e707SKishon Vijay Abraham I 70185d5e707SKishon Vijay Abraham I void *mem; 70241933c04SKever Yang const void *blob = gd->fdt_blob; 70341933c04SKever Yang int node; 70485d5e707SKishon Vijay Abraham I 705b6985a21SMugunthan V N mem = devm_kzalloc((struct udevice *)dev, 706b6985a21SMugunthan V N sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); 70785d5e707SKishon Vijay Abraham I if (!mem) 70885d5e707SKishon Vijay Abraham I return -ENOMEM; 70985d5e707SKishon Vijay Abraham I 71085d5e707SKishon Vijay Abraham I dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); 71185d5e707SKishon Vijay Abraham I dwc->mem = mem; 71285d5e707SKishon Vijay Abraham I 71301c94c4aSMichal Simek dwc->regs = (void *)(uintptr_t)(dwc3_dev->base + 71401c94c4aSMichal Simek DWC3_GLOBALS_REGS_START); 71585d5e707SKishon Vijay Abraham I 71685d5e707SKishon Vijay Abraham I /* default to highest possible threshold */ 71785d5e707SKishon Vijay Abraham I lpm_nyet_threshold = 0xff; 71885d5e707SKishon Vijay Abraham I 71985d5e707SKishon Vijay Abraham I /* default to -3.5dB de-emphasis */ 72085d5e707SKishon Vijay Abraham I tx_de_emphasis = 1; 72185d5e707SKishon Vijay Abraham I 72285d5e707SKishon Vijay Abraham I /* 72385d5e707SKishon Vijay Abraham I * default to assert utmi_sleep_n and use maximum allowed HIRD 72485d5e707SKishon Vijay Abraham I * threshold value of 0b1100 72585d5e707SKishon Vijay Abraham I */ 72685d5e707SKishon Vijay Abraham I hird_threshold = 12; 72785d5e707SKishon Vijay Abraham I 728*36c87911Swilliam.wu dwc->check_linksts = true; 729*36c87911Swilliam.wu dwc->ts = get_timer(0); 7308e1906a8SKishon Vijay Abraham I dwc->maximum_speed = dwc3_dev->maximum_speed; 7318e1906a8SKishon Vijay Abraham I dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum; 7328e1906a8SKishon Vijay Abraham I if (dwc3_dev->lpm_nyet_threshold) 7338e1906a8SKishon Vijay Abraham I lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold; 7348e1906a8SKishon Vijay Abraham I dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend; 7358e1906a8SKishon Vijay Abraham I if (dwc3_dev->hird_threshold) 7368e1906a8SKishon Vijay Abraham I hird_threshold = dwc3_dev->hird_threshold; 73785d5e707SKishon Vijay Abraham I 7388e1906a8SKishon Vijay Abraham I dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize; 7398e1906a8SKishon Vijay Abraham I dwc->dr_mode = dwc3_dev->dr_mode; 74085d5e707SKishon Vijay Abraham I 7418e1906a8SKishon Vijay Abraham I dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk; 7428e1906a8SKishon Vijay Abraham I dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk; 7438e1906a8SKishon Vijay Abraham I dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk; 7448e1906a8SKishon Vijay Abraham I dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk; 7458e1906a8SKishon Vijay Abraham I dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk; 7468e1906a8SKishon Vijay Abraham I dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk; 7478e1906a8SKishon Vijay Abraham I dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk; 7488e1906a8SKishon Vijay Abraham I dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk; 7498e1906a8SKishon Vijay Abraham I dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk; 7508e1906a8SKishon Vijay Abraham I dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk; 7519c946fbbSFrank Wang dwc->dis_u1u2_quirk = dwc3_dev->dis_u2_susphy_quirk; 75285d5e707SKishon Vijay Abraham I 7538e1906a8SKishon Vijay Abraham I dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk; 7548e1906a8SKishon Vijay Abraham I if (dwc3_dev->tx_de_emphasis) 7558e1906a8SKishon Vijay Abraham I tx_de_emphasis = dwc3_dev->tx_de_emphasis; 75685d5e707SKishon Vijay Abraham I 75785d5e707SKishon Vijay Abraham I /* default to superspeed if no maximum_speed passed */ 75885d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_UNKNOWN) 75985d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_SUPER; 760*36c87911Swilliam.wu else if (dwc->maximum_speed == USB_SPEED_SUPER && 761*36c87911Swilliam.wu rkusb_force_usb2_enabled()) 762*36c87911Swilliam.wu dwc->maximum_speed = USB_SPEED_HIGH; 76385d5e707SKishon Vijay Abraham I 76485d5e707SKishon Vijay Abraham I dwc->lpm_nyet_threshold = lpm_nyet_threshold; 76585d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis = tx_de_emphasis; 76685d5e707SKishon Vijay Abraham I 76785d5e707SKishon Vijay Abraham I dwc->hird_threshold = hird_threshold 76885d5e707SKishon Vijay Abraham I | (dwc->is_utmi_l1_suspend << 4); 76985d5e707SKishon Vijay Abraham I 77073d7b075SFrank Wang dwc->hsphy_mode = dwc3_dev->hsphy_mode; 77173d7b075SFrank Wang 772793d347fSKishon Vijay Abraham I dwc->index = dwc3_dev->index; 773793d347fSKishon Vijay Abraham I 7742878d5a3SWilliam Wu if (dwc3_dev->usb2_phyif_utmi_width) 7752878d5a3SWilliam Wu dwc->usb2_phyif_utmi_width = dwc3_dev->usb2_phyif_utmi_width; 7762878d5a3SWilliam Wu 77741933c04SKever Yang node = fdt_node_offset_by_compatible(blob, -1, 77841933c04SKever Yang "rockchip,rk3399-xhci"); 77941933c04SKever Yang if (node < 0) 78041933c04SKever Yang debug("%s dwc3 node not found\n", __func__); 78141933c04SKever Yang else 78241933c04SKever Yang dwc->usb2_phyif_utmi_width = 78341933c04SKever Yang fdtdec_get_int(blob, node, "snps,phyif-utmi-bits", -1); 78441933c04SKever Yang 78585d5e707SKishon Vijay Abraham I dwc3_cache_hwparams(dwc); 78685d5e707SKishon Vijay Abraham I 78785d5e707SKishon Vijay Abraham I ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 78885d5e707SKishon Vijay Abraham I if (ret) { 78985d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate event buffers\n"); 79071744d0dSKishon Vijay Abraham I return -ENOMEM; 79185d5e707SKishon Vijay Abraham I } 79285d5e707SKishon Vijay Abraham I 79385d5e707SKishon Vijay Abraham I if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) 79485d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_HOST; 79585d5e707SKishon Vijay Abraham I else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) 79685d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_PERIPHERAL; 79785d5e707SKishon Vijay Abraham I 79885d5e707SKishon Vijay Abraham I if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) 79985d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_OTG; 80085d5e707SKishon Vijay Abraham I 80185d5e707SKishon Vijay Abraham I ret = dwc3_core_init(dwc); 80285d5e707SKishon Vijay Abraham I if (ret) { 80385d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize core\n"); 80485d5e707SKishon Vijay Abraham I goto err0; 80585d5e707SKishon Vijay Abraham I } 80685d5e707SKishon Vijay Abraham I 80785d5e707SKishon Vijay Abraham I ret = dwc3_event_buffers_setup(dwc); 80885d5e707SKishon Vijay Abraham I if (ret) { 80985d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to setup event buffers\n"); 81071744d0dSKishon Vijay Abraham I goto err1; 81185d5e707SKishon Vijay Abraham I } 81285d5e707SKishon Vijay Abraham I 81385d5e707SKishon Vijay Abraham I ret = dwc3_core_init_mode(dwc); 81485d5e707SKishon Vijay Abraham I if (ret) 81585d5e707SKishon Vijay Abraham I goto err2; 81685d5e707SKishon Vijay Abraham I 817793d347fSKishon Vijay Abraham I list_add_tail(&dwc->list, &dwc3_list); 818793d347fSKishon Vijay Abraham I 81985d5e707SKishon Vijay Abraham I return 0; 82085d5e707SKishon Vijay Abraham I 82185d5e707SKishon Vijay Abraham I err2: 82285d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 82385d5e707SKishon Vijay Abraham I 82485d5e707SKishon Vijay Abraham I err1: 82585d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 82685d5e707SKishon Vijay Abraham I 82785d5e707SKishon Vijay Abraham I err0: 82885d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 82985d5e707SKishon Vijay Abraham I 83085d5e707SKishon Vijay Abraham I return ret; 83185d5e707SKishon Vijay Abraham I } 83285d5e707SKishon Vijay Abraham I 8338e1906a8SKishon Vijay Abraham I /** 8348e1906a8SKishon Vijay Abraham I * dwc3_uboot_exit - dwc3 core uboot cleanup code 8358e1906a8SKishon Vijay Abraham I * @index: index of this controller 8368e1906a8SKishon Vijay Abraham I * 8378e1906a8SKishon Vijay Abraham I * Performs cleanup of memory allocated in dwc3_uboot_init and other misc 838793d347fSKishon Vijay Abraham I * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller 839793d347fSKishon Vijay Abraham I * should be passed and should match with the index passed in 840793d347fSKishon Vijay Abraham I * dwc3_device during init. 8418e1906a8SKishon Vijay Abraham I * 8428e1906a8SKishon Vijay Abraham I * Generally called from board file. 8438e1906a8SKishon Vijay Abraham I */ 844793d347fSKishon Vijay Abraham I void dwc3_uboot_exit(int index) 84585d5e707SKishon Vijay Abraham I { 846793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 847793d347fSKishon Vijay Abraham I 848793d347fSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 849793d347fSKishon Vijay Abraham I if (dwc->index != index) 850793d347fSKishon Vijay Abraham I continue; 851793d347fSKishon Vijay Abraham I 85285d5e707SKishon Vijay Abraham I dwc3_core_exit_mode(dwc); 85385d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 85485d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 85585d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 856793d347fSKishon Vijay Abraham I list_del(&dwc->list); 8578e1906a8SKishon Vijay Abraham I kfree(dwc->mem); 858793d347fSKishon Vijay Abraham I break; 859793d347fSKishon Vijay Abraham I } 86085d5e707SKishon Vijay Abraham I } 86185d5e707SKishon Vijay Abraham I 86227d3b89dSKishon Vijay Abraham I /** 86327d3b89dSKishon Vijay Abraham I * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt 86427d3b89dSKishon Vijay Abraham I * @index: index of this controller 86527d3b89dSKishon Vijay Abraham I * 86627d3b89dSKishon Vijay Abraham I * Invokes dwc3 gadget interrupts. 86727d3b89dSKishon Vijay Abraham I * 86827d3b89dSKishon Vijay Abraham I * Generally called from board file. 86927d3b89dSKishon Vijay Abraham I */ 87027d3b89dSKishon Vijay Abraham I void dwc3_uboot_handle_interrupt(int index) 87127d3b89dSKishon Vijay Abraham I { 87227d3b89dSKishon Vijay Abraham I struct dwc3 *dwc = NULL; 87327d3b89dSKishon Vijay Abraham I 87427d3b89dSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 87527d3b89dSKishon Vijay Abraham I if (dwc->index != index) 87627d3b89dSKishon Vijay Abraham I continue; 87727d3b89dSKishon Vijay Abraham I 87827d3b89dSKishon Vijay Abraham I dwc3_gadget_uboot_handle_interrupt(dwc); 87927d3b89dSKishon Vijay Abraham I break; 88027d3b89dSKishon Vijay Abraham I } 88127d3b89dSKishon Vijay Abraham I } 88227d3b89dSKishon Vijay Abraham I 88385d5e707SKishon Vijay Abraham I MODULE_ALIAS("platform:dwc3"); 88485d5e707SKishon Vijay Abraham I MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 88585d5e707SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 88685d5e707SKishon Vijay Abraham I MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 887434f82edSMugunthan V N 88872d48a52SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) 88972d48a52SJean-Jacques Hiblot int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) 89072d48a52SJean-Jacques Hiblot { 89172d48a52SJean-Jacques Hiblot int i, ret, count; 89272d48a52SJean-Jacques Hiblot struct phy *usb_phys; 89372d48a52SJean-Jacques Hiblot 89472d48a52SJean-Jacques Hiblot /* Return if no phy declared */ 89572d48a52SJean-Jacques Hiblot if (!dev_read_prop(dev, "phys", NULL)) 89672d48a52SJean-Jacques Hiblot return 0; 89772d48a52SJean-Jacques Hiblot count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); 89872d48a52SJean-Jacques Hiblot if (count <= 0) 89972d48a52SJean-Jacques Hiblot return count; 90072d48a52SJean-Jacques Hiblot 90172d48a52SJean-Jacques Hiblot usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), 90272d48a52SJean-Jacques Hiblot GFP_KERNEL); 90372d48a52SJean-Jacques Hiblot if (!usb_phys) 90472d48a52SJean-Jacques Hiblot return -ENOMEM; 90572d48a52SJean-Jacques Hiblot 90672d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 90772d48a52SJean-Jacques Hiblot ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); 90872d48a52SJean-Jacques Hiblot if (ret && ret != -ENOENT) { 90972d48a52SJean-Jacques Hiblot pr_err("Failed to get USB PHY%d for %s\n", 91072d48a52SJean-Jacques Hiblot i, dev->name); 91172d48a52SJean-Jacques Hiblot return ret; 91272d48a52SJean-Jacques Hiblot } 91372d48a52SJean-Jacques Hiblot } 91472d48a52SJean-Jacques Hiblot 91572d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 91672d48a52SJean-Jacques Hiblot ret = generic_phy_init(&usb_phys[i]); 91772d48a52SJean-Jacques Hiblot if (ret) { 91872d48a52SJean-Jacques Hiblot pr_err("Can't init USB PHY%d for %s\n", 91972d48a52SJean-Jacques Hiblot i, dev->name); 92072d48a52SJean-Jacques Hiblot goto phys_init_err; 92172d48a52SJean-Jacques Hiblot } 92272d48a52SJean-Jacques Hiblot } 92372d48a52SJean-Jacques Hiblot 92472d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 92572d48a52SJean-Jacques Hiblot ret = generic_phy_power_on(&usb_phys[i]); 92672d48a52SJean-Jacques Hiblot if (ret) { 92772d48a52SJean-Jacques Hiblot pr_err("Can't power USB PHY%d for %s\n", 92872d48a52SJean-Jacques Hiblot i, dev->name); 92972d48a52SJean-Jacques Hiblot goto phys_poweron_err; 93072d48a52SJean-Jacques Hiblot } 93172d48a52SJean-Jacques Hiblot } 93272d48a52SJean-Jacques Hiblot 93372d48a52SJean-Jacques Hiblot *array = usb_phys; 93472d48a52SJean-Jacques Hiblot *num_phys = count; 93572d48a52SJean-Jacques Hiblot return 0; 93672d48a52SJean-Jacques Hiblot 93772d48a52SJean-Jacques Hiblot phys_poweron_err: 93872d48a52SJean-Jacques Hiblot for (i = count - 1; i >= 0; i--) 93972d48a52SJean-Jacques Hiblot generic_phy_power_off(&usb_phys[i]); 94072d48a52SJean-Jacques Hiblot 94172d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) 94272d48a52SJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 94372d48a52SJean-Jacques Hiblot 94472d48a52SJean-Jacques Hiblot return ret; 94572d48a52SJean-Jacques Hiblot 94672d48a52SJean-Jacques Hiblot phys_init_err: 94772d48a52SJean-Jacques Hiblot for (; i >= 0; i--) 94872d48a52SJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 94972d48a52SJean-Jacques Hiblot 95072d48a52SJean-Jacques Hiblot return ret; 95172d48a52SJean-Jacques Hiblot } 95272d48a52SJean-Jacques Hiblot 95372d48a52SJean-Jacques Hiblot int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) 95472d48a52SJean-Jacques Hiblot { 95572d48a52SJean-Jacques Hiblot int i, ret; 95672d48a52SJean-Jacques Hiblot 95772d48a52SJean-Jacques Hiblot for (i = 0; i < num_phys; i++) { 95872d48a52SJean-Jacques Hiblot if (!generic_phy_valid(&usb_phys[i])) 95972d48a52SJean-Jacques Hiblot continue; 96072d48a52SJean-Jacques Hiblot 96172d48a52SJean-Jacques Hiblot ret = generic_phy_power_off(&usb_phys[i]); 96272d48a52SJean-Jacques Hiblot ret |= generic_phy_exit(&usb_phys[i]); 96372d48a52SJean-Jacques Hiblot if (ret) { 96472d48a52SJean-Jacques Hiblot pr_err("Can't shutdown USB PHY%d for %s\n", 96572d48a52SJean-Jacques Hiblot i, dev->name); 96672d48a52SJean-Jacques Hiblot } 96772d48a52SJean-Jacques Hiblot } 96872d48a52SJean-Jacques Hiblot 96972d48a52SJean-Jacques Hiblot return 0; 97072d48a52SJean-Jacques Hiblot } 97172d48a52SJean-Jacques Hiblot #endif 97272d48a52SJean-Jacques Hiblot 973f7133ecdSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB) 974eedade57SJean-Jacques Hiblot void dwc3_of_parse(struct dwc3 *dwc) 975eedade57SJean-Jacques Hiblot { 976eedade57SJean-Jacques Hiblot const u8 *tmp; 977eedade57SJean-Jacques Hiblot struct udevice *dev = dwc->dev; 978eedade57SJean-Jacques Hiblot u8 lpm_nyet_threshold; 979eedade57SJean-Jacques Hiblot u8 tx_de_emphasis; 980eedade57SJean-Jacques Hiblot u8 hird_threshold; 981eedade57SJean-Jacques Hiblot 982eedade57SJean-Jacques Hiblot /* default to highest possible threshold */ 983eedade57SJean-Jacques Hiblot lpm_nyet_threshold = 0xff; 984eedade57SJean-Jacques Hiblot 985eedade57SJean-Jacques Hiblot /* default to -3.5dB de-emphasis */ 986eedade57SJean-Jacques Hiblot tx_de_emphasis = 1; 987eedade57SJean-Jacques Hiblot 988eedade57SJean-Jacques Hiblot /* 989eedade57SJean-Jacques Hiblot * default to assert utmi_sleep_n and use maximum allowed HIRD 990eedade57SJean-Jacques Hiblot * threshold value of 0b1100 991eedade57SJean-Jacques Hiblot */ 992eedade57SJean-Jacques Hiblot hird_threshold = 12; 993eedade57SJean-Jacques Hiblot 99473d7b075SFrank Wang dwc->hsphy_mode = usb_get_phy_mode(dev->node); 99573d7b075SFrank Wang 996eedade57SJean-Jacques Hiblot dwc->has_lpm_erratum = dev_read_bool(dev, 997eedade57SJean-Jacques Hiblot "snps,has-lpm-erratum"); 998eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1); 999eedade57SJean-Jacques Hiblot if (tmp) 1000eedade57SJean-Jacques Hiblot lpm_nyet_threshold = *tmp; 1001eedade57SJean-Jacques Hiblot 1002eedade57SJean-Jacques Hiblot dwc->is_utmi_l1_suspend = dev_read_bool(dev, 1003eedade57SJean-Jacques Hiblot "snps,is-utmi-l1-suspend"); 1004eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1); 1005eedade57SJean-Jacques Hiblot if (tmp) 1006eedade57SJean-Jacques Hiblot hird_threshold = *tmp; 1007eedade57SJean-Jacques Hiblot 1008eedade57SJean-Jacques Hiblot dwc->disable_scramble_quirk = dev_read_bool(dev, 1009eedade57SJean-Jacques Hiblot "snps,disable_scramble_quirk"); 1010eedade57SJean-Jacques Hiblot dwc->u2exit_lfps_quirk = dev_read_bool(dev, 1011eedade57SJean-Jacques Hiblot "snps,u2exit_lfps_quirk"); 1012eedade57SJean-Jacques Hiblot dwc->u2ss_inp3_quirk = dev_read_bool(dev, 1013eedade57SJean-Jacques Hiblot "snps,u2ss_inp3_quirk"); 1014eedade57SJean-Jacques Hiblot dwc->req_p1p2p3_quirk = dev_read_bool(dev, 1015eedade57SJean-Jacques Hiblot "snps,req_p1p2p3_quirk"); 1016eedade57SJean-Jacques Hiblot dwc->del_p1p2p3_quirk = dev_read_bool(dev, 1017eedade57SJean-Jacques Hiblot "snps,del_p1p2p3_quirk"); 1018eedade57SJean-Jacques Hiblot dwc->del_phy_power_chg_quirk = dev_read_bool(dev, 1019eedade57SJean-Jacques Hiblot "snps,del_phy_power_chg_quirk"); 1020eedade57SJean-Jacques Hiblot dwc->lfps_filter_quirk = dev_read_bool(dev, 1021eedade57SJean-Jacques Hiblot "snps,lfps_filter_quirk"); 1022eedade57SJean-Jacques Hiblot dwc->rx_detect_poll_quirk = dev_read_bool(dev, 1023eedade57SJean-Jacques Hiblot "snps,rx_detect_poll_quirk"); 1024eedade57SJean-Jacques Hiblot dwc->dis_u3_susphy_quirk = dev_read_bool(dev, 1025eedade57SJean-Jacques Hiblot "snps,dis_u3_susphy_quirk"); 1026eedade57SJean-Jacques Hiblot dwc->dis_u2_susphy_quirk = dev_read_bool(dev, 1027eedade57SJean-Jacques Hiblot "snps,dis_u2_susphy_quirk"); 1028f4acaed3SFrank Wang dwc->dis_enblslpm_quirk = dev_read_bool(dev, 1029f4acaed3SFrank Wang "snps,dis_enblslpm_quirk"); 1030efc9f556SFrank Wang dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev, 1031efc9f556SFrank Wang "snps,dis-u2-freeclk-exists-quirk"); 1032eedade57SJean-Jacques Hiblot dwc->tx_de_emphasis_quirk = dev_read_bool(dev, 1033eedade57SJean-Jacques Hiblot "snps,tx_de_emphasis_quirk"); 1034eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1); 1035eedade57SJean-Jacques Hiblot if (tmp) 1036eedade57SJean-Jacques Hiblot tx_de_emphasis = *tmp; 1037eedade57SJean-Jacques Hiblot 1038eedade57SJean-Jacques Hiblot dwc->lpm_nyet_threshold = lpm_nyet_threshold; 1039eedade57SJean-Jacques Hiblot dwc->tx_de_emphasis = tx_de_emphasis; 1040eedade57SJean-Jacques Hiblot 1041eedade57SJean-Jacques Hiblot dwc->hird_threshold = hird_threshold 1042eedade57SJean-Jacques Hiblot | (dwc->is_utmi_l1_suspend << 4); 1043eedade57SJean-Jacques Hiblot } 1044eedade57SJean-Jacques Hiblot 1045434f82edSMugunthan V N int dwc3_init(struct dwc3 *dwc) 1046434f82edSMugunthan V N { 1047434f82edSMugunthan V N int ret; 1048434f82edSMugunthan V N 1049434f82edSMugunthan V N dwc3_cache_hwparams(dwc); 1050434f82edSMugunthan V N 1051434f82edSMugunthan V N ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 1052434f82edSMugunthan V N if (ret) { 1053434f82edSMugunthan V N dev_err(dwc->dev, "failed to allocate event buffers\n"); 1054434f82edSMugunthan V N return -ENOMEM; 1055434f82edSMugunthan V N } 1056434f82edSMugunthan V N 1057434f82edSMugunthan V N ret = dwc3_core_init(dwc); 1058434f82edSMugunthan V N if (ret) { 1059434f82edSMugunthan V N dev_err(dev, "failed to initialize core\n"); 1060434f82edSMugunthan V N goto core_fail; 1061434f82edSMugunthan V N } 1062434f82edSMugunthan V N 1063434f82edSMugunthan V N ret = dwc3_event_buffers_setup(dwc); 1064434f82edSMugunthan V N if (ret) { 1065434f82edSMugunthan V N dev_err(dwc->dev, "failed to setup event buffers\n"); 1066434f82edSMugunthan V N goto event_fail; 1067434f82edSMugunthan V N } 1068434f82edSMugunthan V N 1069434f82edSMugunthan V N ret = dwc3_core_init_mode(dwc); 1070434f82edSMugunthan V N if (ret) 1071434f82edSMugunthan V N goto mode_fail; 1072434f82edSMugunthan V N 1073434f82edSMugunthan V N return 0; 1074434f82edSMugunthan V N 1075434f82edSMugunthan V N mode_fail: 1076434f82edSMugunthan V N dwc3_event_buffers_cleanup(dwc); 1077434f82edSMugunthan V N 1078434f82edSMugunthan V N event_fail: 1079434f82edSMugunthan V N dwc3_core_exit(dwc); 1080434f82edSMugunthan V N 1081434f82edSMugunthan V N core_fail: 1082434f82edSMugunthan V N dwc3_free_event_buffers(dwc); 1083434f82edSMugunthan V N 1084434f82edSMugunthan V N return ret; 1085434f82edSMugunthan V N } 1086434f82edSMugunthan V N 1087434f82edSMugunthan V N void dwc3_remove(struct dwc3 *dwc) 1088434f82edSMugunthan V N { 1089434f82edSMugunthan V N dwc3_core_exit_mode(dwc); 1090434f82edSMugunthan V N dwc3_event_buffers_cleanup(dwc); 1091434f82edSMugunthan V N dwc3_free_event_buffers(dwc); 1092434f82edSMugunthan V N dwc3_core_exit(dwc); 1093434f82edSMugunthan V N kfree(dwc->mem); 1094434f82edSMugunthan V N } 1095434f82edSMugunthan V N #endif 1096