183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0 285d5e707SKishon Vijay Abraham I /** 385d5e707SKishon Vijay Abraham I * core.c - DesignWare USB3 DRD Controller Core file 485d5e707SKishon Vijay Abraham I * 530c31d58SKishon Vijay Abraham I * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com 685d5e707SKishon Vijay Abraham I * 785d5e707SKishon Vijay Abraham I * Authors: Felipe Balbi <balbi@ti.com>, 885d5e707SKishon Vijay Abraham I * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 985d5e707SKishon Vijay Abraham I * 1030c31d58SKishon Vijay Abraham I * Taken from Linux Kernel v3.19-rc1 (drivers/usb/dwc3/core.c) and ported 1130c31d58SKishon Vijay Abraham I * to uboot. 1285d5e707SKishon Vijay Abraham I * 1330c31d58SKishon Vijay Abraham I * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA 1485d5e707SKishon Vijay Abraham I */ 1585d5e707SKishon Vijay Abraham I 1671744d0dSKishon Vijay Abraham I #include <common.h> 1771744d0dSKishon Vijay Abraham I #include <malloc.h> 188e1906a8SKishon Vijay Abraham I #include <dwc3-uboot.h> 1971744d0dSKishon Vijay Abraham I #include <asm/dma-mapping.h> 2085d5e707SKishon Vijay Abraham I #include <linux/ioport.h> 210ad3f771SMugunthan V N #include <dm.h> 22*d648a50cSJean-Jacques Hiblot #include <generic-phy.h> 2385d5e707SKishon Vijay Abraham I #include <linux/usb/ch9.h> 2485d5e707SKishon Vijay Abraham I #include <linux/usb/gadget.h> 2585d5e707SKishon Vijay Abraham I 2685d5e707SKishon Vijay Abraham I #include "core.h" 2785d5e707SKishon Vijay Abraham I #include "gadget.h" 2885d5e707SKishon Vijay Abraham I #include "io.h" 2985d5e707SKishon Vijay Abraham I 3071744d0dSKishon Vijay Abraham I #include "linux-compat.h" 3185d5e707SKishon Vijay Abraham I 32793d347fSKishon Vijay Abraham I static LIST_HEAD(dwc3_list); 3385d5e707SKishon Vijay Abraham I /* -------------------------------------------------------------------------- */ 3485d5e707SKishon Vijay Abraham I 357e9cb796SJoonyoung Shim static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) 3685d5e707SKishon Vijay Abraham I { 3785d5e707SKishon Vijay Abraham I u32 reg; 3885d5e707SKishon Vijay Abraham I 3985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 4085d5e707SKishon Vijay Abraham I reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); 4185d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_PRTCAPDIR(mode); 4285d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 4385d5e707SKishon Vijay Abraham I } 4485d5e707SKishon Vijay Abraham I 4585d5e707SKishon Vijay Abraham I /** 4685d5e707SKishon Vijay Abraham I * dwc3_core_soft_reset - Issues core soft reset and PHY reset 4785d5e707SKishon Vijay Abraham I * @dwc: pointer to our context structure 4885d5e707SKishon Vijay Abraham I */ 4985d5e707SKishon Vijay Abraham I static int dwc3_core_soft_reset(struct dwc3 *dwc) 5085d5e707SKishon Vijay Abraham I { 5185d5e707SKishon Vijay Abraham I u32 reg; 5285d5e707SKishon Vijay Abraham I 5385d5e707SKishon Vijay Abraham I /* Before Resetting PHY, put Core in Reset */ 5485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 5585d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_CORESOFTRESET; 5685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 5785d5e707SKishon Vijay Abraham I 5885d5e707SKishon Vijay Abraham I /* Assert USB3 PHY reset */ 5985d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 6085d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; 6185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 6285d5e707SKishon Vijay Abraham I 6385d5e707SKishon Vijay Abraham I /* Assert USB2 PHY reset */ 6485d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 6585d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; 6685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 6785d5e707SKishon Vijay Abraham I 6885d5e707SKishon Vijay Abraham I mdelay(100); 6985d5e707SKishon Vijay Abraham I 7085d5e707SKishon Vijay Abraham I /* Clear USB3 PHY reset */ 7185d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 7285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; 7385d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 7485d5e707SKishon Vijay Abraham I 7585d5e707SKishon Vijay Abraham I /* Clear USB2 PHY reset */ 7685d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 7785d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; 7885d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 7985d5e707SKishon Vijay Abraham I 8085d5e707SKishon Vijay Abraham I mdelay(100); 8185d5e707SKishon Vijay Abraham I 8285d5e707SKishon Vijay Abraham I /* After PHYs are stable we can take Core out of reset state */ 8385d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 8485d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_CORESOFTRESET; 8585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 8685d5e707SKishon Vijay Abraham I 8785d5e707SKishon Vijay Abraham I return 0; 8885d5e707SKishon Vijay Abraham I } 8985d5e707SKishon Vijay Abraham I 9085d5e707SKishon Vijay Abraham I /** 9185d5e707SKishon Vijay Abraham I * dwc3_free_one_event_buffer - Frees one event buffer 9285d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 9385d5e707SKishon Vijay Abraham I * @evt: Pointer to event buffer to be freed 9485d5e707SKishon Vijay Abraham I */ 9585d5e707SKishon Vijay Abraham I static void dwc3_free_one_event_buffer(struct dwc3 *dwc, 9685d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt) 9785d5e707SKishon Vijay Abraham I { 9871744d0dSKishon Vijay Abraham I dma_free_coherent(evt->buf); 9985d5e707SKishon Vijay Abraham I } 10085d5e707SKishon Vijay Abraham I 10185d5e707SKishon Vijay Abraham I /** 10285d5e707SKishon Vijay Abraham I * dwc3_alloc_one_event_buffer - Allocates one event buffer structure 10385d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 10485d5e707SKishon Vijay Abraham I * @length: size of the event buffer 10585d5e707SKishon Vijay Abraham I * 10685d5e707SKishon Vijay Abraham I * Returns a pointer to the allocated event buffer structure on success 10785d5e707SKishon Vijay Abraham I * otherwise ERR_PTR(errno). 10885d5e707SKishon Vijay Abraham I */ 10985d5e707SKishon Vijay Abraham I static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, 11085d5e707SKishon Vijay Abraham I unsigned length) 11185d5e707SKishon Vijay Abraham I { 11285d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 11385d5e707SKishon Vijay Abraham I 1140ad3f771SMugunthan V N evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt), 1150ad3f771SMugunthan V N GFP_KERNEL); 11685d5e707SKishon Vijay Abraham I if (!evt) 11785d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 11885d5e707SKishon Vijay Abraham I 11985d5e707SKishon Vijay Abraham I evt->dwc = dwc; 12085d5e707SKishon Vijay Abraham I evt->length = length; 12171744d0dSKishon Vijay Abraham I evt->buf = dma_alloc_coherent(length, 12271744d0dSKishon Vijay Abraham I (unsigned long *)&evt->dma); 12385d5e707SKishon Vijay Abraham I if (!evt->buf) 12485d5e707SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 12585d5e707SKishon Vijay Abraham I 126889239d6SPhilipp Tomsich dwc3_flush_cache((uintptr_t)evt->buf, evt->length); 127889239d6SPhilipp Tomsich 12885d5e707SKishon Vijay Abraham I return evt; 12985d5e707SKishon Vijay Abraham I } 13085d5e707SKishon Vijay Abraham I 13185d5e707SKishon Vijay Abraham I /** 13285d5e707SKishon Vijay Abraham I * dwc3_free_event_buffers - frees all allocated event buffers 13385d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 13485d5e707SKishon Vijay Abraham I */ 13585d5e707SKishon Vijay Abraham I static void dwc3_free_event_buffers(struct dwc3 *dwc) 13685d5e707SKishon Vijay Abraham I { 13785d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 13885d5e707SKishon Vijay Abraham I int i; 13985d5e707SKishon Vijay Abraham I 14085d5e707SKishon Vijay Abraham I for (i = 0; i < dwc->num_event_buffers; i++) { 14185d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[i]; 14285d5e707SKishon Vijay Abraham I if (evt) 14385d5e707SKishon Vijay Abraham I dwc3_free_one_event_buffer(dwc, evt); 14485d5e707SKishon Vijay Abraham I } 14585d5e707SKishon Vijay Abraham I } 14685d5e707SKishon Vijay Abraham I 14785d5e707SKishon Vijay Abraham I /** 14885d5e707SKishon Vijay Abraham I * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length 14985d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 15085d5e707SKishon Vijay Abraham I * @length: size of event buffer 15185d5e707SKishon Vijay Abraham I * 15285d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. In the error case, dwc 15385d5e707SKishon Vijay Abraham I * may contain some buffers allocated but not all which were requested. 15485d5e707SKishon Vijay Abraham I */ 15585d5e707SKishon Vijay Abraham I static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) 15685d5e707SKishon Vijay Abraham I { 15785d5e707SKishon Vijay Abraham I int num; 15885d5e707SKishon Vijay Abraham I int i; 15985d5e707SKishon Vijay Abraham I 16085d5e707SKishon Vijay Abraham I num = DWC3_NUM_INT(dwc->hwparams.hwparams1); 16185d5e707SKishon Vijay Abraham I dwc->num_event_buffers = num; 16285d5e707SKishon Vijay Abraham I 163526a50f8SKishon Vijay Abraham I dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE, 164526a50f8SKishon Vijay Abraham I sizeof(*dwc->ev_buffs) * num); 16585d5e707SKishon Vijay Abraham I if (!dwc->ev_buffs) 16685d5e707SKishon Vijay Abraham I return -ENOMEM; 16785d5e707SKishon Vijay Abraham I 16885d5e707SKishon Vijay Abraham I for (i = 0; i < num; i++) { 16985d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 17085d5e707SKishon Vijay Abraham I 17185d5e707SKishon Vijay Abraham I evt = dwc3_alloc_one_event_buffer(dwc, length); 17285d5e707SKishon Vijay Abraham I if (IS_ERR(evt)) { 17385d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "can't allocate event buffer\n"); 17485d5e707SKishon Vijay Abraham I return PTR_ERR(evt); 17585d5e707SKishon Vijay Abraham I } 17685d5e707SKishon Vijay Abraham I dwc->ev_buffs[i] = evt; 17785d5e707SKishon Vijay Abraham I } 17885d5e707SKishon Vijay Abraham I 17985d5e707SKishon Vijay Abraham I return 0; 18085d5e707SKishon Vijay Abraham I } 18185d5e707SKishon Vijay Abraham I 18285d5e707SKishon Vijay Abraham I /** 18385d5e707SKishon Vijay Abraham I * dwc3_event_buffers_setup - setup our allocated event buffers 18485d5e707SKishon Vijay Abraham I * @dwc: pointer to our controller context structure 18585d5e707SKishon Vijay Abraham I * 18685d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 18785d5e707SKishon Vijay Abraham I */ 18885d5e707SKishon Vijay Abraham I static int dwc3_event_buffers_setup(struct dwc3 *dwc) 18985d5e707SKishon Vijay Abraham I { 19085d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 19185d5e707SKishon Vijay Abraham I int n; 19285d5e707SKishon Vijay Abraham I 19385d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 19485d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 19585d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", 19685d5e707SKishon Vijay Abraham I evt->buf, (unsigned long long) evt->dma, 19785d5e707SKishon Vijay Abraham I evt->length); 19885d5e707SKishon Vijay Abraham I 19985d5e707SKishon Vijay Abraham I evt->lpos = 0; 20085d5e707SKishon Vijay Abraham I 20185d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 20285d5e707SKishon Vijay Abraham I lower_32_bits(evt->dma)); 20385d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 20485d5e707SKishon Vijay Abraham I upper_32_bits(evt->dma)); 20585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 20685d5e707SKishon Vijay Abraham I DWC3_GEVNTSIZ_SIZE(evt->length)); 20785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 20885d5e707SKishon Vijay Abraham I } 20985d5e707SKishon Vijay Abraham I 21085d5e707SKishon Vijay Abraham I return 0; 21185d5e707SKishon Vijay Abraham I } 21285d5e707SKishon Vijay Abraham I 21385d5e707SKishon Vijay Abraham I static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) 21485d5e707SKishon Vijay Abraham I { 21585d5e707SKishon Vijay Abraham I struct dwc3_event_buffer *evt; 21685d5e707SKishon Vijay Abraham I int n; 21785d5e707SKishon Vijay Abraham I 21885d5e707SKishon Vijay Abraham I for (n = 0; n < dwc->num_event_buffers; n++) { 21985d5e707SKishon Vijay Abraham I evt = dwc->ev_buffs[n]; 22085d5e707SKishon Vijay Abraham I 22185d5e707SKishon Vijay Abraham I evt->lpos = 0; 22285d5e707SKishon Vijay Abraham I 22385d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); 22485d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); 22585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK 22685d5e707SKishon Vijay Abraham I | DWC3_GEVNTSIZ_SIZE(0)); 22785d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); 22885d5e707SKishon Vijay Abraham I } 22985d5e707SKishon Vijay Abraham I } 23085d5e707SKishon Vijay Abraham I 23185d5e707SKishon Vijay Abraham I static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) 23285d5e707SKishon Vijay Abraham I { 23385d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 23485d5e707SKishon Vijay Abraham I return 0; 23585d5e707SKishon Vijay Abraham I 23685d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 23785d5e707SKishon Vijay Abraham I return 0; 23885d5e707SKishon Vijay Abraham I 23985d5e707SKishon Vijay Abraham I dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, 24085d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); 24185d5e707SKishon Vijay Abraham I if (!dwc->scratchbuf) 24285d5e707SKishon Vijay Abraham I return -ENOMEM; 24385d5e707SKishon Vijay Abraham I 24485d5e707SKishon Vijay Abraham I return 0; 24585d5e707SKishon Vijay Abraham I } 24685d5e707SKishon Vijay Abraham I 24785d5e707SKishon Vijay Abraham I static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) 24885d5e707SKishon Vijay Abraham I { 24985d5e707SKishon Vijay Abraham I dma_addr_t scratch_addr; 25085d5e707SKishon Vijay Abraham I u32 param; 25185d5e707SKishon Vijay Abraham I int ret; 25285d5e707SKishon Vijay Abraham I 25385d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 25485d5e707SKishon Vijay Abraham I return 0; 25585d5e707SKishon Vijay Abraham I 25685d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 25785d5e707SKishon Vijay Abraham I return 0; 25885d5e707SKishon Vijay Abraham I 25971744d0dSKishon Vijay Abraham I scratch_addr = dma_map_single(dwc->scratchbuf, 26085d5e707SKishon Vijay Abraham I dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, 26185d5e707SKishon Vijay Abraham I DMA_BIDIRECTIONAL); 26285d5e707SKishon Vijay Abraham I if (dma_mapping_error(dwc->dev, scratch_addr)) { 26385d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to map scratch buffer\n"); 26485d5e707SKishon Vijay Abraham I ret = -EFAULT; 26585d5e707SKishon Vijay Abraham I goto err0; 26685d5e707SKishon Vijay Abraham I } 26785d5e707SKishon Vijay Abraham I 26885d5e707SKishon Vijay Abraham I dwc->scratch_addr = scratch_addr; 26985d5e707SKishon Vijay Abraham I 27085d5e707SKishon Vijay Abraham I param = lower_32_bits(scratch_addr); 27185d5e707SKishon Vijay Abraham I 27285d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 27385d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); 27485d5e707SKishon Vijay Abraham I if (ret < 0) 27585d5e707SKishon Vijay Abraham I goto err1; 27685d5e707SKishon Vijay Abraham I 27785d5e707SKishon Vijay Abraham I param = upper_32_bits(scratch_addr); 27885d5e707SKishon Vijay Abraham I 27985d5e707SKishon Vijay Abraham I ret = dwc3_send_gadget_generic_command(dwc, 28085d5e707SKishon Vijay Abraham I DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); 28185d5e707SKishon Vijay Abraham I if (ret < 0) 28285d5e707SKishon Vijay Abraham I goto err1; 28385d5e707SKishon Vijay Abraham I 28485d5e707SKishon Vijay Abraham I return 0; 28585d5e707SKishon Vijay Abraham I 28685d5e707SKishon Vijay Abraham I err1: 28701c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 28885d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 28985d5e707SKishon Vijay Abraham I 29085d5e707SKishon Vijay Abraham I err0: 29185d5e707SKishon Vijay Abraham I return ret; 29285d5e707SKishon Vijay Abraham I } 29385d5e707SKishon Vijay Abraham I 29485d5e707SKishon Vijay Abraham I static void dwc3_free_scratch_buffers(struct dwc3 *dwc) 29585d5e707SKishon Vijay Abraham I { 29685d5e707SKishon Vijay Abraham I if (!dwc->has_hibernation) 29785d5e707SKishon Vijay Abraham I return; 29885d5e707SKishon Vijay Abraham I 29985d5e707SKishon Vijay Abraham I if (!dwc->nr_scratch) 30085d5e707SKishon Vijay Abraham I return; 30185d5e707SKishon Vijay Abraham I 30201c94c4aSMichal Simek dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * 30385d5e707SKishon Vijay Abraham I DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); 30485d5e707SKishon Vijay Abraham I kfree(dwc->scratchbuf); 30585d5e707SKishon Vijay Abraham I } 30685d5e707SKishon Vijay Abraham I 30785d5e707SKishon Vijay Abraham I static void dwc3_core_num_eps(struct dwc3 *dwc) 30885d5e707SKishon Vijay Abraham I { 30985d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 31085d5e707SKishon Vijay Abraham I 31185d5e707SKishon Vijay Abraham I dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); 31285d5e707SKishon Vijay Abraham I dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; 31385d5e707SKishon Vijay Abraham I 31485d5e707SKishon Vijay Abraham I dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", 31585d5e707SKishon Vijay Abraham I dwc->num_in_eps, dwc->num_out_eps); 31685d5e707SKishon Vijay Abraham I } 31785d5e707SKishon Vijay Abraham I 31885d5e707SKishon Vijay Abraham I static void dwc3_cache_hwparams(struct dwc3 *dwc) 31985d5e707SKishon Vijay Abraham I { 32085d5e707SKishon Vijay Abraham I struct dwc3_hwparams *parms = &dwc->hwparams; 32185d5e707SKishon Vijay Abraham I 32285d5e707SKishon Vijay Abraham I parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); 32385d5e707SKishon Vijay Abraham I parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); 32485d5e707SKishon Vijay Abraham I parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); 32585d5e707SKishon Vijay Abraham I parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); 32685d5e707SKishon Vijay Abraham I parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); 32785d5e707SKishon Vijay Abraham I parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); 32885d5e707SKishon Vijay Abraham I parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); 32985d5e707SKishon Vijay Abraham I parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); 33085d5e707SKishon Vijay Abraham I parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); 33185d5e707SKishon Vijay Abraham I } 33285d5e707SKishon Vijay Abraham I 33385d5e707SKishon Vijay Abraham I /** 33485d5e707SKishon Vijay Abraham I * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core 33585d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 33685d5e707SKishon Vijay Abraham I */ 33785d5e707SKishon Vijay Abraham I static void dwc3_phy_setup(struct dwc3 *dwc) 33885d5e707SKishon Vijay Abraham I { 33985d5e707SKishon Vijay Abraham I u32 reg; 34085d5e707SKishon Vijay Abraham I 34185d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); 34285d5e707SKishon Vijay Abraham I 34385d5e707SKishon Vijay Abraham I /* 34485d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY 34585d5e707SKishon Vijay Abraham I * to '0' during coreConsultant configuration. So default value 34685d5e707SKishon Vijay Abraham I * will be '0' when the core is reset. Application needs to set it 34785d5e707SKishon Vijay Abraham I * to '1' after the core initialization is completed. 34885d5e707SKishon Vijay Abraham I */ 34985d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 35085d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_SUSPHY; 35185d5e707SKishon Vijay Abraham I 35285d5e707SKishon Vijay Abraham I if (dwc->u2ss_inp3_quirk) 35385d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; 35485d5e707SKishon Vijay Abraham I 35585d5e707SKishon Vijay Abraham I if (dwc->req_p1p2p3_quirk) 35685d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; 35785d5e707SKishon Vijay Abraham I 35885d5e707SKishon Vijay Abraham I if (dwc->del_p1p2p3_quirk) 35985d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN; 36085d5e707SKishon Vijay Abraham I 36185d5e707SKishon Vijay Abraham I if (dwc->del_phy_power_chg_quirk) 36285d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE; 36385d5e707SKishon Vijay Abraham I 36485d5e707SKishon Vijay Abraham I if (dwc->lfps_filter_quirk) 36585d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_LFPSFILT; 36685d5e707SKishon Vijay Abraham I 36785d5e707SKishon Vijay Abraham I if (dwc->rx_detect_poll_quirk) 36885d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL; 36985d5e707SKishon Vijay Abraham I 37085d5e707SKishon Vijay Abraham I if (dwc->tx_de_emphasis_quirk) 37185d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis); 37285d5e707SKishon Vijay Abraham I 37385d5e707SKishon Vijay Abraham I if (dwc->dis_u3_susphy_quirk) 37485d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; 37585d5e707SKishon Vijay Abraham I 37685d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); 37785d5e707SKishon Vijay Abraham I 37885d5e707SKishon Vijay Abraham I mdelay(100); 37985d5e707SKishon Vijay Abraham I 38085d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); 38185d5e707SKishon Vijay Abraham I 38285d5e707SKishon Vijay Abraham I /* 38385d5e707SKishon Vijay Abraham I * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to 38485d5e707SKishon Vijay Abraham I * '0' during coreConsultant configuration. So default value will 38585d5e707SKishon Vijay Abraham I * be '0' when the core is reset. Application needs to set it to 38685d5e707SKishon Vijay Abraham I * '1' after the core initialization is completed. 38785d5e707SKishon Vijay Abraham I */ 38885d5e707SKishon Vijay Abraham I if (dwc->revision > DWC3_REVISION_194A) 38985d5e707SKishon Vijay Abraham I reg |= DWC3_GUSB2PHYCFG_SUSPHY; 39085d5e707SKishon Vijay Abraham I 39185d5e707SKishon Vijay Abraham I if (dwc->dis_u2_susphy_quirk) 39285d5e707SKishon Vijay Abraham I reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; 39385d5e707SKishon Vijay Abraham I 39485d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); 39585d5e707SKishon Vijay Abraham I 39685d5e707SKishon Vijay Abraham I mdelay(100); 39785d5e707SKishon Vijay Abraham I } 39885d5e707SKishon Vijay Abraham I 39985d5e707SKishon Vijay Abraham I /** 40085d5e707SKishon Vijay Abraham I * dwc3_core_init - Low-level initialization of DWC3 Core 40185d5e707SKishon Vijay Abraham I * @dwc: Pointer to our controller context structure 40285d5e707SKishon Vijay Abraham I * 40385d5e707SKishon Vijay Abraham I * Returns 0 on success otherwise negative errno. 40485d5e707SKishon Vijay Abraham I */ 40585d5e707SKishon Vijay Abraham I static int dwc3_core_init(struct dwc3 *dwc) 40685d5e707SKishon Vijay Abraham I { 40785d5e707SKishon Vijay Abraham I unsigned long timeout; 40885d5e707SKishon Vijay Abraham I u32 hwparams4 = dwc->hwparams.hwparams4; 40985d5e707SKishon Vijay Abraham I u32 reg; 41085d5e707SKishon Vijay Abraham I int ret; 41185d5e707SKishon Vijay Abraham I 41285d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); 41385d5e707SKishon Vijay Abraham I /* This should read as U3 followed by revision number */ 41485d5e707SKishon Vijay Abraham I if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { 41585d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); 41685d5e707SKishon Vijay Abraham I ret = -ENODEV; 41785d5e707SKishon Vijay Abraham I goto err0; 41885d5e707SKishon Vijay Abraham I } 41985d5e707SKishon Vijay Abraham I dwc->revision = reg; 42085d5e707SKishon Vijay Abraham I 42185d5e707SKishon Vijay Abraham I /* Handle USB2.0-only core configuration */ 42285d5e707SKishon Vijay Abraham I if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == 42385d5e707SKishon Vijay Abraham I DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { 42485d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_SUPER) 42585d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_HIGH; 42685d5e707SKishon Vijay Abraham I } 42785d5e707SKishon Vijay Abraham I 42885d5e707SKishon Vijay Abraham I /* issue device SoftReset too */ 42971744d0dSKishon Vijay Abraham I timeout = 5000; 43085d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); 43171744d0dSKishon Vijay Abraham I while (timeout--) { 43285d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_DCTL); 43385d5e707SKishon Vijay Abraham I if (!(reg & DWC3_DCTL_CSFTRST)) 43485d5e707SKishon Vijay Abraham I break; 43571744d0dSKishon Vijay Abraham I }; 43685d5e707SKishon Vijay Abraham I 43771744d0dSKishon Vijay Abraham I if (!timeout) { 43885d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "Reset Timed Out\n"); 43985d5e707SKishon Vijay Abraham I ret = -ETIMEDOUT; 44085d5e707SKishon Vijay Abraham I goto err0; 44185d5e707SKishon Vijay Abraham I } 44285d5e707SKishon Vijay Abraham I 44385d5e707SKishon Vijay Abraham I ret = dwc3_core_soft_reset(dwc); 44485d5e707SKishon Vijay Abraham I if (ret) 44585d5e707SKishon Vijay Abraham I goto err0; 44685d5e707SKishon Vijay Abraham I 44785d5e707SKishon Vijay Abraham I reg = dwc3_readl(dwc->regs, DWC3_GCTL); 44885d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 44985d5e707SKishon Vijay Abraham I 45085d5e707SKishon Vijay Abraham I switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { 45185d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 45285d5e707SKishon Vijay Abraham I /** 45385d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an 45485d5e707SKishon Vijay Abraham I * issue which would cause xHCI compliance tests to fail. 45585d5e707SKishon Vijay Abraham I * 45685d5e707SKishon Vijay Abraham I * Because of that we cannot enable clock gating on such 45785d5e707SKishon Vijay Abraham I * configurations. 45885d5e707SKishon Vijay Abraham I * 45985d5e707SKishon Vijay Abraham I * Refers to: 46085d5e707SKishon Vijay Abraham I * 46185d5e707SKishon Vijay Abraham I * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based 46285d5e707SKishon Vijay Abraham I * SOF/ITP Mode Used 46385d5e707SKishon Vijay Abraham I */ 46485d5e707SKishon Vijay Abraham I if ((dwc->dr_mode == USB_DR_MODE_HOST || 46585d5e707SKishon Vijay Abraham I dwc->dr_mode == USB_DR_MODE_OTG) && 46685d5e707SKishon Vijay Abraham I (dwc->revision >= DWC3_REVISION_210A && 46785d5e707SKishon Vijay Abraham I dwc->revision <= DWC3_REVISION_250A)) 46885d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; 46985d5e707SKishon Vijay Abraham I else 47085d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DSBLCLKGTNG; 47185d5e707SKishon Vijay Abraham I break; 47285d5e707SKishon Vijay Abraham I case DWC3_GHWPARAMS1_EN_PWROPT_HIB: 47385d5e707SKishon Vijay Abraham I /* enable hibernation here */ 47485d5e707SKishon Vijay Abraham I dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); 47585d5e707SKishon Vijay Abraham I 47685d5e707SKishon Vijay Abraham I /* 47785d5e707SKishon Vijay Abraham I * REVISIT Enabling this bit so that host-mode hibernation 47885d5e707SKishon Vijay Abraham I * will work. Device-mode hibernation is not yet implemented. 47985d5e707SKishon Vijay Abraham I */ 48085d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_GBLHIBERNATIONEN; 48185d5e707SKishon Vijay Abraham I break; 48285d5e707SKishon Vijay Abraham I default: 48385d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "No power optimization available\n"); 48485d5e707SKishon Vijay Abraham I } 48585d5e707SKishon Vijay Abraham I 48685d5e707SKishon Vijay Abraham I /* check if current dwc3 is on simulation board */ 48785d5e707SKishon Vijay Abraham I if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) { 48885d5e707SKishon Vijay Abraham I dev_dbg(dwc->dev, "it is on FPGA board\n"); 48985d5e707SKishon Vijay Abraham I dwc->is_fpga = true; 49085d5e707SKishon Vijay Abraham I } 49185d5e707SKishon Vijay Abraham I 49271744d0dSKishon Vijay Abraham I if(dwc->disable_scramble_quirk && !dwc->is_fpga) 49371744d0dSKishon Vijay Abraham I WARN(true, 49485d5e707SKishon Vijay Abraham I "disable_scramble cannot be used on non-FPGA builds\n"); 49585d5e707SKishon Vijay Abraham I 49685d5e707SKishon Vijay Abraham I if (dwc->disable_scramble_quirk && dwc->is_fpga) 49785d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_DISSCRAMBLE; 49885d5e707SKishon Vijay Abraham I else 49985d5e707SKishon Vijay Abraham I reg &= ~DWC3_GCTL_DISSCRAMBLE; 50085d5e707SKishon Vijay Abraham I 50185d5e707SKishon Vijay Abraham I if (dwc->u2exit_lfps_quirk) 50285d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2EXIT_LFPS; 50385d5e707SKishon Vijay Abraham I 50485d5e707SKishon Vijay Abraham I /* 50585d5e707SKishon Vijay Abraham I * WORKAROUND: DWC3 revisions <1.90a have a bug 50685d5e707SKishon Vijay Abraham I * where the device can fail to connect at SuperSpeed 50785d5e707SKishon Vijay Abraham I * and falls back to high-speed mode which causes 50885d5e707SKishon Vijay Abraham I * the device to enter a Connect/Disconnect loop 50985d5e707SKishon Vijay Abraham I */ 51085d5e707SKishon Vijay Abraham I if (dwc->revision < DWC3_REVISION_190A) 51185d5e707SKishon Vijay Abraham I reg |= DWC3_GCTL_U2RSTECN; 51285d5e707SKishon Vijay Abraham I 51385d5e707SKishon Vijay Abraham I dwc3_core_num_eps(dwc); 51485d5e707SKishon Vijay Abraham I 51585d5e707SKishon Vijay Abraham I dwc3_writel(dwc->regs, DWC3_GCTL, reg); 51685d5e707SKishon Vijay Abraham I 51785d5e707SKishon Vijay Abraham I dwc3_phy_setup(dwc); 51885d5e707SKishon Vijay Abraham I 51985d5e707SKishon Vijay Abraham I ret = dwc3_alloc_scratch_buffers(dwc); 52085d5e707SKishon Vijay Abraham I if (ret) 52171744d0dSKishon Vijay Abraham I goto err0; 52285d5e707SKishon Vijay Abraham I 52385d5e707SKishon Vijay Abraham I ret = dwc3_setup_scratch_buffers(dwc); 52485d5e707SKishon Vijay Abraham I if (ret) 52571744d0dSKishon Vijay Abraham I goto err1; 52685d5e707SKishon Vijay Abraham I 52785d5e707SKishon Vijay Abraham I return 0; 52885d5e707SKishon Vijay Abraham I 52985d5e707SKishon Vijay Abraham I err1: 53071744d0dSKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 53185d5e707SKishon Vijay Abraham I 53285d5e707SKishon Vijay Abraham I err0: 53385d5e707SKishon Vijay Abraham I return ret; 53485d5e707SKishon Vijay Abraham I } 53585d5e707SKishon Vijay Abraham I 53685d5e707SKishon Vijay Abraham I static void dwc3_core_exit(struct dwc3 *dwc) 53785d5e707SKishon Vijay Abraham I { 53885d5e707SKishon Vijay Abraham I dwc3_free_scratch_buffers(dwc); 53985d5e707SKishon Vijay Abraham I } 54085d5e707SKishon Vijay Abraham I 54185d5e707SKishon Vijay Abraham I static int dwc3_core_init_mode(struct dwc3 *dwc) 54285d5e707SKishon Vijay Abraham I { 54385d5e707SKishon Vijay Abraham I int ret; 54485d5e707SKishon Vijay Abraham I 54585d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 54685d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 54785d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); 54885d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 54985d5e707SKishon Vijay Abraham I if (ret) { 55085d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 55185d5e707SKishon Vijay Abraham I return ret; 55285d5e707SKishon Vijay Abraham I } 55385d5e707SKishon Vijay Abraham I break; 55485d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 55585d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); 55685d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 55785d5e707SKishon Vijay Abraham I if (ret) { 55885d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 55985d5e707SKishon Vijay Abraham I return ret; 56085d5e707SKishon Vijay Abraham I } 56185d5e707SKishon Vijay Abraham I break; 56285d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 56385d5e707SKishon Vijay Abraham I dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); 56485d5e707SKishon Vijay Abraham I ret = dwc3_host_init(dwc); 56585d5e707SKishon Vijay Abraham I if (ret) { 56685d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize host\n"); 56785d5e707SKishon Vijay Abraham I return ret; 56885d5e707SKishon Vijay Abraham I } 56985d5e707SKishon Vijay Abraham I 57085d5e707SKishon Vijay Abraham I ret = dwc3_gadget_init(dwc); 57185d5e707SKishon Vijay Abraham I if (ret) { 57285d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize gadget\n"); 57385d5e707SKishon Vijay Abraham I return ret; 57485d5e707SKishon Vijay Abraham I } 57585d5e707SKishon Vijay Abraham I break; 57685d5e707SKishon Vijay Abraham I default: 57785d5e707SKishon Vijay Abraham I dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); 57885d5e707SKishon Vijay Abraham I return -EINVAL; 57985d5e707SKishon Vijay Abraham I } 58085d5e707SKishon Vijay Abraham I 58185d5e707SKishon Vijay Abraham I return 0; 58285d5e707SKishon Vijay Abraham I } 58385d5e707SKishon Vijay Abraham I 58485d5e707SKishon Vijay Abraham I static void dwc3_core_exit_mode(struct dwc3 *dwc) 58585d5e707SKishon Vijay Abraham I { 58685d5e707SKishon Vijay Abraham I switch (dwc->dr_mode) { 58785d5e707SKishon Vijay Abraham I case USB_DR_MODE_PERIPHERAL: 58885d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 58985d5e707SKishon Vijay Abraham I break; 59085d5e707SKishon Vijay Abraham I case USB_DR_MODE_HOST: 59185d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 59285d5e707SKishon Vijay Abraham I break; 59385d5e707SKishon Vijay Abraham I case USB_DR_MODE_OTG: 59485d5e707SKishon Vijay Abraham I dwc3_host_exit(dwc); 59585d5e707SKishon Vijay Abraham I dwc3_gadget_exit(dwc); 59685d5e707SKishon Vijay Abraham I break; 59785d5e707SKishon Vijay Abraham I default: 59885d5e707SKishon Vijay Abraham I /* do nothing */ 59985d5e707SKishon Vijay Abraham I break; 60085d5e707SKishon Vijay Abraham I } 60185d5e707SKishon Vijay Abraham I } 60285d5e707SKishon Vijay Abraham I 60385d5e707SKishon Vijay Abraham I #define DWC3_ALIGN_MASK (16 - 1) 60485d5e707SKishon Vijay Abraham I 6058e1906a8SKishon Vijay Abraham I /** 6068e1906a8SKishon Vijay Abraham I * dwc3_uboot_init - dwc3 core uboot initialization code 6078e1906a8SKishon Vijay Abraham I * @dwc3_dev: struct dwc3_device containing initialization data 6088e1906a8SKishon Vijay Abraham I * 6098e1906a8SKishon Vijay Abraham I * Entry point for dwc3 driver (equivalent to dwc3_probe in linux 6108e1906a8SKishon Vijay Abraham I * kernel driver). Pointer to dwc3_device should be passed containing 6118e1906a8SKishon Vijay Abraham I * base address and other initialization data. Returns '0' on success and 6128e1906a8SKishon Vijay Abraham I * a negative value on failure. 6138e1906a8SKishon Vijay Abraham I * 6148e1906a8SKishon Vijay Abraham I * Generally called from board_usb_init() implemented in board file. 6158e1906a8SKishon Vijay Abraham I */ 6168e1906a8SKishon Vijay Abraham I int dwc3_uboot_init(struct dwc3_device *dwc3_dev) 61785d5e707SKishon Vijay Abraham I { 618793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 619c2ad4e1bSFelipe Balbi struct device *dev = NULL; 62085d5e707SKishon Vijay Abraham I u8 lpm_nyet_threshold; 62185d5e707SKishon Vijay Abraham I u8 tx_de_emphasis; 62285d5e707SKishon Vijay Abraham I u8 hird_threshold; 62385d5e707SKishon Vijay Abraham I 62485d5e707SKishon Vijay Abraham I int ret; 62585d5e707SKishon Vijay Abraham I 62685d5e707SKishon Vijay Abraham I void *mem; 62785d5e707SKishon Vijay Abraham I 6280ad3f771SMugunthan V N mem = devm_kzalloc((struct udevice *)dev, 6290ad3f771SMugunthan V N sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); 63085d5e707SKishon Vijay Abraham I if (!mem) 63185d5e707SKishon Vijay Abraham I return -ENOMEM; 63285d5e707SKishon Vijay Abraham I 63385d5e707SKishon Vijay Abraham I dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); 63485d5e707SKishon Vijay Abraham I dwc->mem = mem; 63585d5e707SKishon Vijay Abraham I 63601c94c4aSMichal Simek dwc->regs = (void *)(uintptr_t)(dwc3_dev->base + 63701c94c4aSMichal Simek DWC3_GLOBALS_REGS_START); 63885d5e707SKishon Vijay Abraham I 63985d5e707SKishon Vijay Abraham I /* default to highest possible threshold */ 64085d5e707SKishon Vijay Abraham I lpm_nyet_threshold = 0xff; 64185d5e707SKishon Vijay Abraham I 64285d5e707SKishon Vijay Abraham I /* default to -3.5dB de-emphasis */ 64385d5e707SKishon Vijay Abraham I tx_de_emphasis = 1; 64485d5e707SKishon Vijay Abraham I 64585d5e707SKishon Vijay Abraham I /* 64685d5e707SKishon Vijay Abraham I * default to assert utmi_sleep_n and use maximum allowed HIRD 64785d5e707SKishon Vijay Abraham I * threshold value of 0b1100 64885d5e707SKishon Vijay Abraham I */ 64985d5e707SKishon Vijay Abraham I hird_threshold = 12; 65085d5e707SKishon Vijay Abraham I 6518e1906a8SKishon Vijay Abraham I dwc->maximum_speed = dwc3_dev->maximum_speed; 6528e1906a8SKishon Vijay Abraham I dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum; 6538e1906a8SKishon Vijay Abraham I if (dwc3_dev->lpm_nyet_threshold) 6548e1906a8SKishon Vijay Abraham I lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold; 6558e1906a8SKishon Vijay Abraham I dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend; 6568e1906a8SKishon Vijay Abraham I if (dwc3_dev->hird_threshold) 6578e1906a8SKishon Vijay Abraham I hird_threshold = dwc3_dev->hird_threshold; 65885d5e707SKishon Vijay Abraham I 6598e1906a8SKishon Vijay Abraham I dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize; 6608e1906a8SKishon Vijay Abraham I dwc->dr_mode = dwc3_dev->dr_mode; 66185d5e707SKishon Vijay Abraham I 6628e1906a8SKishon Vijay Abraham I dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk; 6638e1906a8SKishon Vijay Abraham I dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk; 6648e1906a8SKishon Vijay Abraham I dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk; 6658e1906a8SKishon Vijay Abraham I dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk; 6668e1906a8SKishon Vijay Abraham I dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk; 6678e1906a8SKishon Vijay Abraham I dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk; 6688e1906a8SKishon Vijay Abraham I dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk; 6698e1906a8SKishon Vijay Abraham I dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk; 6708e1906a8SKishon Vijay Abraham I dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk; 6718e1906a8SKishon Vijay Abraham I dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk; 67285d5e707SKishon Vijay Abraham I 6738e1906a8SKishon Vijay Abraham I dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk; 6748e1906a8SKishon Vijay Abraham I if (dwc3_dev->tx_de_emphasis) 6758e1906a8SKishon Vijay Abraham I tx_de_emphasis = dwc3_dev->tx_de_emphasis; 67685d5e707SKishon Vijay Abraham I 67785d5e707SKishon Vijay Abraham I /* default to superspeed if no maximum_speed passed */ 67885d5e707SKishon Vijay Abraham I if (dwc->maximum_speed == USB_SPEED_UNKNOWN) 67985d5e707SKishon Vijay Abraham I dwc->maximum_speed = USB_SPEED_SUPER; 68085d5e707SKishon Vijay Abraham I 68185d5e707SKishon Vijay Abraham I dwc->lpm_nyet_threshold = lpm_nyet_threshold; 68285d5e707SKishon Vijay Abraham I dwc->tx_de_emphasis = tx_de_emphasis; 68385d5e707SKishon Vijay Abraham I 68485d5e707SKishon Vijay Abraham I dwc->hird_threshold = hird_threshold 68585d5e707SKishon Vijay Abraham I | (dwc->is_utmi_l1_suspend << 4); 68685d5e707SKishon Vijay Abraham I 687793d347fSKishon Vijay Abraham I dwc->index = dwc3_dev->index; 688793d347fSKishon Vijay Abraham I 68985d5e707SKishon Vijay Abraham I dwc3_cache_hwparams(dwc); 69085d5e707SKishon Vijay Abraham I 69185d5e707SKishon Vijay Abraham I ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 69285d5e707SKishon Vijay Abraham I if (ret) { 69385d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to allocate event buffers\n"); 69471744d0dSKishon Vijay Abraham I return -ENOMEM; 69585d5e707SKishon Vijay Abraham I } 69685d5e707SKishon Vijay Abraham I 69785d5e707SKishon Vijay Abraham I if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) 69885d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_HOST; 69985d5e707SKishon Vijay Abraham I else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) 70085d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_PERIPHERAL; 70185d5e707SKishon Vijay Abraham I 70285d5e707SKishon Vijay Abraham I if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) 70385d5e707SKishon Vijay Abraham I dwc->dr_mode = USB_DR_MODE_OTG; 70485d5e707SKishon Vijay Abraham I 70585d5e707SKishon Vijay Abraham I ret = dwc3_core_init(dwc); 70685d5e707SKishon Vijay Abraham I if (ret) { 70785d5e707SKishon Vijay Abraham I dev_err(dev, "failed to initialize core\n"); 70885d5e707SKishon Vijay Abraham I goto err0; 70985d5e707SKishon Vijay Abraham I } 71085d5e707SKishon Vijay Abraham I 71185d5e707SKishon Vijay Abraham I ret = dwc3_event_buffers_setup(dwc); 71285d5e707SKishon Vijay Abraham I if (ret) { 71385d5e707SKishon Vijay Abraham I dev_err(dwc->dev, "failed to setup event buffers\n"); 71471744d0dSKishon Vijay Abraham I goto err1; 71585d5e707SKishon Vijay Abraham I } 71685d5e707SKishon Vijay Abraham I 71785d5e707SKishon Vijay Abraham I ret = dwc3_core_init_mode(dwc); 71885d5e707SKishon Vijay Abraham I if (ret) 71985d5e707SKishon Vijay Abraham I goto err2; 72085d5e707SKishon Vijay Abraham I 721793d347fSKishon Vijay Abraham I list_add_tail(&dwc->list, &dwc3_list); 722793d347fSKishon Vijay Abraham I 72385d5e707SKishon Vijay Abraham I return 0; 72485d5e707SKishon Vijay Abraham I 72585d5e707SKishon Vijay Abraham I err2: 72685d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 72785d5e707SKishon Vijay Abraham I 72885d5e707SKishon Vijay Abraham I err1: 72985d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 73085d5e707SKishon Vijay Abraham I 73185d5e707SKishon Vijay Abraham I err0: 73285d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 73385d5e707SKishon Vijay Abraham I 73485d5e707SKishon Vijay Abraham I return ret; 73585d5e707SKishon Vijay Abraham I } 73685d5e707SKishon Vijay Abraham I 7378e1906a8SKishon Vijay Abraham I /** 7388e1906a8SKishon Vijay Abraham I * dwc3_uboot_exit - dwc3 core uboot cleanup code 7398e1906a8SKishon Vijay Abraham I * @index: index of this controller 7408e1906a8SKishon Vijay Abraham I * 7418e1906a8SKishon Vijay Abraham I * Performs cleanup of memory allocated in dwc3_uboot_init and other misc 742793d347fSKishon Vijay Abraham I * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller 743793d347fSKishon Vijay Abraham I * should be passed and should match with the index passed in 744793d347fSKishon Vijay Abraham I * dwc3_device during init. 7458e1906a8SKishon Vijay Abraham I * 7468e1906a8SKishon Vijay Abraham I * Generally called from board file. 7478e1906a8SKishon Vijay Abraham I */ 748793d347fSKishon Vijay Abraham I void dwc3_uboot_exit(int index) 74985d5e707SKishon Vijay Abraham I { 750793d347fSKishon Vijay Abraham I struct dwc3 *dwc; 751793d347fSKishon Vijay Abraham I 752793d347fSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 753793d347fSKishon Vijay Abraham I if (dwc->index != index) 754793d347fSKishon Vijay Abraham I continue; 755793d347fSKishon Vijay Abraham I 75685d5e707SKishon Vijay Abraham I dwc3_core_exit_mode(dwc); 75785d5e707SKishon Vijay Abraham I dwc3_event_buffers_cleanup(dwc); 75885d5e707SKishon Vijay Abraham I dwc3_free_event_buffers(dwc); 75985d5e707SKishon Vijay Abraham I dwc3_core_exit(dwc); 760793d347fSKishon Vijay Abraham I list_del(&dwc->list); 7618e1906a8SKishon Vijay Abraham I kfree(dwc->mem); 762793d347fSKishon Vijay Abraham I break; 763793d347fSKishon Vijay Abraham I } 76485d5e707SKishon Vijay Abraham I } 76585d5e707SKishon Vijay Abraham I 76627d3b89dSKishon Vijay Abraham I /** 76727d3b89dSKishon Vijay Abraham I * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt 76827d3b89dSKishon Vijay Abraham I * @index: index of this controller 76927d3b89dSKishon Vijay Abraham I * 77027d3b89dSKishon Vijay Abraham I * Invokes dwc3 gadget interrupts. 77127d3b89dSKishon Vijay Abraham I * 77227d3b89dSKishon Vijay Abraham I * Generally called from board file. 77327d3b89dSKishon Vijay Abraham I */ 77427d3b89dSKishon Vijay Abraham I void dwc3_uboot_handle_interrupt(int index) 77527d3b89dSKishon Vijay Abraham I { 77627d3b89dSKishon Vijay Abraham I struct dwc3 *dwc = NULL; 77727d3b89dSKishon Vijay Abraham I 77827d3b89dSKishon Vijay Abraham I list_for_each_entry(dwc, &dwc3_list, list) { 77927d3b89dSKishon Vijay Abraham I if (dwc->index != index) 78027d3b89dSKishon Vijay Abraham I continue; 78127d3b89dSKishon Vijay Abraham I 78227d3b89dSKishon Vijay Abraham I dwc3_gadget_uboot_handle_interrupt(dwc); 78327d3b89dSKishon Vijay Abraham I break; 78427d3b89dSKishon Vijay Abraham I } 78527d3b89dSKishon Vijay Abraham I } 78627d3b89dSKishon Vijay Abraham I 78785d5e707SKishon Vijay Abraham I MODULE_ALIAS("platform:dwc3"); 78885d5e707SKishon Vijay Abraham I MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 78985d5e707SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 79085d5e707SKishon Vijay Abraham I MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); 79123ba2d63SMugunthan V N 792*d648a50cSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) 793*d648a50cSJean-Jacques Hiblot int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) 794*d648a50cSJean-Jacques Hiblot { 795*d648a50cSJean-Jacques Hiblot int i, ret, count; 796*d648a50cSJean-Jacques Hiblot struct phy *usb_phys; 797*d648a50cSJean-Jacques Hiblot 798*d648a50cSJean-Jacques Hiblot /* Return if no phy declared */ 799*d648a50cSJean-Jacques Hiblot if (!dev_read_prop(dev, "phys", NULL)) 800*d648a50cSJean-Jacques Hiblot return 0; 801*d648a50cSJean-Jacques Hiblot count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); 802*d648a50cSJean-Jacques Hiblot if (count <= 0) 803*d648a50cSJean-Jacques Hiblot return count; 804*d648a50cSJean-Jacques Hiblot 805*d648a50cSJean-Jacques Hiblot usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), 806*d648a50cSJean-Jacques Hiblot GFP_KERNEL); 807*d648a50cSJean-Jacques Hiblot if (!usb_phys) 808*d648a50cSJean-Jacques Hiblot return -ENOMEM; 809*d648a50cSJean-Jacques Hiblot 810*d648a50cSJean-Jacques Hiblot for (i = 0; i < count; i++) { 811*d648a50cSJean-Jacques Hiblot ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); 812*d648a50cSJean-Jacques Hiblot if (ret && ret != -ENOENT) { 813*d648a50cSJean-Jacques Hiblot pr_err("Failed to get USB PHY%d for %s\n", 814*d648a50cSJean-Jacques Hiblot i, dev->name); 815*d648a50cSJean-Jacques Hiblot return ret; 816*d648a50cSJean-Jacques Hiblot } 817*d648a50cSJean-Jacques Hiblot } 818*d648a50cSJean-Jacques Hiblot 819*d648a50cSJean-Jacques Hiblot for (i = 0; i < count; i++) { 820*d648a50cSJean-Jacques Hiblot ret = generic_phy_init(&usb_phys[i]); 821*d648a50cSJean-Jacques Hiblot if (ret) { 822*d648a50cSJean-Jacques Hiblot pr_err("Can't init USB PHY%d for %s\n", 823*d648a50cSJean-Jacques Hiblot i, dev->name); 824*d648a50cSJean-Jacques Hiblot goto phys_init_err; 825*d648a50cSJean-Jacques Hiblot } 826*d648a50cSJean-Jacques Hiblot } 827*d648a50cSJean-Jacques Hiblot 828*d648a50cSJean-Jacques Hiblot for (i = 0; i < count; i++) { 829*d648a50cSJean-Jacques Hiblot ret = generic_phy_power_on(&usb_phys[i]); 830*d648a50cSJean-Jacques Hiblot if (ret) { 831*d648a50cSJean-Jacques Hiblot pr_err("Can't power USB PHY%d for %s\n", 832*d648a50cSJean-Jacques Hiblot i, dev->name); 833*d648a50cSJean-Jacques Hiblot goto phys_poweron_err; 834*d648a50cSJean-Jacques Hiblot } 835*d648a50cSJean-Jacques Hiblot } 836*d648a50cSJean-Jacques Hiblot 837*d648a50cSJean-Jacques Hiblot *array = usb_phys; 838*d648a50cSJean-Jacques Hiblot *num_phys = count; 839*d648a50cSJean-Jacques Hiblot return 0; 840*d648a50cSJean-Jacques Hiblot 841*d648a50cSJean-Jacques Hiblot phys_poweron_err: 842*d648a50cSJean-Jacques Hiblot for (i = count - 1; i >= 0; i--) 843*d648a50cSJean-Jacques Hiblot generic_phy_power_off(&usb_phys[i]); 844*d648a50cSJean-Jacques Hiblot 845*d648a50cSJean-Jacques Hiblot for (i = 0; i < count; i++) 846*d648a50cSJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 847*d648a50cSJean-Jacques Hiblot 848*d648a50cSJean-Jacques Hiblot return ret; 849*d648a50cSJean-Jacques Hiblot 850*d648a50cSJean-Jacques Hiblot phys_init_err: 851*d648a50cSJean-Jacques Hiblot for (; i >= 0; i--) 852*d648a50cSJean-Jacques Hiblot generic_phy_exit(&usb_phys[i]); 853*d648a50cSJean-Jacques Hiblot 854*d648a50cSJean-Jacques Hiblot return ret; 855*d648a50cSJean-Jacques Hiblot } 856*d648a50cSJean-Jacques Hiblot 857*d648a50cSJean-Jacques Hiblot int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) 858*d648a50cSJean-Jacques Hiblot { 859*d648a50cSJean-Jacques Hiblot int i, ret; 860*d648a50cSJean-Jacques Hiblot 861*d648a50cSJean-Jacques Hiblot for (i = 0; i < num_phys; i++) { 862*d648a50cSJean-Jacques Hiblot if (!generic_phy_valid(&usb_phys[i])) 863*d648a50cSJean-Jacques Hiblot continue; 864*d648a50cSJean-Jacques Hiblot 865*d648a50cSJean-Jacques Hiblot ret = generic_phy_power_off(&usb_phys[i]); 866*d648a50cSJean-Jacques Hiblot ret |= generic_phy_exit(&usb_phys[i]); 867*d648a50cSJean-Jacques Hiblot if (ret) { 868*d648a50cSJean-Jacques Hiblot pr_err("Can't shutdown USB PHY%d for %s\n", 869*d648a50cSJean-Jacques Hiblot i, dev->name); 870*d648a50cSJean-Jacques Hiblot } 871*d648a50cSJean-Jacques Hiblot } 872*d648a50cSJean-Jacques Hiblot 873*d648a50cSJean-Jacques Hiblot return 0; 874*d648a50cSJean-Jacques Hiblot } 875*d648a50cSJean-Jacques Hiblot #endif 876*d648a50cSJean-Jacques Hiblot 877687ab545SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET) 87823ba2d63SMugunthan V N int dwc3_init(struct dwc3 *dwc) 87923ba2d63SMugunthan V N { 88023ba2d63SMugunthan V N int ret; 88123ba2d63SMugunthan V N 88223ba2d63SMugunthan V N dwc3_cache_hwparams(dwc); 88323ba2d63SMugunthan V N 88423ba2d63SMugunthan V N ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); 88523ba2d63SMugunthan V N if (ret) { 88623ba2d63SMugunthan V N dev_err(dwc->dev, "failed to allocate event buffers\n"); 88723ba2d63SMugunthan V N return -ENOMEM; 88823ba2d63SMugunthan V N } 88923ba2d63SMugunthan V N 89023ba2d63SMugunthan V N ret = dwc3_core_init(dwc); 89123ba2d63SMugunthan V N if (ret) { 89223ba2d63SMugunthan V N dev_err(dev, "failed to initialize core\n"); 89323ba2d63SMugunthan V N goto core_fail; 89423ba2d63SMugunthan V N } 89523ba2d63SMugunthan V N 89623ba2d63SMugunthan V N ret = dwc3_event_buffers_setup(dwc); 89723ba2d63SMugunthan V N if (ret) { 89823ba2d63SMugunthan V N dev_err(dwc->dev, "failed to setup event buffers\n"); 89923ba2d63SMugunthan V N goto event_fail; 90023ba2d63SMugunthan V N } 90123ba2d63SMugunthan V N 90223ba2d63SMugunthan V N ret = dwc3_core_init_mode(dwc); 90323ba2d63SMugunthan V N if (ret) 90423ba2d63SMugunthan V N goto mode_fail; 90523ba2d63SMugunthan V N 90623ba2d63SMugunthan V N return 0; 90723ba2d63SMugunthan V N 90823ba2d63SMugunthan V N mode_fail: 90923ba2d63SMugunthan V N dwc3_event_buffers_cleanup(dwc); 91023ba2d63SMugunthan V N 91123ba2d63SMugunthan V N event_fail: 91223ba2d63SMugunthan V N dwc3_core_exit(dwc); 91323ba2d63SMugunthan V N 91423ba2d63SMugunthan V N core_fail: 91523ba2d63SMugunthan V N dwc3_free_event_buffers(dwc); 91623ba2d63SMugunthan V N 91723ba2d63SMugunthan V N return ret; 91823ba2d63SMugunthan V N } 91923ba2d63SMugunthan V N 92023ba2d63SMugunthan V N void dwc3_remove(struct dwc3 *dwc) 92123ba2d63SMugunthan V N { 92223ba2d63SMugunthan V N dwc3_core_exit_mode(dwc); 92323ba2d63SMugunthan V N dwc3_event_buffers_cleanup(dwc); 92423ba2d63SMugunthan V N dwc3_free_event_buffers(dwc); 92523ba2d63SMugunthan V N dwc3_core_exit(dwc); 92623ba2d63SMugunthan V N kfree(dwc->mem); 92723ba2d63SMugunthan V N } 92823ba2d63SMugunthan V N #endif 929