15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2197ba5f4SPaul Zimmerman /* 3197ba5f4SPaul Zimmerman * core.c - DesignWare HS OTG Controller common routines 4197ba5f4SPaul Zimmerman * 5197ba5f4SPaul Zimmerman * Copyright (C) 2004-2013 Synopsys, Inc. 6197ba5f4SPaul Zimmerman */ 7197ba5f4SPaul Zimmerman 8197ba5f4SPaul Zimmerman /* 9197ba5f4SPaul Zimmerman * The Core code provides basic services for accessing and managing the 10197ba5f4SPaul Zimmerman * DWC_otg hardware. These services are used by both the Host Controller 11197ba5f4SPaul Zimmerman * Driver and the Peripheral Controller Driver. 12197ba5f4SPaul Zimmerman */ 13197ba5f4SPaul Zimmerman #include <linux/kernel.h> 14197ba5f4SPaul Zimmerman #include <linux/module.h> 15197ba5f4SPaul Zimmerman #include <linux/moduleparam.h> 16197ba5f4SPaul Zimmerman #include <linux/spinlock.h> 17197ba5f4SPaul Zimmerman #include <linux/interrupt.h> 18197ba5f4SPaul Zimmerman #include <linux/dma-mapping.h> 19197ba5f4SPaul Zimmerman #include <linux/delay.h> 20197ba5f4SPaul Zimmerman #include <linux/io.h> 21197ba5f4SPaul Zimmerman #include <linux/slab.h> 22197ba5f4SPaul Zimmerman #include <linux/usb.h> 23197ba5f4SPaul Zimmerman 24197ba5f4SPaul Zimmerman #include <linux/usb/hcd.h> 25197ba5f4SPaul Zimmerman #include <linux/usb/ch11.h> 26197ba5f4SPaul Zimmerman 27197ba5f4SPaul Zimmerman #include "core.h" 28197ba5f4SPaul Zimmerman #include "hcd.h" 29197ba5f4SPaul Zimmerman 30d17ee77bSGregory Herrero /** 31d17ee77bSGregory Herrero * dwc2_backup_global_registers() - Backup global controller registers. 32d17ee77bSGregory Herrero * When suspending usb bus, registers needs to be backuped 33d17ee77bSGregory Herrero * if controller power is disabled once suspended. 34d17ee77bSGregory Herrero * 35d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 36d17ee77bSGregory Herrero */ 37c5c403dcSVardan Mikayelyan int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) 38d17ee77bSGregory Herrero { 39d17ee77bSGregory Herrero struct dwc2_gregs_backup *gr; 40af7c2bd3SVardan Mikayelyan 41af7c2bd3SVardan Mikayelyan dev_dbg(hsotg->dev, "%s\n", __func__); 42d17ee77bSGregory Herrero 43d17ee77bSGregory Herrero /* Backup global regs */ 44cc1e204cSMian Yousaf Kaukab gr = &hsotg->gr_backup; 45d17ee77bSGregory Herrero 46f25c42b8SGevorg Sahakyan gr->gotgctl = dwc2_readl(hsotg, GOTGCTL); 47f25c42b8SGevorg Sahakyan gr->gintmsk = dwc2_readl(hsotg, GINTMSK); 48f25c42b8SGevorg Sahakyan gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG); 49f25c42b8SGevorg Sahakyan gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG); 50f25c42b8SGevorg Sahakyan gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ); 51f25c42b8SGevorg Sahakyan gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ); 52f25c42b8SGevorg Sahakyan gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG); 53f25c42b8SGevorg Sahakyan gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 54f25c42b8SGevorg Sahakyan gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); 55f25c42b8SGevorg Sahakyan gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); 56f25c42b8SGevorg Sahakyan gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); 57d17ee77bSGregory Herrero 58cc1e204cSMian Yousaf Kaukab gr->valid = true; 59d17ee77bSGregory Herrero return 0; 60d17ee77bSGregory Herrero } 61d17ee77bSGregory Herrero 62d17ee77bSGregory Herrero /** 63d17ee77bSGregory Herrero * dwc2_restore_global_registers() - Restore controller global registers. 64d17ee77bSGregory Herrero * When resuming usb bus, device registers needs to be restored 65d17ee77bSGregory Herrero * if controller power were disabled. 66d17ee77bSGregory Herrero * 67d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 68d17ee77bSGregory Herrero */ 69c5c403dcSVardan Mikayelyan int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) 70d17ee77bSGregory Herrero { 71d17ee77bSGregory Herrero struct dwc2_gregs_backup *gr; 72d17ee77bSGregory Herrero 73d17ee77bSGregory Herrero dev_dbg(hsotg->dev, "%s\n", __func__); 74d17ee77bSGregory Herrero 75d17ee77bSGregory Herrero /* Restore global regs */ 76cc1e204cSMian Yousaf Kaukab gr = &hsotg->gr_backup; 77cc1e204cSMian Yousaf Kaukab if (!gr->valid) { 78d17ee77bSGregory Herrero dev_err(hsotg->dev, "%s: no global registers to restore\n", 79d17ee77bSGregory Herrero __func__); 80d17ee77bSGregory Herrero return -EINVAL; 81d17ee77bSGregory Herrero } 82cc1e204cSMian Yousaf Kaukab gr->valid = false; 83d17ee77bSGregory Herrero 84f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GINTSTS); 85f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); 86f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gintmsk, GINTMSK); 87f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 88f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); 89f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); 90f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); 91f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); 92f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); 93f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); 94f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); 95f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); 96d17ee77bSGregory Herrero 97d17ee77bSGregory Herrero return 0; 98d17ee77bSGregory Herrero } 99d17ee77bSGregory Herrero 100d17ee77bSGregory Herrero /** 10141ba9b9bSVardan Mikayelyan * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. 102d17ee77bSGregory Herrero * 103d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 104c9c394abSArtur Petrosyan * @rem_wakeup: indicates whether resume is initiated by Reset. 105d17ee77bSGregory Herrero * @restore: Controller registers need to be restored 106d17ee77bSGregory Herrero */ 107c9c394abSArtur Petrosyan int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, 108c9c394abSArtur Petrosyan bool restore) 109d17ee77bSGregory Herrero { 110c9c394abSArtur Petrosyan struct dwc2_gregs_backup *gr; 111d17ee77bSGregory Herrero 112c9c394abSArtur Petrosyan gr = &hsotg->gr_backup; 113285046aaSGregory Herrero 114c9c394abSArtur Petrosyan /* 115c9c394abSArtur Petrosyan * Restore host or device regisers with the same mode core enterted 116c9c394abSArtur Petrosyan * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup 117c9c394abSArtur Petrosyan * value of the "gotgctl" register. 118c9c394abSArtur Petrosyan */ 119c9c394abSArtur Petrosyan if (gr->gotgctl & GOTGCTL_CURMODE_HOST) 120c9c394abSArtur Petrosyan return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup, 121c9c394abSArtur Petrosyan restore); 122c9c394abSArtur Petrosyan else 123c9c394abSArtur Petrosyan return dwc2_gadget_exit_partial_power_down(hsotg, restore); 124d17ee77bSGregory Herrero } 125d17ee77bSGregory Herrero 126d17ee77bSGregory Herrero /** 12741ba9b9bSVardan Mikayelyan * dwc2_enter_partial_power_down() - Put controller in Partial Power Down. 128d17ee77bSGregory Herrero * 129d17ee77bSGregory Herrero * @hsotg: Programming view of the DWC_otg controller 130d17ee77bSGregory Herrero */ 13141ba9b9bSVardan Mikayelyan int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) 132d17ee77bSGregory Herrero { 133c9c394abSArtur Petrosyan if (dwc2_is_host_mode(hsotg)) 134c9c394abSArtur Petrosyan return dwc2_host_enter_partial_power_down(hsotg); 135c9c394abSArtur Petrosyan else 136c9c394abSArtur Petrosyan return dwc2_gadget_enter_partial_power_down(hsotg); 137d17ee77bSGregory Herrero } 138d17ee77bSGregory Herrero 139fef6bc37SJohn Youn /** 14094d2666cSVardan Mikayelyan * dwc2_restore_essential_regs() - Restore essiential regs of core. 14194d2666cSVardan Mikayelyan * 14294d2666cSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 14394d2666cSVardan Mikayelyan * @rmode: Restore mode, enabled in case of remote-wakeup. 14494d2666cSVardan Mikayelyan * @is_host: Host or device mode. 14594d2666cSVardan Mikayelyan */ 14694d2666cSVardan Mikayelyan static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, 14794d2666cSVardan Mikayelyan int is_host) 14894d2666cSVardan Mikayelyan { 14994d2666cSVardan Mikayelyan u32 pcgcctl; 15094d2666cSVardan Mikayelyan struct dwc2_gregs_backup *gr; 15194d2666cSVardan Mikayelyan struct dwc2_dregs_backup *dr; 15294d2666cSVardan Mikayelyan struct dwc2_hregs_backup *hr; 15394d2666cSVardan Mikayelyan 15494d2666cSVardan Mikayelyan gr = &hsotg->gr_backup; 15594d2666cSVardan Mikayelyan dr = &hsotg->dr_backup; 15694d2666cSVardan Mikayelyan hr = &hsotg->hr_backup; 15794d2666cSVardan Mikayelyan 15894d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__); 15994d2666cSVardan Mikayelyan 16094d2666cSVardan Mikayelyan /* Load restore values for [31:14] bits */ 16194d2666cSVardan Mikayelyan pcgcctl = (gr->pcgcctl & 0xffffc000); 16294d2666cSVardan Mikayelyan /* If High Speed */ 16394d2666cSVardan Mikayelyan if (is_host) { 16494d2666cSVardan Mikayelyan if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK)) 16594d2666cSVardan Mikayelyan pcgcctl |= BIT(17); 16694d2666cSVardan Mikayelyan } else { 16794d2666cSVardan Mikayelyan if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK)) 16894d2666cSVardan Mikayelyan pcgcctl |= BIT(17); 16994d2666cSVardan Mikayelyan } 170f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 17194d2666cSVardan Mikayelyan 17294d2666cSVardan Mikayelyan /* Umnask global Interrupt in GAHBCFG and restore it */ 173f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG); 17494d2666cSVardan Mikayelyan 17594d2666cSVardan Mikayelyan /* Clear all pending interupts */ 176f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, 0xffffffff, GINTSTS); 17794d2666cSVardan Mikayelyan 17894d2666cSVardan Mikayelyan /* Unmask restore done interrupt */ 179f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK); 18094d2666cSVardan Mikayelyan 18194d2666cSVardan Mikayelyan /* Restore GUSBCFG and HCFG/DCFG */ 182f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 18394d2666cSVardan Mikayelyan 18494d2666cSVardan Mikayelyan if (is_host) { 185f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, hr->hcfg, HCFG); 18694d2666cSVardan Mikayelyan if (rmode) 18794d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_RESTOREMODE; 188f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 18994d2666cSVardan Mikayelyan udelay(10); 19094d2666cSVardan Mikayelyan 19194d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_ESS_REG_RESTORED; 192f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 19394d2666cSVardan Mikayelyan udelay(10); 19494d2666cSVardan Mikayelyan } else { 195f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, dr->dcfg, DCFG); 19694d2666cSVardan Mikayelyan if (!rmode) 19794d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; 198f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 19994d2666cSVardan Mikayelyan udelay(10); 20094d2666cSVardan Mikayelyan 20194d2666cSVardan Mikayelyan pcgcctl |= PCGCTL_ESS_REG_RESTORED; 202f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl, PCGCTL); 20394d2666cSVardan Mikayelyan udelay(10); 20494d2666cSVardan Mikayelyan } 20594d2666cSVardan Mikayelyan } 20694d2666cSVardan Mikayelyan 20794d2666cSVardan Mikayelyan /** 20894d2666cSVardan Mikayelyan * dwc2_hib_restore_common() - Common part of restore routine. 20994d2666cSVardan Mikayelyan * 21094d2666cSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 21194d2666cSVardan Mikayelyan * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 21294d2666cSVardan Mikayelyan * @is_host: Host or device mode. 21394d2666cSVardan Mikayelyan */ 21494d2666cSVardan Mikayelyan void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, 21594d2666cSVardan Mikayelyan int is_host) 21694d2666cSVardan Mikayelyan { 21794d2666cSVardan Mikayelyan u32 gpwrdn; 21894d2666cSVardan Mikayelyan 21994d2666cSVardan Mikayelyan /* Switch-on voltage to the core */ 220f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 22194d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNSWTCH; 222f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 22394d2666cSVardan Mikayelyan udelay(10); 22494d2666cSVardan Mikayelyan 22594d2666cSVardan Mikayelyan /* Reset core */ 226f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 22794d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNRSTN; 228f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 22994d2666cSVardan Mikayelyan udelay(10); 23094d2666cSVardan Mikayelyan 23194d2666cSVardan Mikayelyan /* Enable restore from PMU */ 232f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 23394d2666cSVardan Mikayelyan gpwrdn |= GPWRDN_RESTORE; 234f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 23594d2666cSVardan Mikayelyan udelay(10); 23694d2666cSVardan Mikayelyan 23794d2666cSVardan Mikayelyan /* Disable Power Down Clamp */ 238f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 23994d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PWRDNCLMP; 240f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 24194d2666cSVardan Mikayelyan udelay(50); 24294d2666cSVardan Mikayelyan 24394d2666cSVardan Mikayelyan if (!is_host && rem_wakeup) 24494d2666cSVardan Mikayelyan udelay(70); 24594d2666cSVardan Mikayelyan 24694d2666cSVardan Mikayelyan /* Deassert reset core */ 247f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 24894d2666cSVardan Mikayelyan gpwrdn |= GPWRDN_PWRDNRSTN; 249f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 25094d2666cSVardan Mikayelyan udelay(10); 25194d2666cSVardan Mikayelyan 2524483ef3cSMinas Harutyunyan /* Reset ULPI latch */ 2534483ef3cSMinas Harutyunyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 2544483ef3cSMinas Harutyunyan gpwrdn &= ~GPWRDN_ULPI_LATCH_EN_DURING_HIB_ENTRY; 2554483ef3cSMinas Harutyunyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 2564483ef3cSMinas Harutyunyan 25794d2666cSVardan Mikayelyan /* Disable PMU interrupt */ 258f25c42b8SGevorg Sahakyan gpwrdn = dwc2_readl(hsotg, GPWRDN); 25994d2666cSVardan Mikayelyan gpwrdn &= ~GPWRDN_PMUINTSEL; 260f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gpwrdn, GPWRDN); 26194d2666cSVardan Mikayelyan udelay(10); 26294d2666cSVardan Mikayelyan 26394d2666cSVardan Mikayelyan /* Set Restore Essential Regs bit in PCGCCTL register */ 26494d2666cSVardan Mikayelyan dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host); 26594d2666cSVardan Mikayelyan 26694d2666cSVardan Mikayelyan /* 26794d2666cSVardan Mikayelyan * Wait For Restore_done Interrupt. This mechanism of polling the 26894d2666cSVardan Mikayelyan * interrupt is introduced to avoid any possible race conditions 26994d2666cSVardan Mikayelyan */ 27094d2666cSVardan Mikayelyan if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE, 27194d2666cSVardan Mikayelyan 20000)) { 27294d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, 273a76cb3d9SColin Ian King "%s: Restore Done wasn't generated here\n", 27494d2666cSVardan Mikayelyan __func__); 27594d2666cSVardan Mikayelyan } else { 27694d2666cSVardan Mikayelyan dev_dbg(hsotg->dev, "restore done generated here\n"); 2775160d687SArtur Petrosyan 2785160d687SArtur Petrosyan /* 2795160d687SArtur Petrosyan * To avoid restore done interrupt storm after restore is 2805160d687SArtur Petrosyan * generated clear GINTSTS_RESTOREDONE bit. 2815160d687SArtur Petrosyan */ 2825160d687SArtur Petrosyan dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS); 28394d2666cSVardan Mikayelyan } 28494d2666cSVardan Mikayelyan } 28594d2666cSVardan Mikayelyan 28694d2666cSVardan Mikayelyan /** 287fef6bc37SJohn Youn * dwc2_wait_for_mode() - Waits for the controller mode. 288fef6bc37SJohn Youn * @hsotg: Programming view of the DWC_otg controller. 289fef6bc37SJohn Youn * @host_mode: If true, waits for host mode, otherwise device mode. 290fef6bc37SJohn Youn */ 291fef6bc37SJohn Youn static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, 292fef6bc37SJohn Youn bool host_mode) 293fef6bc37SJohn Youn { 294fef6bc37SJohn Youn ktime_t start; 295fef6bc37SJohn Youn ktime_t end; 296fef6bc37SJohn Youn unsigned int timeout = 110; 297fef6bc37SJohn Youn 298fef6bc37SJohn Youn dev_vdbg(hsotg->dev, "Waiting for %s mode\n", 299fef6bc37SJohn Youn host_mode ? "host" : "device"); 300fef6bc37SJohn Youn 301fef6bc37SJohn Youn start = ktime_get(); 302fef6bc37SJohn Youn 303fef6bc37SJohn Youn while (1) { 304fef6bc37SJohn Youn s64 ms; 305fef6bc37SJohn Youn 306fef6bc37SJohn Youn if (dwc2_is_host_mode(hsotg) == host_mode) { 307fef6bc37SJohn Youn dev_vdbg(hsotg->dev, "%s mode set\n", 308fef6bc37SJohn Youn host_mode ? "Host" : "Device"); 309fef6bc37SJohn Youn break; 310fef6bc37SJohn Youn } 311fef6bc37SJohn Youn 312fef6bc37SJohn Youn end = ktime_get(); 313fef6bc37SJohn Youn ms = ktime_to_ms(ktime_sub(end, start)); 314fef6bc37SJohn Youn 315fef6bc37SJohn Youn if (ms >= (s64)timeout) { 316fef6bc37SJohn Youn dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n", 317fef6bc37SJohn Youn __func__, host_mode ? "host" : "device"); 318fef6bc37SJohn Youn break; 319fef6bc37SJohn Youn } 320fef6bc37SJohn Youn 321fef6bc37SJohn Youn usleep_range(1000, 2000); 322fef6bc37SJohn Youn } 323fef6bc37SJohn Youn } 324fef6bc37SJohn Youn 325fef6bc37SJohn Youn /** 326fef6bc37SJohn Youn * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce 327fef6bc37SJohn Youn * filter is enabled. 3286fb914d7SGrigor Tovmasyan * 3296fb914d7SGrigor Tovmasyan * @hsotg: Programming view of DWC_otg controller 330fef6bc37SJohn Youn */ 331fef6bc37SJohn Youn static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) 332fef6bc37SJohn Youn { 333fef6bc37SJohn Youn u32 gsnpsid; 334fef6bc37SJohn Youn u32 ghwcfg4; 335fef6bc37SJohn Youn 336fef6bc37SJohn Youn if (!dwc2_hw_is_otg(hsotg)) 337fef6bc37SJohn Youn return false; 338fef6bc37SJohn Youn 339fef6bc37SJohn Youn /* Check if core configuration includes the IDDIG filter. */ 340f25c42b8SGevorg Sahakyan ghwcfg4 = dwc2_readl(hsotg, GHWCFG4); 341fef6bc37SJohn Youn if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN)) 342fef6bc37SJohn Youn return false; 343fef6bc37SJohn Youn 344fef6bc37SJohn Youn /* 345fef6bc37SJohn Youn * Check if the IDDIG debounce filter is bypassed. Available 346fef6bc37SJohn Youn * in core version >= 3.10a. 347fef6bc37SJohn Youn */ 348f25c42b8SGevorg Sahakyan gsnpsid = dwc2_readl(hsotg, GSNPSID); 349fef6bc37SJohn Youn if (gsnpsid >= DWC2_CORE_REV_3_10a) { 350f25c42b8SGevorg Sahakyan u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 351fef6bc37SJohn Youn 352fef6bc37SJohn Youn if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS) 353fef6bc37SJohn Youn return false; 354fef6bc37SJohn Youn } 355fef6bc37SJohn Youn 356fef6bc37SJohn Youn return true; 357fef6bc37SJohn Youn } 358fef6bc37SJohn Youn 359197ba5f4SPaul Zimmerman /* 360624815ceSVardan Mikayelyan * dwc2_enter_hibernation() - Common function to enter hibernation. 361624815ceSVardan Mikayelyan * 362624815ceSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 363624815ceSVardan Mikayelyan * @is_host: True if core is in host mode. 364624815ceSVardan Mikayelyan * 365624815ceSVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 366624815ceSVardan Mikayelyan */ 367624815ceSVardan Mikayelyan int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) 368624815ceSVardan Mikayelyan { 369624815ceSVardan Mikayelyan if (is_host) 370624815ceSVardan Mikayelyan return dwc2_host_enter_hibernation(hsotg); 371624815ceSVardan Mikayelyan else 372624815ceSVardan Mikayelyan return dwc2_gadget_enter_hibernation(hsotg); 373624815ceSVardan Mikayelyan } 374624815ceSVardan Mikayelyan 375624815ceSVardan Mikayelyan /* 376624815ceSVardan Mikayelyan * dwc2_exit_hibernation() - Common function to exit from hibernation. 377624815ceSVardan Mikayelyan * 378624815ceSVardan Mikayelyan * @hsotg: Programming view of the DWC_otg controller 379624815ceSVardan Mikayelyan * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 380624815ceSVardan Mikayelyan * @reset: Enabled in case of restore with reset. 381624815ceSVardan Mikayelyan * @is_host: True if core is in host mode. 382624815ceSVardan Mikayelyan * 383624815ceSVardan Mikayelyan * Return: 0 if successful, negative error code otherwise 384624815ceSVardan Mikayelyan */ 385624815ceSVardan Mikayelyan int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, 386624815ceSVardan Mikayelyan int reset, int is_host) 387624815ceSVardan Mikayelyan { 388624815ceSVardan Mikayelyan if (is_host) 389624815ceSVardan Mikayelyan return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset); 390624815ceSVardan Mikayelyan else 391624815ceSVardan Mikayelyan return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset); 392624815ceSVardan Mikayelyan } 393624815ceSVardan Mikayelyan 394624815ceSVardan Mikayelyan /* 395197ba5f4SPaul Zimmerman * Do core a soft reset of the core. Be careful with this because it 396197ba5f4SPaul Zimmerman * resets all the internal state machines of the core. 397197ba5f4SPaul Zimmerman */ 3986e6360b6SJohn Stultz int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) 399197ba5f4SPaul Zimmerman { 400197ba5f4SPaul Zimmerman u32 greset; 401fef6bc37SJohn Youn bool wait_for_host_mode = false; 402197ba5f4SPaul Zimmerman 403197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "%s()\n", __func__); 404197ba5f4SPaul Zimmerman 405fef6bc37SJohn Youn /* 406fef6bc37SJohn Youn * If the current mode is host, either due to the force mode 407fef6bc37SJohn Youn * bit being set (which persists after core reset) or the 408fef6bc37SJohn Youn * connector id pin, a core soft reset will temporarily reset 409fef6bc37SJohn Youn * the mode to device. A delay from the IDDIG debounce filter 410fef6bc37SJohn Youn * will occur before going back to host mode. 411fef6bc37SJohn Youn * 412fef6bc37SJohn Youn * Determine whether we will go back into host mode after a 413fef6bc37SJohn Youn * reset and account for this delay after the reset. 414fef6bc37SJohn Youn */ 415fef6bc37SJohn Youn if (dwc2_iddig_filter_enabled(hsotg)) { 416f25c42b8SGevorg Sahakyan u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 417f25c42b8SGevorg Sahakyan u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG); 418fef6bc37SJohn Youn 419fef6bc37SJohn Youn if (!(gotgctl & GOTGCTL_CONID_B) || 420fef6bc37SJohn Youn (gusbcfg & GUSBCFG_FORCEHOSTMODE)) { 421fef6bc37SJohn Youn wait_for_host_mode = true; 422fef6bc37SJohn Youn } 423fef6bc37SJohn Youn } 424fef6bc37SJohn Youn 425197ba5f4SPaul Zimmerman /* Core Soft Reset */ 426f25c42b8SGevorg Sahakyan greset = dwc2_readl(hsotg, GRSTCTL); 427197ba5f4SPaul Zimmerman greset |= GRSTCTL_CSFTRST; 428f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, greset, GRSTCTL); 42979d6b8c5SSevak Arakelyan 43065dc2e72SMinas Harutyunyan if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) < 43165dc2e72SMinas Harutyunyan (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) { 43265dc2e72SMinas Harutyunyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, 43365dc2e72SMinas Harutyunyan GRSTCTL_CSFTRST, 10000)) { 43465dc2e72SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n", 43579d6b8c5SSevak Arakelyan __func__); 436197ba5f4SPaul Zimmerman return -EBUSY; 437197ba5f4SPaul Zimmerman } 43865dc2e72SMinas Harutyunyan } else { 43965dc2e72SMinas Harutyunyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, 44065dc2e72SMinas Harutyunyan GRSTCTL_CSFTRST_DONE, 10000)) { 44165dc2e72SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n", 44265dc2e72SMinas Harutyunyan __func__); 44365dc2e72SMinas Harutyunyan return -EBUSY; 44465dc2e72SMinas Harutyunyan } 44565dc2e72SMinas Harutyunyan greset = dwc2_readl(hsotg, GRSTCTL); 44665dc2e72SMinas Harutyunyan greset &= ~GRSTCTL_CSFTRST; 44765dc2e72SMinas Harutyunyan greset |= GRSTCTL_CSFTRST_DONE; 44865dc2e72SMinas Harutyunyan dwc2_writel(hsotg, greset, GRSTCTL); 44965dc2e72SMinas Harutyunyan } 450197ba5f4SPaul Zimmerman 451238f65aeSArtur Petrosyan /* 452238f65aeSArtur Petrosyan * Switching from device mode to host mode by disconnecting 453238f65aeSArtur Petrosyan * device cable core enters and exits form hibernation. 454238f65aeSArtur Petrosyan * However, the fifo map remains not cleared. It results 455238f65aeSArtur Petrosyan * to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ 456238f65aeSArtur Petrosyan * gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) 457238f65aeSArtur Petrosyan * if in host mode we disconnect the micro a to b host 458238f65aeSArtur Petrosyan * cable. Because core reset occurs. 459238f65aeSArtur Petrosyan * To avoid the WARNING, fifo_map should be cleared 460238f65aeSArtur Petrosyan * in dwc2_core_reset() function by taking into account configs. 461238f65aeSArtur Petrosyan * fifo_map must be cleared only if driver is configured in 462238f65aeSArtur Petrosyan * "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" 463238f65aeSArtur Petrosyan * mode. 464238f65aeSArtur Petrosyan */ 465238f65aeSArtur Petrosyan dwc2_clear_fifo_map(hsotg); 466238f65aeSArtur Petrosyan 467b8ccc593SJohn Youn /* Wait for AHB master IDLE state */ 468dfc4fdebSMartin Blumenstingl if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) { 46979d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", 47079d6b8c5SSevak Arakelyan __func__); 471b8ccc593SJohn Youn return -EBUSY; 472b8ccc593SJohn Youn } 473b8ccc593SJohn Youn 4746e6360b6SJohn Stultz if (wait_for_host_mode && !skip_wait) 475fef6bc37SJohn Youn dwc2_wait_for_mode(hsotg, true); 476fef6bc37SJohn Youn 477b5d308abSJohn Youn return 0; 478b5d308abSJohn Youn } 479b5d308abSJohn Youn 48013b1f8e2SVardan Mikayelyan /** 48113b1f8e2SVardan Mikayelyan * dwc2_force_mode() - Force the mode of the controller. 48209c96980SJohn Youn * 48309c96980SJohn Youn * Forcing the mode is needed for two cases: 48409c96980SJohn Youn * 48509c96980SJohn Youn * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the 48609c96980SJohn Youn * controller to stay in a particular mode regardless of ID pin 48713b1f8e2SVardan Mikayelyan * changes. We do this once during probe. 48809c96980SJohn Youn * 48909c96980SJohn Youn * 2) During probe we want to read reset values of the hw 49009c96980SJohn Youn * configuration registers that are only available in either host or 49109c96980SJohn Youn * device mode. We may need to force the mode if the current mode does 49209c96980SJohn Youn * not allow us to access the register in the mode that we want. 49309c96980SJohn Youn * 49409c96980SJohn Youn * In either case it only makes sense to force the mode if the 49509c96980SJohn Youn * controller hardware is OTG capable. 49609c96980SJohn Youn * 49709c96980SJohn Youn * Checks are done in this function to determine whether doing a force 49809c96980SJohn Youn * would be valid or not. 49909c96980SJohn Youn * 5002938fc63SJohn Youn * If a force is done, it requires a IDDIG debounce filter delay if 5012938fc63SJohn Youn * the filter is configured and enabled. We poll the current mode of 5022938fc63SJohn Youn * the controller to account for this delay. 5036fb914d7SGrigor Tovmasyan * 5046fb914d7SGrigor Tovmasyan * @hsotg: Programming view of DWC_otg controller 5056fb914d7SGrigor Tovmasyan * @host: Host mode flag 50609c96980SJohn Youn */ 50713b1f8e2SVardan Mikayelyan void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) 50809c96980SJohn Youn { 50909c96980SJohn Youn u32 gusbcfg; 51009c96980SJohn Youn u32 set; 51109c96980SJohn Youn u32 clear; 51209c96980SJohn Youn 51309c96980SJohn Youn dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device"); 51409c96980SJohn Youn 51509c96980SJohn Youn /* 51609c96980SJohn Youn * Force mode has no effect if the hardware is not OTG. 51709c96980SJohn Youn */ 51809c96980SJohn Youn if (!dwc2_hw_is_otg(hsotg)) 51913b1f8e2SVardan Mikayelyan return; 52009c96980SJohn Youn 52109c96980SJohn Youn /* 52209c96980SJohn Youn * If dr_mode is either peripheral or host only, there is no 52309c96980SJohn Youn * need to ever force the mode to the opposite mode. 52409c96980SJohn Youn */ 52509c96980SJohn Youn if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) 52613b1f8e2SVardan Mikayelyan return; 52709c96980SJohn Youn 52809c96980SJohn Youn if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST)) 52913b1f8e2SVardan Mikayelyan return; 53009c96980SJohn Youn 531f25c42b8SGevorg Sahakyan gusbcfg = dwc2_readl(hsotg, GUSBCFG); 53209c96980SJohn Youn 53309c96980SJohn Youn set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; 53409c96980SJohn Youn clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; 53509c96980SJohn Youn 53609c96980SJohn Youn gusbcfg &= ~clear; 53709c96980SJohn Youn gusbcfg |= set; 538f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gusbcfg, GUSBCFG); 53909c96980SJohn Youn 5402938fc63SJohn Youn dwc2_wait_for_mode(hsotg, host); 54113b1f8e2SVardan Mikayelyan return; 54209c96980SJohn Youn } 54309c96980SJohn Youn 5442938fc63SJohn Youn /** 5452938fc63SJohn Youn * dwc2_clear_force_mode() - Clears the force mode bits. 5462938fc63SJohn Youn * 5472938fc63SJohn Youn * After clearing the bits, wait up to 100 ms to account for any 5482938fc63SJohn Youn * potential IDDIG filter delay. We can't know if we expect this delay 5492938fc63SJohn Youn * or not because the value of the connector ID status is affected by 5502938fc63SJohn Youn * the force mode. We only need to call this once during probe if 5512938fc63SJohn Youn * dr_mode == OTG. 5526fb914d7SGrigor Tovmasyan * 5536fb914d7SGrigor Tovmasyan * @hsotg: Programming view of DWC_otg controller 55409c96980SJohn Youn */ 555365b7673SGrigor Tovmasyan static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) 55609c96980SJohn Youn { 55709c96980SJohn Youn u32 gusbcfg; 55809c96980SJohn Youn 55913b1f8e2SVardan Mikayelyan if (!dwc2_hw_is_otg(hsotg)) 56013b1f8e2SVardan Mikayelyan return; 56113b1f8e2SVardan Mikayelyan 56213b1f8e2SVardan Mikayelyan dev_dbg(hsotg->dev, "Clearing force mode bits\n"); 56313b1f8e2SVardan Mikayelyan 564f25c42b8SGevorg Sahakyan gusbcfg = dwc2_readl(hsotg, GUSBCFG); 56509c96980SJohn Youn gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; 56609c96980SJohn Youn gusbcfg &= ~GUSBCFG_FORCEDEVMODE; 567f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, gusbcfg, GUSBCFG); 56809c96980SJohn Youn 5692938fc63SJohn Youn if (dwc2_iddig_filter_enabled(hsotg)) 570d3fe81d2SNicholas Mc Guire msleep(100); 57109c96980SJohn Youn } 57209c96980SJohn Youn 57309c96980SJohn Youn /* 57409c96980SJohn Youn * Sets or clears force mode based on the dr_mode parameter. 57509c96980SJohn Youn */ 57609c96980SJohn Youn void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) 57709c96980SJohn Youn { 57809c96980SJohn Youn switch (hsotg->dr_mode) { 57909c96980SJohn Youn case USB_DR_MODE_HOST: 580a07ce8d3SHeiko Stuebner /* 581a07ce8d3SHeiko Stuebner * NOTE: This is required for some rockchip soc based 582a07ce8d3SHeiko Stuebner * platforms on their host-only dwc2. 583a07ce8d3SHeiko Stuebner */ 58413b1f8e2SVardan Mikayelyan if (!dwc2_hw_is_otg(hsotg)) 585a07ce8d3SHeiko Stuebner msleep(50); 586a07ce8d3SHeiko Stuebner 58709c96980SJohn Youn break; 58809c96980SJohn Youn case USB_DR_MODE_PERIPHERAL: 58909c96980SJohn Youn dwc2_force_mode(hsotg, false); 59009c96980SJohn Youn break; 59109c96980SJohn Youn case USB_DR_MODE_OTG: 59209c96980SJohn Youn dwc2_clear_force_mode(hsotg); 59309c96980SJohn Youn break; 59409c96980SJohn Youn default: 59509c96980SJohn Youn dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n", 59609c96980SJohn Youn __func__, hsotg->dr_mode); 59709c96980SJohn Youn break; 59809c96980SJohn Youn } 59909c96980SJohn Youn } 60009c96980SJohn Youn 60109c96980SJohn Youn /* 60266e77a24SRazmik Karapetyan * dwc2_enable_acg - enable active clock gating feature 60366e77a24SRazmik Karapetyan */ 60466e77a24SRazmik Karapetyan void dwc2_enable_acg(struct dwc2_hsotg *hsotg) 60566e77a24SRazmik Karapetyan { 60666e77a24SRazmik Karapetyan if (hsotg->params.acg_enable) { 607f25c42b8SGevorg Sahakyan u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 60866e77a24SRazmik Karapetyan 60966e77a24SRazmik Karapetyan dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n"); 61066e77a24SRazmik Karapetyan pcgcctl1 |= PCGCCTL1_GATEEN; 611f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, pcgcctl1, PCGCCTL1); 61266e77a24SRazmik Karapetyan } 61366e77a24SRazmik Karapetyan } 61466e77a24SRazmik Karapetyan 615197ba5f4SPaul Zimmerman /** 616197ba5f4SPaul Zimmerman * dwc2_dump_host_registers() - Prints the host registers 617197ba5f4SPaul Zimmerman * 618197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 619197ba5f4SPaul Zimmerman * 620197ba5f4SPaul Zimmerman * NOTE: This function will be removed once the peripheral controller code 621197ba5f4SPaul Zimmerman * is integrated and the driver is stable 622197ba5f4SPaul Zimmerman */ 623197ba5f4SPaul Zimmerman void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) 624197ba5f4SPaul Zimmerman { 625197ba5f4SPaul Zimmerman #ifdef DEBUG 626197ba5f4SPaul Zimmerman u32 __iomem *addr; 627197ba5f4SPaul Zimmerman int i; 628197ba5f4SPaul Zimmerman 629197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Host Global Registers\n"); 630197ba5f4SPaul Zimmerman addr = hsotg->regs + HCFG; 631197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", 632f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCFG)); 633197ba5f4SPaul Zimmerman addr = hsotg->regs + HFIR; 634197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n", 635f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HFIR)); 636197ba5f4SPaul Zimmerman addr = hsotg->regs + HFNUM; 637197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n", 638f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HFNUM)); 639197ba5f4SPaul Zimmerman addr = hsotg->regs + HPTXSTS; 640197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n", 641f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HPTXSTS)); 642197ba5f4SPaul Zimmerman addr = hsotg->regs + HAINT; 643197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n", 644f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HAINT)); 645197ba5f4SPaul Zimmerman addr = hsotg->regs + HAINTMSK; 646197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", 647f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HAINTMSK)); 64895832c00SJohn Youn if (hsotg->params.dma_desc_enable) { 649197ba5f4SPaul Zimmerman addr = hsotg->regs + HFLBADDR; 650197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", 651f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HFLBADDR)); 652197ba5f4SPaul Zimmerman } 653197ba5f4SPaul Zimmerman 654197ba5f4SPaul Zimmerman addr = hsotg->regs + HPRT0; 655197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n", 656f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HPRT0)); 657197ba5f4SPaul Zimmerman 658bea8e86cSJohn Youn for (i = 0; i < hsotg->params.host_channels; i++) { 659197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); 660197ba5f4SPaul Zimmerman addr = hsotg->regs + HCCHAR(i); 661197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n", 662f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i))); 663197ba5f4SPaul Zimmerman addr = hsotg->regs + HCSPLT(i); 664197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n", 665f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i))); 666197ba5f4SPaul Zimmerman addr = hsotg->regs + HCINT(i); 667197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n", 668f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCINT(i))); 669197ba5f4SPaul Zimmerman addr = hsotg->regs + HCINTMSK(i); 670197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n", 671f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i))); 672197ba5f4SPaul Zimmerman addr = hsotg->regs + HCTSIZ(i); 673197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n", 674f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i))); 675197ba5f4SPaul Zimmerman addr = hsotg->regs + HCDMA(i); 676197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", 677f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HCDMA(i))); 67895832c00SJohn Youn if (hsotg->params.dma_desc_enable) { 679197ba5f4SPaul Zimmerman addr = hsotg->regs + HCDMAB(i); 680197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", 681f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, 682f25c42b8SGevorg Sahakyan HCDMAB(i))); 683197ba5f4SPaul Zimmerman } 684197ba5f4SPaul Zimmerman } 685197ba5f4SPaul Zimmerman #endif 686197ba5f4SPaul Zimmerman } 687197ba5f4SPaul Zimmerman 688197ba5f4SPaul Zimmerman /** 689197ba5f4SPaul Zimmerman * dwc2_dump_global_registers() - Prints the core global registers 690197ba5f4SPaul Zimmerman * 691197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 692197ba5f4SPaul Zimmerman * 693197ba5f4SPaul Zimmerman * NOTE: This function will be removed once the peripheral controller code 694197ba5f4SPaul Zimmerman * is integrated and the driver is stable 695197ba5f4SPaul Zimmerman */ 696197ba5f4SPaul Zimmerman void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) 697197ba5f4SPaul Zimmerman { 698197ba5f4SPaul Zimmerman #ifdef DEBUG 699197ba5f4SPaul Zimmerman u32 __iomem *addr; 700197ba5f4SPaul Zimmerman 701197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "Core Global Registers\n"); 702197ba5f4SPaul Zimmerman addr = hsotg->regs + GOTGCTL; 703197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n", 704f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GOTGCTL)); 705197ba5f4SPaul Zimmerman addr = hsotg->regs + GOTGINT; 706197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n", 707f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GOTGINT)); 708197ba5f4SPaul Zimmerman addr = hsotg->regs + GAHBCFG; 709197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n", 710f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GAHBCFG)); 711197ba5f4SPaul Zimmerman addr = hsotg->regs + GUSBCFG; 712197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n", 713f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GUSBCFG)); 714197ba5f4SPaul Zimmerman addr = hsotg->regs + GRSTCTL; 715197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n", 716f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GRSTCTL)); 717197ba5f4SPaul Zimmerman addr = hsotg->regs + GINTSTS; 718197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n", 719f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GINTSTS)); 720197ba5f4SPaul Zimmerman addr = hsotg->regs + GINTMSK; 721197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n", 722f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GINTMSK)); 723197ba5f4SPaul Zimmerman addr = hsotg->regs + GRXSTSR; 724197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n", 725f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GRXSTSR)); 726197ba5f4SPaul Zimmerman addr = hsotg->regs + GRXFSIZ; 727197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n", 728f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ)); 729197ba5f4SPaul Zimmerman addr = hsotg->regs + GNPTXFSIZ; 730197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n", 731f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ)); 732197ba5f4SPaul Zimmerman addr = hsotg->regs + GNPTXSTS; 733197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n", 734f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS)); 735197ba5f4SPaul Zimmerman addr = hsotg->regs + GI2CCTL; 736197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n", 737f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GI2CCTL)); 738197ba5f4SPaul Zimmerman addr = hsotg->regs + GPVNDCTL; 739197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", 740f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL)); 741197ba5f4SPaul Zimmerman addr = hsotg->regs + GGPIO; 742197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", 743f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GGPIO)); 744197ba5f4SPaul Zimmerman addr = hsotg->regs + GUID; 745197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", 746f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GUID)); 747197ba5f4SPaul Zimmerman addr = hsotg->regs + GSNPSID; 748197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n", 749f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GSNPSID)); 750197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG1; 751197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n", 752f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GHWCFG1)); 753197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG2; 754197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n", 755f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GHWCFG2)); 756197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG3; 757197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n", 758f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GHWCFG3)); 759197ba5f4SPaul Zimmerman addr = hsotg->regs + GHWCFG4; 760197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n", 761f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GHWCFG4)); 762197ba5f4SPaul Zimmerman addr = hsotg->regs + GLPMCFG; 763197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n", 764f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GLPMCFG)); 765197ba5f4SPaul Zimmerman addr = hsotg->regs + GPWRDN; 766197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n", 767f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GPWRDN)); 768197ba5f4SPaul Zimmerman addr = hsotg->regs + GDFIFOCFG; 769197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n", 770f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG)); 771197ba5f4SPaul Zimmerman addr = hsotg->regs + HPTXFSIZ; 772197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", 773f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ)); 774197ba5f4SPaul Zimmerman 775197ba5f4SPaul Zimmerman addr = hsotg->regs + PCGCTL; 776197ba5f4SPaul Zimmerman dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", 777f25c42b8SGevorg Sahakyan (unsigned long)addr, dwc2_readl(hsotg, PCGCTL)); 778197ba5f4SPaul Zimmerman #endif 779197ba5f4SPaul Zimmerman } 780197ba5f4SPaul Zimmerman 781197ba5f4SPaul Zimmerman /** 782197ba5f4SPaul Zimmerman * dwc2_flush_tx_fifo() - Flushes a Tx FIFO 783197ba5f4SPaul Zimmerman * 784197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 785197ba5f4SPaul Zimmerman * @num: Tx FIFO to flush 786197ba5f4SPaul Zimmerman */ 787197ba5f4SPaul Zimmerman void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num) 788197ba5f4SPaul Zimmerman { 789197ba5f4SPaul Zimmerman u32 greset; 790197ba5f4SPaul Zimmerman 791197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num); 792197ba5f4SPaul Zimmerman 7938f55fd60SMinas Harutyunyan /* Wait for AHB master IDLE state */ 7948f55fd60SMinas Harutyunyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 7958f55fd60SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 7968f55fd60SMinas Harutyunyan __func__); 7978f55fd60SMinas Harutyunyan 798197ba5f4SPaul Zimmerman greset = GRSTCTL_TXFFLSH; 799197ba5f4SPaul Zimmerman greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; 800f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, greset, GRSTCTL); 801197ba5f4SPaul Zimmerman 80279d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000)) 80379d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n", 80479d6b8c5SSevak Arakelyan __func__); 805197ba5f4SPaul Zimmerman 806197ba5f4SPaul Zimmerman /* Wait for at least 3 PHY Clocks */ 807197ba5f4SPaul Zimmerman udelay(1); 808197ba5f4SPaul Zimmerman } 809197ba5f4SPaul Zimmerman 810197ba5f4SPaul Zimmerman /** 811197ba5f4SPaul Zimmerman * dwc2_flush_rx_fifo() - Flushes the Rx FIFO 812197ba5f4SPaul Zimmerman * 813197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 814197ba5f4SPaul Zimmerman */ 815197ba5f4SPaul Zimmerman void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg) 816197ba5f4SPaul Zimmerman { 817197ba5f4SPaul Zimmerman u32 greset; 818197ba5f4SPaul Zimmerman 819197ba5f4SPaul Zimmerman dev_vdbg(hsotg->dev, "%s()\n", __func__); 820197ba5f4SPaul Zimmerman 8218f55fd60SMinas Harutyunyan /* Wait for AHB master IDLE state */ 8228f55fd60SMinas Harutyunyan if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 8238f55fd60SMinas Harutyunyan dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 8248f55fd60SMinas Harutyunyan __func__); 8258f55fd60SMinas Harutyunyan 826197ba5f4SPaul Zimmerman greset = GRSTCTL_RXFFLSH; 827f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, greset, GRSTCTL); 828197ba5f4SPaul Zimmerman 82979d6b8c5SSevak Arakelyan /* Wait for RxFIFO flush done */ 83079d6b8c5SSevak Arakelyan if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000)) 83179d6b8c5SSevak Arakelyan dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n", 83279d6b8c5SSevak Arakelyan __func__); 833197ba5f4SPaul Zimmerman 834197ba5f4SPaul Zimmerman /* Wait for at least 3 PHY Clocks */ 835197ba5f4SPaul Zimmerman udelay(1); 836197ba5f4SPaul Zimmerman } 837197ba5f4SPaul Zimmerman 838197ba5f4SPaul Zimmerman bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) 839197ba5f4SPaul Zimmerman { 840f25c42b8SGevorg Sahakyan if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff) 841197ba5f4SPaul Zimmerman return false; 842197ba5f4SPaul Zimmerman else 843197ba5f4SPaul Zimmerman return true; 844197ba5f4SPaul Zimmerman } 845197ba5f4SPaul Zimmerman 846197ba5f4SPaul Zimmerman /** 847197ba5f4SPaul Zimmerman * dwc2_enable_global_interrupts() - Enables the controller's Global 848197ba5f4SPaul Zimmerman * Interrupt in the AHB Config register 849197ba5f4SPaul Zimmerman * 850197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 851197ba5f4SPaul Zimmerman */ 852197ba5f4SPaul Zimmerman void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg) 853197ba5f4SPaul Zimmerman { 854f25c42b8SGevorg Sahakyan u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 855197ba5f4SPaul Zimmerman 856197ba5f4SPaul Zimmerman ahbcfg |= GAHBCFG_GLBL_INTR_EN; 857f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ahbcfg, GAHBCFG); 858197ba5f4SPaul Zimmerman } 859197ba5f4SPaul Zimmerman 860197ba5f4SPaul Zimmerman /** 861197ba5f4SPaul Zimmerman * dwc2_disable_global_interrupts() - Disables the controller's Global 862197ba5f4SPaul Zimmerman * Interrupt in the AHB Config register 863197ba5f4SPaul Zimmerman * 864197ba5f4SPaul Zimmerman * @hsotg: Programming view of DWC_otg controller 865197ba5f4SPaul Zimmerman */ 866197ba5f4SPaul Zimmerman void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) 867197ba5f4SPaul Zimmerman { 868f25c42b8SGevorg Sahakyan u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 869197ba5f4SPaul Zimmerman 870197ba5f4SPaul Zimmerman ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; 871f25c42b8SGevorg Sahakyan dwc2_writel(hsotg, ahbcfg, GAHBCFG); 872197ba5f4SPaul Zimmerman } 873197ba5f4SPaul Zimmerman 8746bea9620SJohn Youn /* Returns the controller's GHWCFG2.OTG_MODE. */ 8759da51974SJohn Youn unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) 8766bea9620SJohn Youn { 877f25c42b8SGevorg Sahakyan u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2); 8786bea9620SJohn Youn 8796bea9620SJohn Youn return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >> 8806bea9620SJohn Youn GHWCFG2_OP_MODE_SHIFT; 8816bea9620SJohn Youn } 8826bea9620SJohn Youn 8836bea9620SJohn Youn /* Returns true if the controller is capable of DRD. */ 8846bea9620SJohn Youn bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) 8856bea9620SJohn Youn { 8869da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 8876bea9620SJohn Youn 8886bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || 8896bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || 8906bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE); 8916bea9620SJohn Youn } 8926bea9620SJohn Youn 8936bea9620SJohn Youn /* Returns true if the controller is host-only. */ 8946bea9620SJohn Youn bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) 8956bea9620SJohn Youn { 8969da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 8976bea9620SJohn Youn 8986bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || 8996bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); 9006bea9620SJohn Youn } 9016bea9620SJohn Youn 9026bea9620SJohn Youn /* Returns true if the controller is device-only. */ 9036bea9620SJohn Youn bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) 9046bea9620SJohn Youn { 9059da51974SJohn Youn unsigned int op_mode = dwc2_op_mode(hsotg); 9066bea9620SJohn Youn 9076bea9620SJohn Youn return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || 9086bea9620SJohn Youn (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); 9096bea9620SJohn Youn } 9106bea9620SJohn Youn 91179d6b8c5SSevak Arakelyan /** 91279d6b8c5SSevak Arakelyan * dwc2_hsotg_wait_bit_set - Waits for bit to be set. 91379d6b8c5SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller. 91479d6b8c5SSevak Arakelyan * @offset: Register's offset where bit/bits must be set. 91579d6b8c5SSevak Arakelyan * @mask: Mask of the bit/bits which must be set. 91679d6b8c5SSevak Arakelyan * @timeout: Timeout to wait. 91779d6b8c5SSevak Arakelyan * 91879d6b8c5SSevak Arakelyan * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 91979d6b8c5SSevak Arakelyan */ 92079d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 92179d6b8c5SSevak Arakelyan u32 timeout) 92279d6b8c5SSevak Arakelyan { 92379d6b8c5SSevak Arakelyan u32 i; 92479d6b8c5SSevak Arakelyan 92579d6b8c5SSevak Arakelyan for (i = 0; i < timeout; i++) { 926f25c42b8SGevorg Sahakyan if (dwc2_readl(hsotg, offset) & mask) 92779d6b8c5SSevak Arakelyan return 0; 92879d6b8c5SSevak Arakelyan udelay(1); 92979d6b8c5SSevak Arakelyan } 93079d6b8c5SSevak Arakelyan 93179d6b8c5SSevak Arakelyan return -ETIMEDOUT; 93279d6b8c5SSevak Arakelyan } 93379d6b8c5SSevak Arakelyan 93479d6b8c5SSevak Arakelyan /** 93579d6b8c5SSevak Arakelyan * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear. 93679d6b8c5SSevak Arakelyan * @hsotg: Programming view of DWC_otg controller. 93779d6b8c5SSevak Arakelyan * @offset: Register's offset where bit/bits must be set. 93879d6b8c5SSevak Arakelyan * @mask: Mask of the bit/bits which must be set. 93979d6b8c5SSevak Arakelyan * @timeout: Timeout to wait. 94079d6b8c5SSevak Arakelyan * 94179d6b8c5SSevak Arakelyan * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 94279d6b8c5SSevak Arakelyan */ 94379d6b8c5SSevak Arakelyan int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 94479d6b8c5SSevak Arakelyan u32 timeout) 94579d6b8c5SSevak Arakelyan { 94679d6b8c5SSevak Arakelyan u32 i; 94779d6b8c5SSevak Arakelyan 94879d6b8c5SSevak Arakelyan for (i = 0; i < timeout; i++) { 949f25c42b8SGevorg Sahakyan if (!(dwc2_readl(hsotg, offset) & mask)) 95079d6b8c5SSevak Arakelyan return 0; 95179d6b8c5SSevak Arakelyan udelay(1); 95279d6b8c5SSevak Arakelyan } 95379d6b8c5SSevak Arakelyan 95479d6b8c5SSevak Arakelyan return -ETIMEDOUT; 95579d6b8c5SSevak Arakelyan } 95679d6b8c5SSevak Arakelyan 957059d8d52SJules Maselbas /* 958059d8d52SJules Maselbas * Initializes the FSLSPClkSel field of the HCFG register depending on the 959059d8d52SJules Maselbas * PHY type 960059d8d52SJules Maselbas */ 961059d8d52SJules Maselbas void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) 962059d8d52SJules Maselbas { 963059d8d52SJules Maselbas u32 hcfg, val; 964059d8d52SJules Maselbas 965059d8d52SJules Maselbas if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 966059d8d52SJules Maselbas hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 967059d8d52SJules Maselbas hsotg->params.ulpi_fs_ls) || 968059d8d52SJules Maselbas hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 969059d8d52SJules Maselbas /* Full speed PHY */ 970059d8d52SJules Maselbas val = HCFG_FSLSPCLKSEL_48_MHZ; 971059d8d52SJules Maselbas } else { 972059d8d52SJules Maselbas /* High speed PHY running at full speed or high speed */ 973059d8d52SJules Maselbas val = HCFG_FSLSPCLKSEL_30_60_MHZ; 974059d8d52SJules Maselbas } 975059d8d52SJules Maselbas 976059d8d52SJules Maselbas dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); 977059d8d52SJules Maselbas hcfg = dwc2_readl(hsotg, HCFG); 978059d8d52SJules Maselbas hcfg &= ~HCFG_FSLSPCLKSEL_MASK; 979059d8d52SJules Maselbas hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; 980059d8d52SJules Maselbas dwc2_writel(hsotg, hcfg, HCFG); 981059d8d52SJules Maselbas } 982059d8d52SJules Maselbas 983*f8453bbdSMinas Harutyunyan static void dwc2_set_clock_switch_timer(struct dwc2_hsotg *hsotg) 984*f8453bbdSMinas Harutyunyan { 985*f8453bbdSMinas Harutyunyan u32 grstctl, gsnpsid, val = 0; 986*f8453bbdSMinas Harutyunyan 987*f8453bbdSMinas Harutyunyan gsnpsid = dwc2_readl(hsotg, GSNPSID); 988*f8453bbdSMinas Harutyunyan 989*f8453bbdSMinas Harutyunyan /* 990*f8453bbdSMinas Harutyunyan * Applicable only to HSOTG core v5.00a or higher. 991*f8453bbdSMinas Harutyunyan * Not applicable to HS/FS IOT devices. 992*f8453bbdSMinas Harutyunyan */ 993*f8453bbdSMinas Harutyunyan if ((gsnpsid & ~DWC2_CORE_REV_MASK) != DWC2_OTG_ID || 994*f8453bbdSMinas Harutyunyan gsnpsid < DWC2_CORE_REV_5_00a) 995*f8453bbdSMinas Harutyunyan return; 996*f8453bbdSMinas Harutyunyan 997*f8453bbdSMinas Harutyunyan if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI && 998*f8453bbdSMinas Harutyunyan hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) || 999*f8453bbdSMinas Harutyunyan (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 1000*f8453bbdSMinas Harutyunyan hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) || 1001*f8453bbdSMinas Harutyunyan (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED && 1002*f8453bbdSMinas Harutyunyan hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED)) { 1003*f8453bbdSMinas Harutyunyan val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_DIS; 1004*f8453bbdSMinas Harutyunyan } 1005*f8453bbdSMinas Harutyunyan 1006*f8453bbdSMinas Harutyunyan if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW && 1007*f8453bbdSMinas Harutyunyan hsotg->hw_params.hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED && 1008*f8453bbdSMinas Harutyunyan hsotg->hw_params.fs_phy_type != GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED) { 1009*f8453bbdSMinas Harutyunyan val = GRSTCTL_CLOCK_SWITH_TIMER_VALUE_147; 1010*f8453bbdSMinas Harutyunyan } 1011*f8453bbdSMinas Harutyunyan 1012*f8453bbdSMinas Harutyunyan grstctl = dwc2_readl(hsotg, GRSTCTL); 1013*f8453bbdSMinas Harutyunyan grstctl &= ~GRSTCTL_CLOCK_SWITH_TIMER_MASK; 1014*f8453bbdSMinas Harutyunyan grstctl |= GRSTCTL_CLOCK_SWITH_TIMER(val); 1015*f8453bbdSMinas Harutyunyan dwc2_writel(hsotg, grstctl, GRSTCTL); 1016*f8453bbdSMinas Harutyunyan } 1017*f8453bbdSMinas Harutyunyan 1018059d8d52SJules Maselbas static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 1019059d8d52SJules Maselbas { 1020059d8d52SJules Maselbas u32 usbcfg, ggpio, i2cctl; 1021059d8d52SJules Maselbas int retval = 0; 1022059d8d52SJules Maselbas 1023059d8d52SJules Maselbas /* 1024059d8d52SJules Maselbas * core_init() is now called on every switch so only call the 1025059d8d52SJules Maselbas * following for the first time through 1026059d8d52SJules Maselbas */ 1027059d8d52SJules Maselbas if (select_phy) { 1028059d8d52SJules Maselbas dev_dbg(hsotg->dev, "FS PHY selected\n"); 1029059d8d52SJules Maselbas 1030059d8d52SJules Maselbas usbcfg = dwc2_readl(hsotg, GUSBCFG); 1031059d8d52SJules Maselbas if (!(usbcfg & GUSBCFG_PHYSEL)) { 1032059d8d52SJules Maselbas usbcfg |= GUSBCFG_PHYSEL; 1033059d8d52SJules Maselbas dwc2_writel(hsotg, usbcfg, GUSBCFG); 1034059d8d52SJules Maselbas 1035*f8453bbdSMinas Harutyunyan dwc2_set_clock_switch_timer(hsotg); 1036*f8453bbdSMinas Harutyunyan 1037059d8d52SJules Maselbas /* Reset after a PHY select */ 1038059d8d52SJules Maselbas retval = dwc2_core_reset(hsotg, false); 1039059d8d52SJules Maselbas 1040059d8d52SJules Maselbas if (retval) { 1041059d8d52SJules Maselbas dev_err(hsotg->dev, 1042059d8d52SJules Maselbas "%s: Reset failed, aborting", __func__); 1043059d8d52SJules Maselbas return retval; 1044059d8d52SJules Maselbas } 1045059d8d52SJules Maselbas } 1046059d8d52SJules Maselbas 1047059d8d52SJules Maselbas if (hsotg->params.activate_stm_fs_transceiver) { 1048059d8d52SJules Maselbas ggpio = dwc2_readl(hsotg, GGPIO); 1049059d8d52SJules Maselbas if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { 1050059d8d52SJules Maselbas dev_dbg(hsotg->dev, "Activating transceiver\n"); 1051059d8d52SJules Maselbas /* 1052059d8d52SJules Maselbas * STM32F4x9 uses the GGPIO register as general 1053059d8d52SJules Maselbas * core configuration register. 1054059d8d52SJules Maselbas */ 1055059d8d52SJules Maselbas ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; 1056059d8d52SJules Maselbas dwc2_writel(hsotg, ggpio, GGPIO); 1057059d8d52SJules Maselbas } 1058059d8d52SJules Maselbas } 1059059d8d52SJules Maselbas } 1060059d8d52SJules Maselbas 1061059d8d52SJules Maselbas /* 1062059d8d52SJules Maselbas * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also 1063059d8d52SJules Maselbas * do this on HNP Dev/Host mode switches (done in dev_init and 1064059d8d52SJules Maselbas * host_init). 1065059d8d52SJules Maselbas */ 1066059d8d52SJules Maselbas if (dwc2_is_host_mode(hsotg)) 1067059d8d52SJules Maselbas dwc2_init_fs_ls_pclk_sel(hsotg); 1068059d8d52SJules Maselbas 1069059d8d52SJules Maselbas if (hsotg->params.i2c_enable) { 1070059d8d52SJules Maselbas dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); 1071059d8d52SJules Maselbas 1072059d8d52SJules Maselbas /* Program GUSBCFG.OtgUtmiFsSel to I2C */ 1073059d8d52SJules Maselbas usbcfg = dwc2_readl(hsotg, GUSBCFG); 1074059d8d52SJules Maselbas usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; 1075059d8d52SJules Maselbas dwc2_writel(hsotg, usbcfg, GUSBCFG); 1076059d8d52SJules Maselbas 1077059d8d52SJules Maselbas /* Program GI2CCTL.I2CEn */ 1078059d8d52SJules Maselbas i2cctl = dwc2_readl(hsotg, GI2CCTL); 1079059d8d52SJules Maselbas i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; 1080059d8d52SJules Maselbas i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; 1081059d8d52SJules Maselbas i2cctl &= ~GI2CCTL_I2CEN; 1082059d8d52SJules Maselbas dwc2_writel(hsotg, i2cctl, GI2CCTL); 1083059d8d52SJules Maselbas i2cctl |= GI2CCTL_I2CEN; 1084059d8d52SJules Maselbas dwc2_writel(hsotg, i2cctl, GI2CCTL); 1085059d8d52SJules Maselbas } 1086059d8d52SJules Maselbas 1087059d8d52SJules Maselbas return retval; 1088059d8d52SJules Maselbas } 1089059d8d52SJules Maselbas 1090059d8d52SJules Maselbas static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 1091059d8d52SJules Maselbas { 1092059d8d52SJules Maselbas u32 usbcfg, usbcfg_old; 1093059d8d52SJules Maselbas int retval = 0; 1094059d8d52SJules Maselbas 1095059d8d52SJules Maselbas if (!select_phy) 1096059d8d52SJules Maselbas return 0; 1097059d8d52SJules Maselbas 1098059d8d52SJules Maselbas usbcfg = dwc2_readl(hsotg, GUSBCFG); 1099059d8d52SJules Maselbas usbcfg_old = usbcfg; 1100059d8d52SJules Maselbas 1101059d8d52SJules Maselbas /* 1102059d8d52SJules Maselbas * HS PHY parameters. These parameters are preserved during soft reset 1103059d8d52SJules Maselbas * so only program the first time. Do a soft reset immediately after 1104059d8d52SJules Maselbas * setting phyif. 1105059d8d52SJules Maselbas */ 1106059d8d52SJules Maselbas switch (hsotg->params.phy_type) { 1107059d8d52SJules Maselbas case DWC2_PHY_TYPE_PARAM_ULPI: 1108059d8d52SJules Maselbas /* ULPI interface */ 1109059d8d52SJules Maselbas dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); 1110059d8d52SJules Maselbas usbcfg |= GUSBCFG_ULPI_UTMI_SEL; 1111059d8d52SJules Maselbas usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); 1112059d8d52SJules Maselbas if (hsotg->params.phy_ulpi_ddr) 1113059d8d52SJules Maselbas usbcfg |= GUSBCFG_DDRSEL; 1114059d8d52SJules Maselbas 1115059d8d52SJules Maselbas /* Set external VBUS indicator as needed. */ 1116059d8d52SJules Maselbas if (hsotg->params.oc_disable) 1117059d8d52SJules Maselbas usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | 1118059d8d52SJules Maselbas GUSBCFG_INDICATORPASSTHROUGH); 1119059d8d52SJules Maselbas break; 1120059d8d52SJules Maselbas case DWC2_PHY_TYPE_PARAM_UTMI: 1121059d8d52SJules Maselbas /* UTMI+ interface */ 1122059d8d52SJules Maselbas dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); 1123059d8d52SJules Maselbas usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); 1124059d8d52SJules Maselbas if (hsotg->params.phy_utmi_width == 16) 1125059d8d52SJules Maselbas usbcfg |= GUSBCFG_PHYIF16; 1126059d8d52SJules Maselbas break; 1127059d8d52SJules Maselbas default: 1128059d8d52SJules Maselbas dev_err(hsotg->dev, "FS PHY selected at HS!\n"); 1129059d8d52SJules Maselbas break; 1130059d8d52SJules Maselbas } 1131059d8d52SJules Maselbas 1132059d8d52SJules Maselbas if (usbcfg != usbcfg_old) { 1133059d8d52SJules Maselbas dwc2_writel(hsotg, usbcfg, GUSBCFG); 1134059d8d52SJules Maselbas 1135059d8d52SJules Maselbas /* Reset after setting the PHY parameters */ 1136059d8d52SJules Maselbas retval = dwc2_core_reset(hsotg, false); 1137059d8d52SJules Maselbas if (retval) { 1138059d8d52SJules Maselbas dev_err(hsotg->dev, 1139059d8d52SJules Maselbas "%s: Reset failed, aborting", __func__); 1140059d8d52SJules Maselbas return retval; 1141059d8d52SJules Maselbas } 1142059d8d52SJules Maselbas } 1143059d8d52SJules Maselbas 1144059d8d52SJules Maselbas return retval; 1145059d8d52SJules Maselbas } 1146059d8d52SJules Maselbas 1147aafe9351SClément Lassieur static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg) 1148aafe9351SClément Lassieur { 1149aafe9351SClément Lassieur u32 usbcfg; 1150aafe9351SClément Lassieur 1151aafe9351SClément Lassieur if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI) 1152aafe9351SClément Lassieur return; 1153aafe9351SClément Lassieur 1154aafe9351SClément Lassieur usbcfg = dwc2_readl(hsotg, GUSBCFG); 1155aafe9351SClément Lassieur 1156aafe9351SClément Lassieur usbcfg &= ~GUSBCFG_USBTRDTIM_MASK; 1157aafe9351SClément Lassieur if (hsotg->params.phy_utmi_width == 16) 1158aafe9351SClément Lassieur usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT; 1159aafe9351SClément Lassieur else 1160aafe9351SClément Lassieur usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT; 1161aafe9351SClément Lassieur 1162aafe9351SClément Lassieur dwc2_writel(hsotg, usbcfg, GUSBCFG); 1163aafe9351SClément Lassieur } 1164aafe9351SClément Lassieur 1165059d8d52SJules Maselbas int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 1166059d8d52SJules Maselbas { 1167059d8d52SJules Maselbas u32 usbcfg; 1168d712b725S周琰杰 (Zhou Yanjie) u32 otgctl; 1169059d8d52SJules Maselbas int retval = 0; 1170059d8d52SJules Maselbas 1171059d8d52SJules Maselbas if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || 1172059d8d52SJules Maselbas hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && 1173059d8d52SJules Maselbas hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 1174059d8d52SJules Maselbas /* If FS/LS mode with FS/LS PHY */ 1175059d8d52SJules Maselbas retval = dwc2_fs_phy_init(hsotg, select_phy); 1176059d8d52SJules Maselbas if (retval) 1177059d8d52SJules Maselbas return retval; 1178059d8d52SJules Maselbas } else { 1179059d8d52SJules Maselbas /* High speed PHY */ 1180059d8d52SJules Maselbas retval = dwc2_hs_phy_init(hsotg, select_phy); 1181059d8d52SJules Maselbas if (retval) 1182059d8d52SJules Maselbas return retval; 1183aafe9351SClément Lassieur 1184aafe9351SClément Lassieur if (dwc2_is_device_mode(hsotg)) 1185aafe9351SClément Lassieur dwc2_set_turnaround_time(hsotg); 1186059d8d52SJules Maselbas } 1187059d8d52SJules Maselbas 1188059d8d52SJules Maselbas if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 1189059d8d52SJules Maselbas hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 1190059d8d52SJules Maselbas hsotg->params.ulpi_fs_ls) { 1191059d8d52SJules Maselbas dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); 1192059d8d52SJules Maselbas usbcfg = dwc2_readl(hsotg, GUSBCFG); 1193059d8d52SJules Maselbas usbcfg |= GUSBCFG_ULPI_FS_LS; 1194059d8d52SJules Maselbas usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; 1195059d8d52SJules Maselbas dwc2_writel(hsotg, usbcfg, GUSBCFG); 1196059d8d52SJules Maselbas } else { 1197059d8d52SJules Maselbas usbcfg = dwc2_readl(hsotg, GUSBCFG); 1198059d8d52SJules Maselbas usbcfg &= ~GUSBCFG_ULPI_FS_LS; 1199059d8d52SJules Maselbas usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; 1200059d8d52SJules Maselbas dwc2_writel(hsotg, usbcfg, GUSBCFG); 1201059d8d52SJules Maselbas } 1202059d8d52SJules Maselbas 1203d712b725S周琰杰 (Zhou Yanjie) if (!hsotg->params.activate_ingenic_overcurrent_detection) { 1204d712b725S周琰杰 (Zhou Yanjie) if (dwc2_is_host_mode(hsotg)) { 1205d712b725S周琰杰 (Zhou Yanjie) otgctl = readl(hsotg->regs + GOTGCTL); 1206d712b725S周琰杰 (Zhou Yanjie) otgctl |= GOTGCTL_VBVALOEN | GOTGCTL_VBVALOVAL; 1207d712b725S周琰杰 (Zhou Yanjie) writel(otgctl, hsotg->regs + GOTGCTL); 1208d712b725S周琰杰 (Zhou Yanjie) } 1209d712b725S周琰杰 (Zhou Yanjie) } 1210d712b725S周琰杰 (Zhou Yanjie) 1211059d8d52SJules Maselbas return retval; 1212059d8d52SJules Maselbas } 1213059d8d52SJules Maselbas 1214197ba5f4SPaul Zimmerman MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); 1215197ba5f4SPaul Zimmerman MODULE_AUTHOR("Synopsys, Inc."); 1216197ba5f4SPaul Zimmerman MODULE_LICENSE("Dual BSD/GPL"); 1217