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" 3385d5e707SKishon Vijay Abraham I 3441933c04SKever Yang DECLARE_GLOBAL_DATA_PTR; 3541933c04SKever Yang 36793d347fSKishon Vijay Abraham I static LIST_HEAD(dwc3_list); 3785d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 3885d5e707SKishon Vijay Abraham I 397e9cb796SJoonyoung Shim static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) 4085d5e707SKishon Vijay Abraham I { 4185d5e707SKishon Vijay Abraham I u32 reg; 4285d5e707SKishon Vijay Abraham I 4385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 4485d5e707SKishon Vijay Abraham I reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); 4585d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_PRTCAPDIR(mode); 4685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 4785d5e707SKishon Vijay Abraham I } 4885d5e707SKishon Vijay Abraham I 4985d5e707SKishon Vijay Abraham I /** 5085d5e707SKishon Vijay Abraham I * dwc3_core_soft_reset - Issues core soft reset and PHY reset 5185d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 5285d5e707SKishon Vijay Abraham I */ 5385d5e707SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc) 5485d5e707SKishon Vijay Abraham I { 5585d5e707SKishon Vijay Abraham I u32 reg; 5685d5e707SKishon Vijay Abraham I 5785d5e707SKishon Vijay Abraham I /* Before Resetting PHY, put Core in Reset */ 5885d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 5985d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_CORESOFTRESET; 6085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 6185d5e707SKishon Vijay Abraham I 6285d5e707SKishon Vijay Abraham I /* Assert USB3 PHY reset */ 6385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 6485d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; 6585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 6685d5e707SKishon Vijay Abraham I 6785d5e707SKishon Vijay Abraham I /* Assert USB2 PHY reset */ 6885d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 6985d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; 7085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 7185d5e707SKishon Vijay Abraham I 7285d5e707SKishon Vijay Abraham I mdelay(100); 7385d5e707SKishon Vijay Abraham I 7485d5e707SKishon Vijay Abraham I /* Clear USB3 PHY reset */ 7585d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 7685d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; 7785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 7885d5e707SKishon Vijay Abraham I 7985d5e707SKishon Vijay Abraham I /* Clear USB2 PHY reset */ 8085d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 8185d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; 8285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 8385d5e707SKishon Vijay Abraham I 8485d5e707SKishon Vijay Abraham I mdelay(100); 8585d5e707SKishon Vijay Abraham I 8685d5e707SKishon Vijay Abraham I /* After PHYs are stable we can take Core out of reset state */ 8785d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 8885d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_CORESOFTRESET; 8985d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 9085d5e707SKishon Vijay Abraham I 9185d5e707SKishon Vijay Abraham I return 0; 9285d5e707SKishon Vijay Abraham I } 9385d5e707SKishon Vijay Abraham I 9485d5e707SKishon Vijay Abraham I /** 9585d5e707SKishon Vijay Abraham I * dwc3_free_one_event_buffer - Frees one event buffer 9685d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 9785d5e707SKishon Vijay Abraham I * @evt: Pointer to event buffer to be freed 9885d5e707SKishon Vijay Abraham I */ 9985d5e707SKishon Vijay Abraham I static void dwc3_free_one_event_buffer(struct dwc3 *dwc, 10085d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt) 10185d5e707SKishon Vijay Abraham I { 10271744d0dSKishon Vijay Abraham I dma_free_coherent(evt->buf); 10385d5e707SKishon Vijay Abraham I } 10485d5e707SKishon Vijay Abraham I 10585d5e707SKishon Vijay Abraham I /** 10685d5e707SKishon Vijay Abraham I * dwc3_alloc_one_event_buffer - Allocates one event buffer structure 10785d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 10885d5e707SKishon Vijay Abraham I * @length: size of the event buffer 10985d5e707SKishon Vijay Abraham I * 11085d5e707SKishon Vijay Abraham I * Returns a pointer to the allocated event buffer structure on success 11185d5e707SKishon Vijay Abraham I * otherwise ERR_PTR(errno). 11285d5e707SKishon Vijay Abraham I */ 11385d5e707SKishon Vijay Abraham I static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, 11485d5e707SKishon Vijay Abraham I unsigned length) 11585d5e707SKishon Vijay Abraham I { 11685d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 11785d5e707SKishon Vijay Abraham I 118b6985a21SMugunthan V N evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt), 119b6985a21SMugunthan V N GFP_KERNEL); 12085d5e707SKishon Vijay Abraham I if (!evt) 12185d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 12285d5e707SKishon Vijay Abraham I 12385d5e707SKishon Vijay Abraham I evt->dwc = dwc; 12485d5e707SKishon Vijay Abraham I evt->length = length; 12571744d0dSKishon Vijay Abraham I evt->buf = dma_alloc_coherent(length, 12671744d0dSKishon Vijay Abraham I (unsigned long *)&evt->dma); 12785d5e707SKishon Vijay Abraham I if (!evt->buf) 12885d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 12985d5e707SKishon Vijay Abraham I 130889239d6SPhilipp Tomsich dwc3_flush_cache((uintptr_t)evt->buf, evt->length); 131889239d6SPhilipp Tomsich 13285d5e707SKishon Vijay Abraham I return evt; 13385d5e707SKishon Vijay Abraham I } 13485d5e707SKishon Vijay Abraham I 13585d5e707SKishon Vijay Abraham I /** 13685d5e707SKishon Vijay Abraham I * dwc3_free_event_buffers - frees all allocated event buffers 13785d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 13885d5e707SKishon Vijay Abraham I */ 13985d5e707SKishon Vijay Abraham I static void dwc3_free_event_buffers(struct dwc3 *dwc) 14085d5e707SKishon Vijay Abraham I { 14185d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 14285d5e707SKishon Vijay Abraham I int i; 14385d5e707SKishon Vijay Abraham I 14485d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) { 14585d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[i]; 14685d5e707SKishon Vijay Abraham I if (evt) 14785d5e707SKishon Vijay Abraham I dwc3_free_one_event_buffer(dwc, evt); 14885d5e707SKishon Vijay Abraham I } 14985d5e707SKishon Vijay Abraham I } 15085d5e707SKishon Vijay Abraham I 15185d5e707SKishon Vijay Abraham I /** 15285d5e707SKishon Vijay Abraham I * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length 15385d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 15485d5e707SKishon Vijay Abraham I * @length: size of event buffer 15585d5e707SKishon Vijay Abraham I * 15685d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. In the error case, dwc 15785d5e707SKishon Vijay Abraham I * may contain some buffers allocated but not all which were requested. 15885d5e707SKishon Vijay Abraham I */ 15985d5e707SKishon Vijay Abraham I static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) 16085d5e707SKishon Vijay Abraham I { 16185d5e707SKishon Vijay Abraham I int num; 16285d5e707SKishon Vijay Abraham I int i; 16385d5e707SKishon Vijay Abraham I 16485d5e707SKishon Vijay Abraham I num = DWC3_NUM_INT(dwc->hwparams.hwparams1); 16585d5e707SKishon Vijay Abraham I dwc->num_event_buffers = num; 16685d5e707SKishon Vijay Abraham I 167526a50f8SKishon Vijay Abraham I dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE, 168526a50f8SKishon Vijay Abraham I sizeof(*dwc->ev_buffs) * num); 16985d5e707SKishon Vijay Abraham I if (!dwc->ev_buffs) 17085d5e707SKishon Vijay Abraham I return -ENOMEM; 17185d5e707SKishon Vijay Abraham I 17285d5e707SKishon Vijay Abraham I for (i = 0; i < num; i++) { 17385d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 17485d5e707SKishon Vijay Abraham I 17585d5e707SKishon Vijay Abraham I evt = dwc3_alloc_one_event_buffer(dwc, length); 17685d5e707SKishon Vijay Abraham I if (IS_ERR(evt)) { 17785d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "can't allocate event buffer\n"); 17885d5e707SKishon Vijay Abraham I return PTR_ERR(evt); 17985d5e707SKishon Vijay Abraham I } 18085d5e707SKishon Vijay Abraham I dwc->ev_buffs[i] = evt; 18185d5e707SKishon Vijay Abraham I } 18285d5e707SKishon Vijay Abraham I 18385d5e707SKishon Vijay Abraham I return 0; 18485d5e707SKishon Vijay Abraham I } 18585d5e707SKishon Vijay Abraham I 18685d5e707SKishon Vijay Abraham I /** 18785d5e707SKishon Vijay Abraham I * dwc3_event_buffers_setup - setup our allocated event buffers 18885d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 18985d5e707SKishon Vijay Abraham I * 19085d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 19185d5e707SKishon Vijay Abraham I */ 19285d5e707SKishon Vijay Abraham I static int dwc3_event_buffers_setup(struct dwc3 *dwc) 19385d5e707SKishon Vijay Abraham I { 19485d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 19585d5e707SKishon Vijay Abraham I int n; 19685d5e707SKishon Vijay Abraham I 19785d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 19885d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 19985d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", 20085d5e707SKishon Vijay Abraham I evt->buf, (unsigned long long) evt->dma, 20185d5e707SKishon Vijay Abraham I evt->length); 20285d5e707SKishon Vijay Abraham I 20385d5e707SKishon Vijay Abraham I evt->lpos = 0; 20485d5e707SKishon Vijay Abraham I 20585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 20685d5e707SKishon Vijay Abraham I lower_32_bits(evt->dma)); 20785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 20885d5e707SKishon Vijay Abraham I upper_32_bits(evt->dma)); 20985d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 21085d5e707SKishon Vijay Abraham I DWC3_GEVNTSIZ_SIZE(evt->length)); 21185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 21285d5e707SKishon Vijay Abraham I } 21385d5e707SKishon Vijay Abraham I 21485d5e707SKishon Vijay Abraham I return 0; 21585d5e707SKishon Vijay Abraham I } 21685d5e707SKishon Vijay Abraham I 21785d5e707SKishon Vijay Abraham I static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) 21885d5e707SKishon Vijay Abraham I { 21985d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 22085d5e707SKishon Vijay Abraham I int n; 22185d5e707SKishon Vijay Abraham I 22285d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 22385d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 22485d5e707SKishon Vijay Abraham I 22585d5e707SKishon Vijay Abraham I evt->lpos = 0; 22685d5e707SKishon Vijay Abraham I 22785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); 22885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); 22985d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK 23085d5e707SKishon Vijay Abraham I | DWC3_GEVNTSIZ_SIZE(0)); 23185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 23285d5e707SKishon Vijay Abraham I } 23385d5e707SKishon Vijay Abraham I } 23485d5e707SKishon Vijay Abraham I 23585d5e707SKishon Vijay Abraham I static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) 23685d5e707SKishon Vijay Abraham I { 23785d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 23885d5e707SKishon Vijay Abraham I return 0; 23985d5e707SKishon Vijay Abraham I 24085d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 24185d5e707SKishon Vijay Abraham I return 0; 24285d5e707SKishon Vijay Abraham I 24385d5e707SKishon Vijay Abraham I dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, 24485d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); 24585d5e707SKishon Vijay Abraham I if (!dwc->scratchbuf) 24685d5e707SKishon Vijay Abraham I return -ENOMEM; 24785d5e707SKishon Vijay Abraham I 24885d5e707SKishon Vijay Abraham I return 0; 24985d5e707SKishon Vijay Abraham I } 25085d5e707SKishon Vijay Abraham I 25185d5e707SKishon Vijay Abraham I static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) 25285d5e707SKishon Vijay Abraham I { 25385d5e707SKishon Vijay Abraham I dma_addr_t scratch_addr; 25485d5e707SKishon Vijay Abraham I u32 param; 25585d5e707SKishon Vijay Abraham I int ret; 25685d5e707SKishon Vijay Abraham I 25785d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 25885d5e707SKishon Vijay Abraham I return 0; 25985d5e707SKishon Vijay Abraham I 26085d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 26185d5e707SKishon Vijay Abraham I return 0; 26285d5e707SKishon Vijay Abraham I 26371744d0dSKishon Vijay Abraham I scratch_addr = dma_map_single(dwc->scratchbuf, 26485d5e707SKishon Vijay Abraham I dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, 26585d5e707SKishon Vijay Abraham I DMA_BIDIRECTIONAL); 26685d5e707SKishon Vijay Abraham I if (dma_mapping_error(dwc->dev, scratch_addr)) { 26785d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to map scratch buffer\n"); 26885d5e707SKishon Vijay Abraham I ret = -EFAULT; 26985d5e707SKishon Vijay Abraham I goto err0; 27085d5e707SKishon Vijay Abraham I } 27185d5e707SKishon Vijay Abraham I 27285d5e707SKishon Vijay Abraham I dwc->scratch_addr = scratch_addr; 27385d5e707SKishon Vijay Abraham I 27485d5e707SKishon Vijay Abraham I param = lower_32_bits(scratch_addr); 27585d5e707SKishon Vijay Abraham I 27685d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 27785d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); 27885d5e707SKishon Vijay Abraham I if (ret < 0) 27985d5e707SKishon Vijay Abraham I goto err1; 28085d5e707SKishon Vijay Abraham I 28185d5e707SKishon Vijay Abraham I param = upper_32_bits(scratch_addr); 28285d5e707SKishon Vijay Abraham I 28385d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 28485d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); 28585d5e707SKishon Vijay Abraham I if (ret < 0) 28685d5e707SKishon Vijay Abraham I goto err1; 28785d5e707SKishon Vijay Abraham I 28885d5e707SKishon Vijay Abraham I return 0; 28985d5e707SKishon Vijay Abraham I 29085d5e707SKishon Vijay Abraham I err1: 29101c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 29285d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 29385d5e707SKishon Vijay Abraham I 29485d5e707SKishon Vijay Abraham I err0: 29585d5e707SKishon Vijay Abraham I return ret; 29685d5e707SKishon Vijay Abraham I } 29785d5e707SKishon Vijay Abraham I 29885d5e707SKishon Vijay Abraham I static void dwc3_free_scratch_buffers(struct dwc3 *dwc) 29985d5e707SKishon Vijay Abraham I { 30085d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 30185d5e707SKishon Vijay Abraham I return; 30285d5e707SKishon Vijay Abraham I 30385d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 30485d5e707SKishon Vijay Abraham I return; 30585d5e707SKishon Vijay Abraham I 30601c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 30785d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 30885d5e707SKishon Vijay Abraham I kfree(dwc->scratchbuf); 30985d5e707SKishon Vijay Abraham I } 31085d5e707SKishon Vijay Abraham I 31185d5e707SKishon Vijay Abraham I static void dwc3_core_num_eps(struct dwc3 *dwc) 31285d5e707SKishon Vijay Abraham I { 31385d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 31485d5e707SKishon Vijay Abraham I 31585d5e707SKishon Vijay Abraham I dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); 31685d5e707SKishon Vijay Abraham I dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; 31785d5e707SKishon Vijay Abraham I 31885d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", 31985d5e707SKishon Vijay Abraham I dwc->num_in_eps, dwc->num_out_eps); 32085d5e707SKishon Vijay Abraham I } 32185d5e707SKishon Vijay Abraham I 32285d5e707SKishon Vijay Abraham I static void dwc3_cache_hwparams(struct dwc3 *dwc) 32385d5e707SKishon Vijay Abraham I { 32485d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 32585d5e707SKishon Vijay Abraham I 32685d5e707SKishon Vijay Abraham I parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); 32785d5e707SKishon Vijay Abraham I parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); 32885d5e707SKishon Vijay Abraham I parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); 32985d5e707SKishon Vijay Abraham I parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); 33085d5e707SKishon Vijay Abraham I parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); 33185d5e707SKishon Vijay Abraham I parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); 33285d5e707SKishon Vijay Abraham I parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); 33385d5e707SKishon Vijay Abraham I parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); 33485d5e707SKishon Vijay Abraham I parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); 33585d5e707SKishon Vijay Abraham I } 33685d5e707SKishon Vijay Abraham I 33773d7b075SFrank Wang static void dwc3_hsphy_mode_setup(struct dwc3 *dwc) 33873d7b075SFrank Wang { 33973d7b075SFrank Wang enum usb_phy_interface hsphy_mode = dwc->hsphy_mode; 34073d7b075SFrank Wang u32 reg; 34173d7b075SFrank Wang 34273d7b075SFrank Wang /* Set dwc3 usb2 phy config */ 34373d7b075SFrank Wang reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 34473d7b075SFrank Wang 34573d7b075SFrank Wang switch (hsphy_mode) { 34673d7b075SFrank Wang case USBPHY_INTERFACE_MODE_UTMI: 34773d7b075SFrank Wang reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 34873d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 34973d7b075SFrank Wang reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | 35073d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); 35173d7b075SFrank Wang break; 35273d7b075SFrank Wang case USBPHY_INTERFACE_MODE_UTMIW: 35373d7b075SFrank Wang reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 35473d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 35573d7b075SFrank Wang reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | 35673d7b075SFrank Wang DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); 35773d7b075SFrank Wang break; 35873d7b075SFrank Wang default: 35973d7b075SFrank Wang break; 36073d7b075SFrank Wang } 36173d7b075SFrank Wang 36273d7b075SFrank Wang dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 36373d7b075SFrank Wang } 36473d7b075SFrank Wang 36585d5e707SKishon Vijay Abraham I /** 36685d5e707SKishon Vijay Abraham I * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core 36785d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 36885d5e707SKishon Vijay Abraham I */ 36985d5e707SKishon Vijay Abraham I static void dwc3_phy_setup(struct dwc3 *dwc) 37085d5e707SKishon Vijay Abraham I { 37185d5e707SKishon Vijay Abraham I u32 reg; 37285d5e707SKishon Vijay Abraham I 37385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 37485d5e707SKishon Vijay Abraham I 37585d5e707SKishon Vijay Abraham I /* 37685d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY 37785d5e707SKishon Vijay Abraham I * to '0' during coreConsultant configuration. So default value 37885d5e707SKishon Vijay Abraham I * will be '0' when the core is reset. Application needs to set it 37985d5e707SKishon Vijay Abraham I * to '1' after the core initialization is completed. 38085d5e707SKishon Vijay Abraham I */ 38185d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 38285d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_SUSPHY; 38385d5e707SKishon Vijay Abraham I 38485d5e707SKishon Vijay Abraham I if (dwc->u2ss_inp3_quirk) 38585d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; 38685d5e707SKishon Vijay Abraham I 38785d5e707SKishon Vijay Abraham I if (dwc->req_p1p2p3_quirk) 38885d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; 38985d5e707SKishon Vijay Abraham I 39085d5e707SKishon Vijay Abraham I if (dwc->del_p1p2p3_quirk) 39185d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; 39285d5e707SKishon Vijay Abraham I 39385d5e707SKishon Vijay Abraham I if (dwc->del_phy_power_chg_quirk) 39485d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; 39585d5e707SKishon Vijay Abraham I 39685d5e707SKishon Vijay Abraham I if (dwc->lfps_filter_quirk) 39785d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_LFPSFILT; 39885d5e707SKishon Vijay Abraham I 39985d5e707SKishon Vijay Abraham I if (dwc->rx_detect_poll_quirk) 40085d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; 40185d5e707SKishon Vijay Abraham I 40285d5e707SKishon Vijay Abraham I if (dwc->tx_de_emphasis_quirk) 40385d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); 40485d5e707SKishon Vijay Abraham I 40585d5e707SKishon Vijay Abraham I if (dwc->dis_u3_susphy_quirk) 40685d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 40785d5e707SKishon Vijay Abraham I 40885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 40985d5e707SKishon Vijay Abraham I 41073d7b075SFrank Wang dwc3_hsphy_mode_setup(dwc); 41173d7b075SFrank Wang 41285d5e707SKishon Vijay Abraham I mdelay(100); 41385d5e707SKishon Vijay Abraham I 41485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 41585d5e707SKishon Vijay Abraham I 41685d5e707SKishon Vijay Abraham I /* 41785d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to 41885d5e707SKishon Vijay Abraham I * '0' during coreConsultant configuration. So default value will 41985d5e707SKishon Vijay Abraham I * be '0' when the core is reset. Application needs to set it to 42085d5e707SKishon Vijay Abraham I * '1' after the core initialization is completed. 42185d5e707SKishon Vijay Abraham I */ 42285d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 42385d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_SUSPHY; 42485d5e707SKishon Vijay Abraham I 42585d5e707SKishon Vijay Abraham I if (dwc->dis_u2_susphy_quirk) 42685d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 42785d5e707SKishon Vijay Abraham I 428f4acaed3SFrank Wang if (dwc->dis_enblslpm_quirk) 429f4acaed3SFrank Wang reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; 430f4acaed3SFrank Wang 431efc9f556SFrank Wang if (dwc->dis_u2_freeclk_exists_quirk) 432efc9f556SFrank Wang reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; 433efc9f556SFrank Wang 43441933c04SKever Yang if (dwc->usb2_phyif_utmi_width == 16) { 4352136741eSJagan Teki reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | 4362136741eSJagan Teki DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); 4372136741eSJagan Teki reg |= DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); 4382136741eSJagan Teki reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT); 43941933c04SKever Yang } 44085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 44185d5e707SKishon Vijay Abraham I 44285d5e707SKishon Vijay Abraham I mdelay(100); 44385d5e707SKishon Vijay Abraham I } 44485d5e707SKishon Vijay Abraham I 44585d5e707SKishon Vijay Abraham I /** 44685d5e707SKishon Vijay Abraham I * dwc3_core_init - Low-level initialization of DWC3 Core 44785d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 44885d5e707SKishon Vijay Abraham I * 44985d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 45085d5e707SKishon Vijay Abraham I */ 45185d5e707SKishon Vijay Abraham I static int dwc3_core_init(struct dwc3 *dwc) 45285d5e707SKishon Vijay Abraham I { 45385d5e707SKishon Vijay Abraham I unsigned long timeout; 45485d5e707SKishon Vijay Abraham I u32 hwparams4 = dwc->hwparams.hwparams4; 45585d5e707SKishon Vijay Abraham I u32 reg; 45685d5e707SKishon Vijay Abraham I int ret; 45785d5e707SKishon Vijay Abraham I 45885d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); 45985d5e707SKishon Vijay Abraham I /* This should read as U3 followed by revision number */ 46085d5e707SKishon Vijay Abraham I if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { 46185d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); 46285d5e707SKishon Vijay Abraham I ret = -ENODEV; 46385d5e707SKishon Vijay Abraham I goto err0; 46485d5e707SKishon Vijay Abraham I } 46585d5e707SKishon Vijay Abraham I dwc->revision = reg; 46685d5e707SKishon Vijay Abraham I 46785d5e707SKishon Vijay Abraham I /* Handle USB2.0-only core configuration */ 46885d5e707SKishon Vijay Abraham I if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == 46985d5e707SKishon Vijay Abraham I DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { 47085d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_SUPER) 47185d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_HIGH; 47285d5e707SKishon Vijay Abraham I } 47385d5e707SKishon Vijay Abraham I 47485d5e707SKishon Vijay Abraham I /* issue device SoftReset too */ 47571744d0dSKishon Vijay Abraham I timeout = 5000; 47685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); 47771744d0dSKishon Vijay Abraham I while (timeout--) { 47885d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 47985d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DCTL_CSFTRST)) 48085d5e707SKishon Vijay Abraham I break; 48171744d0dSKishon Vijay Abraham I }; 48285d5e707SKishon Vijay Abraham I 48371744d0dSKishon Vijay Abraham I if (!timeout) { 48485d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Reset Timed Out\n"); 48585d5e707SKishon Vijay Abraham I ret = -ETIMEDOUT; 48685d5e707SKishon Vijay Abraham I goto err0; 48785d5e707SKishon Vijay Abraham I } 48885d5e707SKishon Vijay Abraham I 48985d5e707SKishon Vijay Abraham I ret = dwc3_core_soft_reset(dwc); 49085d5e707SKishon Vijay Abraham I if (ret) 49185d5e707SKishon Vijay Abraham I goto err0; 49285d5e707SKishon Vijay Abraham I 493*3b2dd5deSWilliam Wu if (dwc->revision >= DWC3_REVISION_250A) { 494*3b2dd5deSWilliam Wu reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); 495*3b2dd5deSWilliam Wu 496*3b2dd5deSWilliam Wu if (dwc->maximum_speed == USB_SPEED_HIGH || 497*3b2dd5deSWilliam Wu dwc->maximum_speed == USB_SPEED_FULL) 498*3b2dd5deSWilliam Wu reg |= DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; 499*3b2dd5deSWilliam Wu 500*3b2dd5deSWilliam Wu dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); 501*3b2dd5deSWilliam Wu } 502*3b2dd5deSWilliam Wu 50385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 50485d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 50585d5e707SKishon Vijay Abraham I 50685d5e707SKishon Vijay Abraham I switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { 50785d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 50885d5e707SKishon Vijay Abraham I /** 50985d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an 51085d5e707SKishon Vijay Abraham I * issue which would cause xHCI compliance tests to fail. 51185d5e707SKishon Vijay Abraham I * 51285d5e707SKishon Vijay Abraham I * Because of that we cannot enable clock gating on such 51385d5e707SKishon Vijay Abraham I * configurations. 51485d5e707SKishon Vijay Abraham I * 51585d5e707SKishon Vijay Abraham I * Refers to: 51685d5e707SKishon Vijay Abraham I * 51785d5e707SKishon Vijay Abraham I * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based 51885d5e707SKishon Vijay Abraham I * SOF/ITP Mode Used 51985d5e707SKishon Vijay Abraham I */ 52085d5e707SKishon Vijay Abraham I if ((dwc->dr_mode == USB_DR_MODE_HOST || 52185d5e707SKishon Vijay Abraham I dwc->dr_mode == USB_DR_MODE_OTG) && 52285d5e707SKishon Vijay Abraham I (dwc->revision >= DWC3_REVISION_210A && 52385d5e707SKishon Vijay Abraham I dwc->revision <= DWC3_REVISION_250A)) 52485d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 52585d5e707SKishon Vijay Abraham I else 52685d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DSBLCLKGTNG; 52785d5e707SKishon Vijay Abraham I break; 52885d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 52985d5e707SKishon Vijay Abraham I /* enable hibernation here */ 53085d5e707SKishon Vijay Abraham I dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); 53185d5e707SKishon Vijay Abraham I 53285d5e707SKishon Vijay Abraham I /* 53385d5e707SKishon Vijay Abraham I * REVISIT Enabling this bit so that host-mode hibernation 53485d5e707SKishon Vijay Abraham I * will work. Device-mode hibernation is not yet implemented. 53585d5e707SKishon Vijay Abraham I */ 53685d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_GBLHIBERNATIONEN; 53785d5e707SKishon Vijay Abraham I break; 53885d5e707SKishon Vijay Abraham I default: 53985d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "No power optimization available\n"); 54085d5e707SKishon Vijay Abraham I } 54185d5e707SKishon Vijay Abraham I 54285d5e707SKishon Vijay Abraham I /* check if current dwc3 is on simulation board */ 54385d5e707SKishon Vijay Abraham I if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { 54485d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "it is on FPGA board\n"); 54585d5e707SKishon Vijay Abraham I dwc->is_fpga = true; 54685d5e707SKishon Vijay Abraham I } 54785d5e707SKishon Vijay Abraham I 54871744d0dSKishon Vijay Abraham I if(dwc->disable_scramble_quirk && !dwc->is_fpga) 54971744d0dSKishon Vijay Abraham I WARN(true, 55085d5e707SKishon Vijay Abraham I "disable_scramble cannot be used on non-FPGA builds\n"); 55185d5e707SKishon Vijay Abraham I 55285d5e707SKishon Vijay Abraham I if (dwc->disable_scramble_quirk && dwc->is_fpga) 55385d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DISSCRAMBLE; 55485d5e707SKishon Vijay Abraham I else 55585d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DISSCRAMBLE; 55685d5e707SKishon Vijay Abraham I 55785d5e707SKishon Vijay Abraham I if (dwc->u2exit_lfps_quirk) 55885d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2EXIT_LFPS; 55985d5e707SKishon Vijay Abraham I 56085d5e707SKishon Vijay Abraham I /* 56185d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.90a have a bug 56285d5e707SKishon Vijay Abraham I * where the device can fail to connect at SuperSpeed 56385d5e707SKishon Vijay Abraham I * and falls back to high-speed mode which causes 56485d5e707SKishon Vijay Abraham I * the device to enter a Connect/Disconnect loop 56585d5e707SKishon Vijay Abraham I */ 56685d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_190A) 56785d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2RSTECN; 56885d5e707SKishon Vijay Abraham I 56985d5e707SKishon Vijay Abraham I dwc3_core_num_eps(dwc); 57085d5e707SKishon Vijay Abraham I 57185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 57285d5e707SKishon Vijay Abraham I 5737ce213e7SFrank Wang dwc3_phy_setup(dwc); 5747ce213e7SFrank Wang 57585d5e707SKishon Vijay Abraham I ret = dwc3_alloc_scratch_buffers(dwc); 57685d5e707SKishon Vijay Abraham I if (ret) 57771744d0dSKishon Vijay Abraham I goto err0; 57885d5e707SKishon Vijay Abraham I 57985d5e707SKishon Vijay Abraham I ret = dwc3_setup_scratch_buffers(dwc); 58085d5e707SKishon Vijay Abraham I if (ret) 58171744d0dSKishon Vijay Abraham I goto err1; 58285d5e707SKishon Vijay Abraham I 58385d5e707SKishon Vijay Abraham I return 0; 58485d5e707SKishon Vijay Abraham I 58585d5e707SKishon Vijay Abraham I err1: 58671744d0dSKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 58785d5e707SKishon Vijay Abraham I 58885d5e707SKishon Vijay Abraham I err0: 58985d5e707SKishon Vijay Abraham I return ret; 59085d5e707SKishon Vijay Abraham I } 59185d5e707SKishon Vijay Abraham I 59285d5e707SKishon Vijay Abraham I static void dwc3_core_exit(struct dwc3 *dwc) 59385d5e707SKishon Vijay Abraham I { 59485d5e707SKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 59585d5e707SKishon Vijay Abraham I } 59685d5e707SKishon Vijay Abraham I 59785d5e707SKishon Vijay Abraham I static int dwc3_core_init_mode(struct dwc3 *dwc) 59885d5e707SKishon Vijay Abraham I { 59985d5e707SKishon Vijay Abraham I int ret; 60085d5e707SKishon Vijay Abraham I 60185d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 60285d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 60385d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 60485d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 60585d5e707SKishon Vijay Abraham I if (ret) { 60685d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 60785d5e707SKishon Vijay Abraham I return ret; 60885d5e707SKishon Vijay Abraham I } 60985d5e707SKishon Vijay Abraham I break; 61085d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 61185d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); 61285d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 61385d5e707SKishon Vijay Abraham I if (ret) { 61485d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 61585d5e707SKishon Vijay Abraham I return ret; 61685d5e707SKishon Vijay Abraham I } 61785d5e707SKishon Vijay Abraham I break; 61885d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 61985d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); 62085d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 62185d5e707SKishon Vijay Abraham I if (ret) { 62285d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 62385d5e707SKishon Vijay Abraham I return ret; 62485d5e707SKishon Vijay Abraham I } 62585d5e707SKishon Vijay Abraham I 62685d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 62785d5e707SKishon Vijay Abraham I if (ret) { 62885d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 62985d5e707SKishon Vijay Abraham I return ret; 63085d5e707SKishon Vijay Abraham I } 63185d5e707SKishon Vijay Abraham I break; 63285d5e707SKishon Vijay Abraham I default: 63385d5e707SKishon Vijay Abraham I dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); 63485d5e707SKishon Vijay Abraham I return -EINVAL; 63585d5e707SKishon Vijay Abraham I } 63685d5e707SKishon Vijay Abraham I 63785d5e707SKishon Vijay Abraham I return 0; 63885d5e707SKishon Vijay Abraham I } 63985d5e707SKishon Vijay Abraham I 6402f6edaaeSJean-Jacques Hiblot static void dwc3_gadget_run(struct dwc3 *dwc) 6412f6edaaeSJean-Jacques Hiblot { 6422f6edaaeSJean-Jacques Hiblot dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_RUN_STOP); 6432f6edaaeSJean-Jacques Hiblot mdelay(100); 6442f6edaaeSJean-Jacques Hiblot } 6452f6edaaeSJean-Jacques Hiblot 64685d5e707SKishon Vijay Abraham I static void dwc3_core_exit_mode(struct dwc3 *dwc) 64785d5e707SKishon Vijay Abraham I { 64885d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 64985d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 65085d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 65185d5e707SKishon Vijay Abraham I break; 65285d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 65385d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 65485d5e707SKishon Vijay Abraham I break; 65585d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 65685d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 65785d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 65885d5e707SKishon Vijay Abraham I break; 65985d5e707SKishon Vijay Abraham I default: 66085d5e707SKishon Vijay Abraham I /* do nothing */ 66185d5e707SKishon Vijay Abraham I break; 66285d5e707SKishon Vijay Abraham I } 6632f6edaaeSJean-Jacques Hiblot 6642f6edaaeSJean-Jacques Hiblot /* 6652f6edaaeSJean-Jacques Hiblot * switch back to peripheral mode 6662f6edaaeSJean-Jacques Hiblot * This enables the phy to enter idle and then, if enabled, suspend. 6672f6edaaeSJean-Jacques Hiblot */ 6682f6edaaeSJean-Jacques Hiblot dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 6692f6edaaeSJean-Jacques Hiblot dwc3_gadget_run(dwc); 67085d5e707SKishon Vijay Abraham I } 67185d5e707SKishon Vijay Abraham I 67285d5e707SKishon Vijay Abraham I #define DWC3_ALIGN_MASK (16 - 1) 67385d5e707SKishon Vijay Abraham I 6748e1906a8SKishon Vijay Abraham I /** 6758e1906a8SKishon Vijay Abraham I * dwc3_uboot_init - dwc3 core uboot initialization code 6768e1906a8SKishon Vijay Abraham I * @dwc3_dev: struct dwc3_device containing initialization data 6778e1906a8SKishon Vijay Abraham I * 6788e1906a8SKishon Vijay Abraham I * Entry point for dwc3 driver (equivalent to dwc3_probe in linux 6798e1906a8SKishon Vijay Abraham I * kernel driver). Pointer to dwc3_device should be passed containing 6808e1906a8SKishon Vijay Abraham I * base address and other initialization data. Returns '0' on success and 6818e1906a8SKishon Vijay Abraham I * a negative value on failure. 6828e1906a8SKishon Vijay Abraham I * 6838e1906a8SKishon Vijay Abraham I * Generally called from board_usb_init() implemented in board file. 6848e1906a8SKishon Vijay Abraham I */ 6858e1906a8SKishon Vijay Abraham I int dwc3_uboot_init(struct dwc3_device *dwc3_dev) 68685d5e707SKishon Vijay Abraham I { 687793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 688c2ad4e1bSFelipe Balbi struct device *dev = NULL; 68985d5e707SKishon Vijay Abraham I u8 lpm_nyet_threshold; 69085d5e707SKishon Vijay Abraham I u8 tx_de_emphasis; 69185d5e707SKishon Vijay Abraham I u8 hird_threshold; 69285d5e707SKishon Vijay Abraham I 69385d5e707SKishon Vijay Abraham I int ret; 69485d5e707SKishon Vijay Abraham I 69585d5e707SKishon Vijay Abraham I void *mem; 69641933c04SKever Yang const void *blob = gd->fdt_blob; 69741933c04SKever Yang int node; 69885d5e707SKishon Vijay Abraham I 699b6985a21SMugunthan V N mem = devm_kzalloc((struct udevice *)dev, 700b6985a21SMugunthan V N sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); 70185d5e707SKishon Vijay Abraham I if (!mem) 70285d5e707SKishon Vijay Abraham I return -ENOMEM; 70385d5e707SKishon Vijay Abraham I 70485d5e707SKishon Vijay Abraham I dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); 70585d5e707SKishon Vijay Abraham I dwc->mem = mem; 70685d5e707SKishon Vijay Abraham I 70701c94c4aSMichal Simek dwc->regs = (void *)(uintptr_t)(dwc3_dev->base + 70801c94c4aSMichal Simek DWC3_GLOBALS_REGS_START); 70985d5e707SKishon Vijay Abraham I 71085d5e707SKishon Vijay Abraham I /* default to highest possible threshold */ 71185d5e707SKishon Vijay Abraham I lpm_nyet_threshold = 0xff; 71285d5e707SKishon Vijay Abraham I 71385d5e707SKishon Vijay Abraham I /* default to -3.5dB de-emphasis */ 71485d5e707SKishon Vijay Abraham I tx_de_emphasis = 1; 71585d5e707SKishon Vijay Abraham I 71685d5e707SKishon Vijay Abraham I /* 71785d5e707SKishon Vijay Abraham I * default to assert utmi_sleep_n and use maximum allowed HIRD 71885d5e707SKishon Vijay Abraham I * threshold value of 0b1100 71985d5e707SKishon Vijay Abraham I */ 72085d5e707SKishon Vijay Abraham I hird_threshold = 12; 72185d5e707SKishon Vijay Abraham I 7228e1906a8SKishon Vijay Abraham I dwc->maximum_speed = dwc3_dev->maximum_speed; 7238e1906a8SKishon Vijay Abraham I dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum; 7248e1906a8SKishon Vijay Abraham I if (dwc3_dev->lpm_nyet_threshold) 7258e1906a8SKishon Vijay Abraham I lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold; 7268e1906a8SKishon Vijay Abraham I dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend; 7278e1906a8SKishon Vijay Abraham I if (dwc3_dev->hird_threshold) 7288e1906a8SKishon Vijay Abraham I hird_threshold = dwc3_dev->hird_threshold; 72985d5e707SKishon Vijay Abraham I 7308e1906a8SKishon Vijay Abraham I dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize; 7318e1906a8SKishon Vijay Abraham I dwc->dr_mode = dwc3_dev->dr_mode; 73285d5e707SKishon Vijay Abraham I 7338e1906a8SKishon Vijay Abraham I dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk; 7348e1906a8SKishon Vijay Abraham I dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk; 7358e1906a8SKishon Vijay Abraham I dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk; 7368e1906a8SKishon Vijay Abraham I dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk; 7378e1906a8SKishon Vijay Abraham I dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk; 7388e1906a8SKishon Vijay Abraham I dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk; 7398e1906a8SKishon Vijay Abraham I dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk; 7408e1906a8SKishon Vijay Abraham I dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk; 7418e1906a8SKishon Vijay Abraham I dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk; 7428e1906a8SKishon Vijay Abraham I dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk; 7439c946fbbSFrank Wang dwc->dis_u1u2_quirk = dwc3_dev->dis_u2_susphy_quirk; 74485d5e707SKishon Vijay Abraham I 7458e1906a8SKishon Vijay Abraham I dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk; 7468e1906a8SKishon Vijay Abraham I if (dwc3_dev->tx_de_emphasis) 7478e1906a8SKishon Vijay Abraham I tx_de_emphasis = dwc3_dev->tx_de_emphasis; 74885d5e707SKishon Vijay Abraham I 74985d5e707SKishon Vijay Abraham I /* default to superspeed if no maximum_speed passed */ 75085d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_UNKNOWN) 75185d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_SUPER; 75285d5e707SKishon Vijay Abraham I 75385d5e707SKishon Vijay Abraham I dwc->lpm_nyet_threshold = lpm_nyet_threshold; 75485d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis = tx_de_emphasis; 75585d5e707SKishon Vijay Abraham I 75685d5e707SKishon Vijay Abraham I dwc->hird_threshold = hird_threshold 75785d5e707SKishon Vijay Abraham I | (dwc->is_utmi_l1_suspend << 4); 75885d5e707SKishon Vijay Abraham I 75973d7b075SFrank Wang dwc->hsphy_mode = dwc3_dev->hsphy_mode; 76073d7b075SFrank Wang 761793d347fSKishon Vijay Abraham I dwc->index = dwc3_dev->index; 762793d347fSKishon Vijay Abraham I 7632878d5a3SWilliam Wu if (dwc3_dev->usb2_phyif_utmi_width) 7642878d5a3SWilliam Wu dwc->usb2_phyif_utmi_width = dwc3_dev->usb2_phyif_utmi_width; 7652878d5a3SWilliam Wu 76641933c04SKever Yang node = fdt_node_offset_by_compatible(blob, -1, 76741933c04SKever Yang "rockchip,rk3399-xhci"); 76841933c04SKever Yang if (node < 0) 76941933c04SKever Yang debug("%s dwc3 node not found\n", __func__); 77041933c04SKever Yang else 77141933c04SKever Yang dwc->usb2_phyif_utmi_width = 77241933c04SKever Yang fdtdec_get_int(blob, node, "snps,phyif-utmi-bits", -1); 77341933c04SKever Yang 77485d5e707SKishon Vijay Abraham I dwc3_cache_hwparams(dwc); 77585d5e707SKishon Vijay Abraham I 77685d5e707SKishon Vijay Abraham I ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 77785d5e707SKishon Vijay Abraham I if (ret) { 77885d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate event buffers\n"); 77971744d0dSKishon Vijay Abraham I return -ENOMEM; 78085d5e707SKishon Vijay Abraham I } 78185d5e707SKishon Vijay Abraham I 78285d5e707SKishon Vijay Abraham I if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) 78385d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_HOST; 78485d5e707SKishon Vijay Abraham I else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) 78585d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_PERIPHERAL; 78685d5e707SKishon Vijay Abraham I 78785d5e707SKishon Vijay Abraham I if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) 78885d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_OTG; 78985d5e707SKishon Vijay Abraham I 79085d5e707SKishon Vijay Abraham I ret = dwc3_core_init(dwc); 79185d5e707SKishon Vijay Abraham I if (ret) { 79285d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize core\n"); 79385d5e707SKishon Vijay Abraham I goto err0; 79485d5e707SKishon Vijay Abraham I } 79585d5e707SKishon Vijay Abraham I 79685d5e707SKishon Vijay Abraham I ret = dwc3_event_buffers_setup(dwc); 79785d5e707SKishon Vijay Abraham I if (ret) { 79885d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to setup event buffers\n"); 79971744d0dSKishon Vijay Abraham I goto err1; 80085d5e707SKishon Vijay Abraham I } 80185d5e707SKishon Vijay Abraham I 80285d5e707SKishon Vijay Abraham I ret = dwc3_core_init_mode(dwc); 80385d5e707SKishon Vijay Abraham I if (ret) 80485d5e707SKishon Vijay Abraham I goto err2; 80585d5e707SKishon Vijay Abraham I 806793d347fSKishon Vijay Abraham I list_add_tail(&dwc->list, &dwc3_list); 807793d347fSKishon Vijay Abraham I 80885d5e707SKishon Vijay Abraham I return 0; 80985d5e707SKishon Vijay Abraham I 81085d5e707SKishon Vijay Abraham I err2: 81185d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 81285d5e707SKishon Vijay Abraham I 81385d5e707SKishon Vijay Abraham I err1: 81485d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 81585d5e707SKishon Vijay Abraham I 81685d5e707SKishon Vijay Abraham I err0: 81785d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 81885d5e707SKishon Vijay Abraham I 81985d5e707SKishon Vijay Abraham I return ret; 82085d5e707SKishon Vijay Abraham I } 82185d5e707SKishon Vijay Abraham I 8228e1906a8SKishon Vijay Abraham I /** 8238e1906a8SKishon Vijay Abraham I * dwc3_uboot_exit - dwc3 core uboot cleanup code 8248e1906a8SKishon Vijay Abraham I * @index: index of this controller 8258e1906a8SKishon Vijay Abraham I * 8268e1906a8SKishon Vijay Abraham I * Performs cleanup of memory allocated in dwc3_uboot_init and other misc 827793d347fSKishon Vijay Abraham I * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller 828793d347fSKishon Vijay Abraham I * should be passed and should match with the index passed in 829793d347fSKishon Vijay Abraham I * dwc3_device during init. 8308e1906a8SKishon Vijay Abraham I * 8318e1906a8SKishon Vijay Abraham I * Generally called from board file. 8328e1906a8SKishon Vijay Abraham I */ 833793d347fSKishon Vijay Abraham I void dwc3_uboot_exit(int index) 83485d5e707SKishon Vijay Abraham I { 835793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 836793d347fSKishon Vijay Abraham I 837793d347fSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 838793d347fSKishon Vijay Abraham I if (dwc->index != index) 839793d347fSKishon Vijay Abraham I continue; 840793d347fSKishon Vijay Abraham I 84185d5e707SKishon Vijay Abraham I dwc3_core_exit_mode(dwc); 84285d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 84385d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 84485d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 845793d347fSKishon Vijay Abraham I list_del(&dwc->list); 8468e1906a8SKishon Vijay Abraham I kfree(dwc->mem); 847793d347fSKishon Vijay Abraham I break; 848793d347fSKishon Vijay Abraham I } 84985d5e707SKishon Vijay Abraham I } 85085d5e707SKishon Vijay Abraham I 85127d3b89dSKishon Vijay Abraham I /** 85227d3b89dSKishon Vijay Abraham I * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt 85327d3b89dSKishon Vijay Abraham I * @index: index of this controller 85427d3b89dSKishon Vijay Abraham I * 85527d3b89dSKishon Vijay Abraham I * Invokes dwc3 gadget interrupts. 85627d3b89dSKishon Vijay Abraham I * 85727d3b89dSKishon Vijay Abraham I * Generally called from board file. 85827d3b89dSKishon Vijay Abraham I */ 85927d3b89dSKishon Vijay Abraham I void dwc3_uboot_handle_interrupt(int index) 86027d3b89dSKishon Vijay Abraham I { 86127d3b89dSKishon Vijay Abraham I struct dwc3 *dwc = NULL; 86227d3b89dSKishon Vijay Abraham I 86327d3b89dSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 86427d3b89dSKishon Vijay Abraham I if (dwc->index != index) 86527d3b89dSKishon Vijay Abraham I continue; 86627d3b89dSKishon Vijay Abraham I 86727d3b89dSKishon Vijay Abraham I dwc3_gadget_uboot_handle_interrupt(dwc); 86827d3b89dSKishon Vijay Abraham I break; 86927d3b89dSKishon Vijay Abraham I } 87027d3b89dSKishon Vijay Abraham I } 87127d3b89dSKishon Vijay Abraham I 87285d5e707SKishon Vijay Abraham I MODULE_ALIAS("platform:dwc3"); 87385d5e707SKishon Vijay Abraham I MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 87485d5e707SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 87585d5e707SKishon Vijay Abraham I MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 876434f82edSMugunthan V N 87772d48a52SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) 87872d48a52SJean-Jacques Hiblot int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) 87972d48a52SJean-Jacques Hiblot { 88072d48a52SJean-Jacques Hiblot int i, ret, count; 88172d48a52SJean-Jacques Hiblot struct phy *usb_phys; 88272d48a52SJean-Jacques Hiblot 88372d48a52SJean-Jacques Hiblot /* Return if no phy declared */ 88472d48a52SJean-Jacques Hiblot if (!dev_read_prop(dev, "phys", NULL)) 88572d48a52SJean-Jacques Hiblot return 0; 88672d48a52SJean-Jacques Hiblot count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); 88772d48a52SJean-Jacques Hiblot if (count <= 0) 88872d48a52SJean-Jacques Hiblot return count; 88972d48a52SJean-Jacques Hiblot 89072d48a52SJean-Jacques Hiblot usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), 89172d48a52SJean-Jacques Hiblot GFP_KERNEL); 89272d48a52SJean-Jacques Hiblot if (!usb_phys) 89372d48a52SJean-Jacques Hiblot return -ENOMEM; 89472d48a52SJean-Jacques Hiblot 89572d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 89672d48a52SJean-Jacques Hiblot ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); 89772d48a52SJean-Jacques Hiblot if (ret && ret != -ENOENT) { 89872d48a52SJean-Jacques Hiblot pr_err("Failed to get USB PHY%d for %s\n", 89972d48a52SJean-Jacques Hiblot i, dev->name); 90072d48a52SJean-Jacques Hiblot return ret; 90172d48a52SJean-Jacques Hiblot } 90272d48a52SJean-Jacques Hiblot } 90372d48a52SJean-Jacques Hiblot 90472d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 90572d48a52SJean-Jacques Hiblot ret = generic_phy_init(&usb_phys[i]); 90672d48a52SJean-Jacques Hiblot if (ret) { 90772d48a52SJean-Jacques Hiblot pr_err("Can't init USB PHY%d for %s\n", 90872d48a52SJean-Jacques Hiblot i, dev->name); 90972d48a52SJean-Jacques Hiblot goto phys_init_err; 91072d48a52SJean-Jacques Hiblot } 91172d48a52SJean-Jacques Hiblot } 91272d48a52SJean-Jacques Hiblot 91372d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) { 91472d48a52SJean-Jacques Hiblot ret = generic_phy_power_on(&usb_phys[i]); 91572d48a52SJean-Jacques Hiblot if (ret) { 91672d48a52SJean-Jacques Hiblot pr_err("Can't power USB PHY%d for %s\n", 91772d48a52SJean-Jacques Hiblot i, dev->name); 91872d48a52SJean-Jacques Hiblot goto phys_poweron_err; 91972d48a52SJean-Jacques Hiblot } 92072d48a52SJean-Jacques Hiblot } 92172d48a52SJean-Jacques Hiblot 92272d48a52SJean-Jacques Hiblot *array = usb_phys; 92372d48a52SJean-Jacques Hiblot *num_phys = count; 92472d48a52SJean-Jacques Hiblot return 0; 92572d48a52SJean-Jacques Hiblot 92672d48a52SJean-Jacques Hiblot phys_poweron_err: 92772d48a52SJean-Jacques Hiblot for (i = count - 1; i >= 0; i--) 92872d48a52SJean-Jacques Hiblot generic_phy_power_off(&usb_phys[i]); 92972d48a52SJean-Jacques Hiblot 93072d48a52SJean-Jacques Hiblot for (i = 0; i < count; i++) 93172d48a52SJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 93272d48a52SJean-Jacques Hiblot 93372d48a52SJean-Jacques Hiblot return ret; 93472d48a52SJean-Jacques Hiblot 93572d48a52SJean-Jacques Hiblot phys_init_err: 93672d48a52SJean-Jacques Hiblot for (; i >= 0; i--) 93772d48a52SJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 93872d48a52SJean-Jacques Hiblot 93972d48a52SJean-Jacques Hiblot return ret; 94072d48a52SJean-Jacques Hiblot } 94172d48a52SJean-Jacques Hiblot 94272d48a52SJean-Jacques Hiblot int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) 94372d48a52SJean-Jacques Hiblot { 94472d48a52SJean-Jacques Hiblot int i, ret; 94572d48a52SJean-Jacques Hiblot 94672d48a52SJean-Jacques Hiblot for (i = 0; i < num_phys; i++) { 94772d48a52SJean-Jacques Hiblot if (!generic_phy_valid(&usb_phys[i])) 94872d48a52SJean-Jacques Hiblot continue; 94972d48a52SJean-Jacques Hiblot 95072d48a52SJean-Jacques Hiblot ret = generic_phy_power_off(&usb_phys[i]); 95172d48a52SJean-Jacques Hiblot ret |= generic_phy_exit(&usb_phys[i]); 95272d48a52SJean-Jacques Hiblot if (ret) { 95372d48a52SJean-Jacques Hiblot pr_err("Can't shutdown USB PHY%d for %s\n", 95472d48a52SJean-Jacques Hiblot i, dev->name); 95572d48a52SJean-Jacques Hiblot } 95672d48a52SJean-Jacques Hiblot } 95772d48a52SJean-Jacques Hiblot 95872d48a52SJean-Jacques Hiblot return 0; 95972d48a52SJean-Jacques Hiblot } 96072d48a52SJean-Jacques Hiblot #endif 96172d48a52SJean-Jacques Hiblot 962f7133ecdSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB) 963eedade57SJean-Jacques Hiblot void dwc3_of_parse(struct dwc3 *dwc) 964eedade57SJean-Jacques Hiblot { 965eedade57SJean-Jacques Hiblot const u8 *tmp; 966eedade57SJean-Jacques Hiblot struct udevice *dev = dwc->dev; 967eedade57SJean-Jacques Hiblot u8 lpm_nyet_threshold; 968eedade57SJean-Jacques Hiblot u8 tx_de_emphasis; 969eedade57SJean-Jacques Hiblot u8 hird_threshold; 970eedade57SJean-Jacques Hiblot 971eedade57SJean-Jacques Hiblot /* default to highest possible threshold */ 972eedade57SJean-Jacques Hiblot lpm_nyet_threshold = 0xff; 973eedade57SJean-Jacques Hiblot 974eedade57SJean-Jacques Hiblot /* default to -3.5dB de-emphasis */ 975eedade57SJean-Jacques Hiblot tx_de_emphasis = 1; 976eedade57SJean-Jacques Hiblot 977eedade57SJean-Jacques Hiblot /* 978eedade57SJean-Jacques Hiblot * default to assert utmi_sleep_n and use maximum allowed HIRD 979eedade57SJean-Jacques Hiblot * threshold value of 0b1100 980eedade57SJean-Jacques Hiblot */ 981eedade57SJean-Jacques Hiblot hird_threshold = 12; 982eedade57SJean-Jacques Hiblot 98373d7b075SFrank Wang dwc->hsphy_mode = usb_get_phy_mode(dev->node); 98473d7b075SFrank Wang 985eedade57SJean-Jacques Hiblot dwc->has_lpm_erratum = dev_read_bool(dev, 986eedade57SJean-Jacques Hiblot "snps,has-lpm-erratum"); 987eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1); 988eedade57SJean-Jacques Hiblot if (tmp) 989eedade57SJean-Jacques Hiblot lpm_nyet_threshold = *tmp; 990eedade57SJean-Jacques Hiblot 991eedade57SJean-Jacques Hiblot dwc->is_utmi_l1_suspend = dev_read_bool(dev, 992eedade57SJean-Jacques Hiblot "snps,is-utmi-l1-suspend"); 993eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1); 994eedade57SJean-Jacques Hiblot if (tmp) 995eedade57SJean-Jacques Hiblot hird_threshold = *tmp; 996eedade57SJean-Jacques Hiblot 997eedade57SJean-Jacques Hiblot dwc->disable_scramble_quirk = dev_read_bool(dev, 998eedade57SJean-Jacques Hiblot "snps,disable_scramble_quirk"); 999eedade57SJean-Jacques Hiblot dwc->u2exit_lfps_quirk = dev_read_bool(dev, 1000eedade57SJean-Jacques Hiblot "snps,u2exit_lfps_quirk"); 1001eedade57SJean-Jacques Hiblot dwc->u2ss_inp3_quirk = dev_read_bool(dev, 1002eedade57SJean-Jacques Hiblot "snps,u2ss_inp3_quirk"); 1003eedade57SJean-Jacques Hiblot dwc->req_p1p2p3_quirk = dev_read_bool(dev, 1004eedade57SJean-Jacques Hiblot "snps,req_p1p2p3_quirk"); 1005eedade57SJean-Jacques Hiblot dwc->del_p1p2p3_quirk = dev_read_bool(dev, 1006eedade57SJean-Jacques Hiblot "snps,del_p1p2p3_quirk"); 1007eedade57SJean-Jacques Hiblot dwc->del_phy_power_chg_quirk = dev_read_bool(dev, 1008eedade57SJean-Jacques Hiblot "snps,del_phy_power_chg_quirk"); 1009eedade57SJean-Jacques Hiblot dwc->lfps_filter_quirk = dev_read_bool(dev, 1010eedade57SJean-Jacques Hiblot "snps,lfps_filter_quirk"); 1011eedade57SJean-Jacques Hiblot dwc->rx_detect_poll_quirk = dev_read_bool(dev, 1012eedade57SJean-Jacques Hiblot "snps,rx_detect_poll_quirk"); 1013eedade57SJean-Jacques Hiblot dwc->dis_u3_susphy_quirk = dev_read_bool(dev, 1014eedade57SJean-Jacques Hiblot "snps,dis_u3_susphy_quirk"); 1015eedade57SJean-Jacques Hiblot dwc->dis_u2_susphy_quirk = dev_read_bool(dev, 1016eedade57SJean-Jacques Hiblot "snps,dis_u2_susphy_quirk"); 1017f4acaed3SFrank Wang dwc->dis_enblslpm_quirk = dev_read_bool(dev, 1018f4acaed3SFrank Wang "snps,dis_enblslpm_quirk"); 1019efc9f556SFrank Wang dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev, 1020efc9f556SFrank Wang "snps,dis-u2-freeclk-exists-quirk"); 1021eedade57SJean-Jacques Hiblot dwc->tx_de_emphasis_quirk = dev_read_bool(dev, 1022eedade57SJean-Jacques Hiblot "snps,tx_de_emphasis_quirk"); 1023eedade57SJean-Jacques Hiblot tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1); 1024eedade57SJean-Jacques Hiblot if (tmp) 1025eedade57SJean-Jacques Hiblot tx_de_emphasis = *tmp; 1026eedade57SJean-Jacques Hiblot 1027eedade57SJean-Jacques Hiblot dwc->lpm_nyet_threshold = lpm_nyet_threshold; 1028eedade57SJean-Jacques Hiblot dwc->tx_de_emphasis = tx_de_emphasis; 1029eedade57SJean-Jacques Hiblot 1030eedade57SJean-Jacques Hiblot dwc->hird_threshold = hird_threshold 1031eedade57SJean-Jacques Hiblot | (dwc->is_utmi_l1_suspend << 4); 1032eedade57SJean-Jacques Hiblot } 1033eedade57SJean-Jacques Hiblot 1034434f82edSMugunthan V N int dwc3_init(struct dwc3 *dwc) 1035434f82edSMugunthan V N { 1036434f82edSMugunthan V N int ret; 1037434f82edSMugunthan V N 1038434f82edSMugunthan V N dwc3_cache_hwparams(dwc); 1039434f82edSMugunthan V N 1040434f82edSMugunthan V N ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 1041434f82edSMugunthan V N if (ret) { 1042434f82edSMugunthan V N dev_err(dwc->dev, "failed to allocate event buffers\n"); 1043434f82edSMugunthan V N return -ENOMEM; 1044434f82edSMugunthan V N } 1045434f82edSMugunthan V N 1046434f82edSMugunthan V N ret = dwc3_core_init(dwc); 1047434f82edSMugunthan V N if (ret) { 1048434f82edSMugunthan V N dev_err(dev, "failed to initialize core\n"); 1049434f82edSMugunthan V N goto core_fail; 1050434f82edSMugunthan V N } 1051434f82edSMugunthan V N 1052434f82edSMugunthan V N ret = dwc3_event_buffers_setup(dwc); 1053434f82edSMugunthan V N if (ret) { 1054434f82edSMugunthan V N dev_err(dwc->dev, "failed to setup event buffers\n"); 1055434f82edSMugunthan V N goto event_fail; 1056434f82edSMugunthan V N } 1057434f82edSMugunthan V N 1058434f82edSMugunthan V N ret = dwc3_core_init_mode(dwc); 1059434f82edSMugunthan V N if (ret) 1060434f82edSMugunthan V N goto mode_fail; 1061434f82edSMugunthan V N 1062434f82edSMugunthan V N return 0; 1063434f82edSMugunthan V N 1064434f82edSMugunthan V N mode_fail: 1065434f82edSMugunthan V N dwc3_event_buffers_cleanup(dwc); 1066434f82edSMugunthan V N 1067434f82edSMugunthan V N event_fail: 1068434f82edSMugunthan V N dwc3_core_exit(dwc); 1069434f82edSMugunthan V N 1070434f82edSMugunthan V N core_fail: 1071434f82edSMugunthan V N dwc3_free_event_buffers(dwc); 1072434f82edSMugunthan V N 1073434f82edSMugunthan V N return ret; 1074434f82edSMugunthan V N } 1075434f82edSMugunthan V N 1076434f82edSMugunthan V N void dwc3_remove(struct dwc3 *dwc) 1077434f82edSMugunthan V N { 1078434f82edSMugunthan V N dwc3_core_exit_mode(dwc); 1079434f82edSMugunthan V N dwc3_event_buffers_cleanup(dwc); 1080434f82edSMugunthan V N dwc3_free_event_buffers(dwc); 1081434f82edSMugunthan V N dwc3_core_exit(dwc); 1082434f82edSMugunthan V N kfree(dwc->mem); 1083434f82edSMugunthan V N } 1084434f82edSMugunthan V N #endif 1085