162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * core.c - DesignWare HS OTG Controller common routines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * The Core code provides basic services for accessing and managing the 1062306a36Sopenharmony_ci * DWC_otg hardware. These services are used by both the Host Controller 1162306a36Sopenharmony_ci * Driver and the Peripheral Controller Driver. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/moduleparam.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/usb.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/usb/hcd.h> 2562306a36Sopenharmony_ci#include <linux/usb/ch11.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "core.h" 2862306a36Sopenharmony_ci#include "hcd.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * dwc2_backup_global_registers() - Backup global controller registers. 3262306a36Sopenharmony_ci * When suspending usb bus, registers needs to be backuped 3362306a36Sopenharmony_ci * if controller power is disabled once suspended. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ciint dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct dwc2_gregs_backup *gr; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Backup global regs */ 4462306a36Sopenharmony_ci gr = &hsotg->gr_backup; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci gr->gotgctl = dwc2_readl(hsotg, GOTGCTL); 4762306a36Sopenharmony_ci gr->gintmsk = dwc2_readl(hsotg, GINTMSK); 4862306a36Sopenharmony_ci gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG); 4962306a36Sopenharmony_ci gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG); 5062306a36Sopenharmony_ci gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ); 5162306a36Sopenharmony_ci gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ); 5262306a36Sopenharmony_ci gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG); 5362306a36Sopenharmony_ci gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 5462306a36Sopenharmony_ci gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); 5562306a36Sopenharmony_ci gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); 5662306a36Sopenharmony_ci gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci gr->valid = true; 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/** 6362306a36Sopenharmony_ci * dwc2_restore_global_registers() - Restore controller global registers. 6462306a36Sopenharmony_ci * When resuming usb bus, device registers needs to be restored 6562306a36Sopenharmony_ci * if controller power were disabled. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ciint dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct dwc2_gregs_backup *gr; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Restore global regs */ 7662306a36Sopenharmony_ci gr = &hsotg->gr_backup; 7762306a36Sopenharmony_ci if (!gr->valid) { 7862306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: no global registers to restore\n", 7962306a36Sopenharmony_ci __func__); 8062306a36Sopenharmony_ci return -EINVAL; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci gr->valid = false; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 8562306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gotgctl, GOTGCTL); 8662306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gintmsk, GINTMSK); 8762306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 8862306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG); 8962306a36Sopenharmony_ci dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); 9062306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); 9162306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); 9262306a36Sopenharmony_ci dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); 9362306a36Sopenharmony_ci dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); 9462306a36Sopenharmony_ci dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); 9562306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/** 10162306a36Sopenharmony_ci * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 10462306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Reset. 10562306a36Sopenharmony_ci * @restore: Controller registers need to be restored 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ciint dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, 10862306a36Sopenharmony_ci bool restore) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct dwc2_gregs_backup *gr; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci gr = &hsotg->gr_backup; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * Restore host or device regisers with the same mode core enterted 11662306a36Sopenharmony_ci * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup 11762306a36Sopenharmony_ci * value of the "gotgctl" register. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci if (gr->gotgctl & GOTGCTL_CURMODE_HOST) 12062306a36Sopenharmony_ci return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup, 12162306a36Sopenharmony_ci restore); 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci return dwc2_gadget_exit_partial_power_down(hsotg, restore); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/** 12762306a36Sopenharmony_ci * dwc2_enter_partial_power_down() - Put controller in Partial Power Down. 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ciint dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) 13462306a36Sopenharmony_ci return dwc2_host_enter_partial_power_down(hsotg); 13562306a36Sopenharmony_ci else 13662306a36Sopenharmony_ci return dwc2_gadget_enter_partial_power_down(hsotg); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * dwc2_restore_essential_regs() - Restore essiential regs of core. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 14362306a36Sopenharmony_ci * @rmode: Restore mode, enabled in case of remote-wakeup. 14462306a36Sopenharmony_ci * @is_host: Host or device mode. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, 14762306a36Sopenharmony_ci int is_host) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci u32 pcgcctl; 15062306a36Sopenharmony_ci struct dwc2_gregs_backup *gr; 15162306a36Sopenharmony_ci struct dwc2_dregs_backup *dr; 15262306a36Sopenharmony_ci struct dwc2_hregs_backup *hr; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci gr = &hsotg->gr_backup; 15562306a36Sopenharmony_ci dr = &hsotg->dr_backup; 15662306a36Sopenharmony_ci hr = &hsotg->hr_backup; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Load restore values for [31:14] bits */ 16162306a36Sopenharmony_ci pcgcctl = (gr->pcgcctl & 0xffffc000); 16262306a36Sopenharmony_ci /* If High Speed */ 16362306a36Sopenharmony_ci if (is_host) { 16462306a36Sopenharmony_ci if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK)) 16562306a36Sopenharmony_ci pcgcctl |= BIT(17); 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK)) 16862306a36Sopenharmony_ci pcgcctl |= BIT(17); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Umnask global Interrupt in GAHBCFG and restore it */ 17362306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Clear all pending interupts */ 17662306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Unmask restore done interrupt */ 17962306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Restore GUSBCFG and HCFG/DCFG */ 18262306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (is_host) { 18562306a36Sopenharmony_ci dwc2_writel(hsotg, hr->hcfg, HCFG); 18662306a36Sopenharmony_ci if (rmode) 18762306a36Sopenharmony_ci pcgcctl |= PCGCTL_RESTOREMODE; 18862306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 18962306a36Sopenharmony_ci udelay(10); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci pcgcctl |= PCGCTL_ESS_REG_RESTORED; 19262306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 19362306a36Sopenharmony_ci udelay(10); 19462306a36Sopenharmony_ci } else { 19562306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dcfg, DCFG); 19662306a36Sopenharmony_ci if (!rmode) 19762306a36Sopenharmony_ci pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; 19862306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 19962306a36Sopenharmony_ci udelay(10); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci pcgcctl |= PCGCTL_ESS_REG_RESTORED; 20262306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 20362306a36Sopenharmony_ci udelay(10); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/** 20862306a36Sopenharmony_ci * dwc2_hib_restore_common() - Common part of restore routine. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 21162306a36Sopenharmony_ci * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 21262306a36Sopenharmony_ci * @is_host: Host or device mode. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_civoid dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, 21562306a36Sopenharmony_ci int is_host) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci u32 gpwrdn; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Switch-on voltage to the core */ 22062306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 22162306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNSWTCH; 22262306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 22362306a36Sopenharmony_ci udelay(10); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Reset core */ 22662306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 22762306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNRSTN; 22862306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 22962306a36Sopenharmony_ci udelay(10); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* Enable restore from PMU */ 23262306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 23362306a36Sopenharmony_ci gpwrdn |= GPWRDN_RESTORE; 23462306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 23562306a36Sopenharmony_ci udelay(10); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Disable Power Down Clamp */ 23862306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 23962306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_PWRDNCLMP; 24062306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 24162306a36Sopenharmony_ci udelay(50); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!is_host && rem_wakeup) 24462306a36Sopenharmony_ci udelay(70); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Deassert reset core */ 24762306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 24862306a36Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNRSTN; 24962306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 25062306a36Sopenharmony_ci udelay(10); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* Disable PMU interrupt */ 25362306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 25462306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_PMUINTSEL; 25562306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 25662306a36Sopenharmony_ci udelay(10); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Set Restore Essential Regs bit in PCGCCTL register */ 25962306a36Sopenharmony_ci dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * Wait For Restore_done Interrupt. This mechanism of polling the 26362306a36Sopenharmony_ci * interrupt is introduced to avoid any possible race conditions 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE, 26662306a36Sopenharmony_ci 20000)) { 26762306a36Sopenharmony_ci dev_dbg(hsotg->dev, 26862306a36Sopenharmony_ci "%s: Restore Done wasn't generated here\n", 26962306a36Sopenharmony_ci __func__); 27062306a36Sopenharmony_ci } else { 27162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "restore done generated here\n"); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * To avoid restore done interrupt storm after restore is 27562306a36Sopenharmony_ci * generated clear GINTSTS_RESTOREDONE bit. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/** 28262306a36Sopenharmony_ci * dwc2_wait_for_mode() - Waits for the controller mode. 28362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller. 28462306a36Sopenharmony_ci * @host_mode: If true, waits for host mode, otherwise device mode. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, 28762306a36Sopenharmony_ci bool host_mode) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci ktime_t start; 29062306a36Sopenharmony_ci ktime_t end; 29162306a36Sopenharmony_ci unsigned int timeout = 110; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci dev_vdbg(hsotg->dev, "Waiting for %s mode\n", 29462306a36Sopenharmony_ci host_mode ? "host" : "device"); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci start = ktime_get(); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci while (1) { 29962306a36Sopenharmony_ci s64 ms; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (dwc2_is_host_mode(hsotg) == host_mode) { 30262306a36Sopenharmony_ci dev_vdbg(hsotg->dev, "%s mode set\n", 30362306a36Sopenharmony_ci host_mode ? "Host" : "Device"); 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci end = ktime_get(); 30862306a36Sopenharmony_ci ms = ktime_to_ms(ktime_sub(end, start)); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (ms >= (s64)timeout) { 31162306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n", 31262306a36Sopenharmony_ci __func__, host_mode ? "host" : "device"); 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci usleep_range(1000, 2000); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/** 32162306a36Sopenharmony_ci * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce 32262306a36Sopenharmony_ci * filter is enabled. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cistatic bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci u32 gsnpsid; 32962306a36Sopenharmony_ci u32 ghwcfg4; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 33262306a36Sopenharmony_ci return false; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Check if core configuration includes the IDDIG filter. */ 33562306a36Sopenharmony_ci ghwcfg4 = dwc2_readl(hsotg, GHWCFG4); 33662306a36Sopenharmony_ci if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN)) 33762306a36Sopenharmony_ci return false; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * Check if the IDDIG debounce filter is bypassed. Available 34162306a36Sopenharmony_ci * in core version >= 3.10a. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci gsnpsid = dwc2_readl(hsotg, GSNPSID); 34462306a36Sopenharmony_ci if (gsnpsid >= DWC2_CORE_REV_3_10a) { 34562306a36Sopenharmony_ci u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS) 34862306a36Sopenharmony_ci return false; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return true; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* 35562306a36Sopenharmony_ci * dwc2_enter_hibernation() - Common function to enter hibernation. 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 35862306a36Sopenharmony_ci * @is_host: True if core is in host mode. 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_ciint dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci if (is_host) 36562306a36Sopenharmony_ci return dwc2_host_enter_hibernation(hsotg); 36662306a36Sopenharmony_ci else 36762306a36Sopenharmony_ci return dwc2_gadget_enter_hibernation(hsotg); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * dwc2_exit_hibernation() - Common function to exit from hibernation. 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 37462306a36Sopenharmony_ci * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup. 37562306a36Sopenharmony_ci * @reset: Enabled in case of restore with reset. 37662306a36Sopenharmony_ci * @is_host: True if core is in host mode. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ciint dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, 38162306a36Sopenharmony_ci int reset, int is_host) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci if (is_host) 38462306a36Sopenharmony_ci return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset); 38562306a36Sopenharmony_ci else 38662306a36Sopenharmony_ci return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* 39062306a36Sopenharmony_ci * Do core a soft reset of the core. Be careful with this because it 39162306a36Sopenharmony_ci * resets all the internal state machines of the core. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ciint dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci u32 greset; 39662306a36Sopenharmony_ci bool wait_for_host_mode = false; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * If the current mode is host, either due to the force mode 40262306a36Sopenharmony_ci * bit being set (which persists after core reset) or the 40362306a36Sopenharmony_ci * connector id pin, a core soft reset will temporarily reset 40462306a36Sopenharmony_ci * the mode to device. A delay from the IDDIG debounce filter 40562306a36Sopenharmony_ci * will occur before going back to host mode. 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * Determine whether we will go back into host mode after a 40862306a36Sopenharmony_ci * reset and account for this delay after the reset. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci if (dwc2_iddig_filter_enabled(hsotg)) { 41162306a36Sopenharmony_ci u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 41262306a36Sopenharmony_ci u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!(gotgctl & GOTGCTL_CONID_B) || 41562306a36Sopenharmony_ci (gusbcfg & GUSBCFG_FORCEHOSTMODE)) { 41662306a36Sopenharmony_ci wait_for_host_mode = true; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Core Soft Reset */ 42162306a36Sopenharmony_ci greset = dwc2_readl(hsotg, GRSTCTL); 42262306a36Sopenharmony_ci greset |= GRSTCTL_CSFTRST; 42362306a36Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) < 42662306a36Sopenharmony_ci (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) { 42762306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, 42862306a36Sopenharmony_ci GRSTCTL_CSFTRST, 10000)) { 42962306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n", 43062306a36Sopenharmony_ci __func__); 43162306a36Sopenharmony_ci return -EBUSY; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, 43562306a36Sopenharmony_ci GRSTCTL_CSFTRST_DONE, 10000)) { 43662306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n", 43762306a36Sopenharmony_ci __func__); 43862306a36Sopenharmony_ci return -EBUSY; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci greset = dwc2_readl(hsotg, GRSTCTL); 44162306a36Sopenharmony_ci greset &= ~GRSTCTL_CSFTRST; 44262306a36Sopenharmony_ci greset |= GRSTCTL_CSFTRST_DONE; 44362306a36Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * Switching from device mode to host mode by disconnecting 44862306a36Sopenharmony_ci * device cable core enters and exits form hibernation. 44962306a36Sopenharmony_ci * However, the fifo map remains not cleared. It results 45062306a36Sopenharmony_ci * to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ 45162306a36Sopenharmony_ci * gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) 45262306a36Sopenharmony_ci * if in host mode we disconnect the micro a to b host 45362306a36Sopenharmony_ci * cable. Because core reset occurs. 45462306a36Sopenharmony_ci * To avoid the WARNING, fifo_map should be cleared 45562306a36Sopenharmony_ci * in dwc2_core_reset() function by taking into account configs. 45662306a36Sopenharmony_ci * fifo_map must be cleared only if driver is configured in 45762306a36Sopenharmony_ci * "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" 45862306a36Sopenharmony_ci * mode. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci dwc2_clear_fifo_map(hsotg); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Wait for AHB master IDLE state */ 46362306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) { 46462306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", 46562306a36Sopenharmony_ci __func__); 46662306a36Sopenharmony_ci return -EBUSY; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (wait_for_host_mode && !skip_wait) 47062306a36Sopenharmony_ci dwc2_wait_for_mode(hsotg, true); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/** 47662306a36Sopenharmony_ci * dwc2_force_mode() - Force the mode of the controller. 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * Forcing the mode is needed for two cases: 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * 1) If the dr_mode is set to either HOST or PERIPHERAL we force the 48162306a36Sopenharmony_ci * controller to stay in a particular mode regardless of ID pin 48262306a36Sopenharmony_ci * changes. We do this once during probe. 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * 2) During probe we want to read reset values of the hw 48562306a36Sopenharmony_ci * configuration registers that are only available in either host or 48662306a36Sopenharmony_ci * device mode. We may need to force the mode if the current mode does 48762306a36Sopenharmony_ci * not allow us to access the register in the mode that we want. 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * In either case it only makes sense to force the mode if the 49062306a36Sopenharmony_ci * controller hardware is OTG capable. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * Checks are done in this function to determine whether doing a force 49362306a36Sopenharmony_ci * would be valid or not. 49462306a36Sopenharmony_ci * 49562306a36Sopenharmony_ci * If a force is done, it requires a IDDIG debounce filter delay if 49662306a36Sopenharmony_ci * the filter is configured and enabled. We poll the current mode of 49762306a36Sopenharmony_ci * the controller to account for this delay. 49862306a36Sopenharmony_ci * 49962306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 50062306a36Sopenharmony_ci * @host: Host mode flag 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_civoid dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci u32 gusbcfg; 50562306a36Sopenharmony_ci u32 set; 50662306a36Sopenharmony_ci u32 clear; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Forcing mode to %s\n", host ? "host" : "device"); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * Force mode has no effect if the hardware is not OTG. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * If dr_mode is either peripheral or host only, there is no 51862306a36Sopenharmony_ci * need to ever force the mode to the opposite mode. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ci if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) 52162306a36Sopenharmony_ci return; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST)) 52462306a36Sopenharmony_ci return; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci gusbcfg = dwc2_readl(hsotg, GUSBCFG); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; 52962306a36Sopenharmony_ci clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci gusbcfg &= ~clear; 53262306a36Sopenharmony_ci gusbcfg |= set; 53362306a36Sopenharmony_ci dwc2_writel(hsotg, gusbcfg, GUSBCFG); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci dwc2_wait_for_mode(hsotg, host); 53662306a36Sopenharmony_ci return; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/** 54062306a36Sopenharmony_ci * dwc2_clear_force_mode() - Clears the force mode bits. 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * After clearing the bits, wait up to 100 ms to account for any 54362306a36Sopenharmony_ci * potential IDDIG filter delay. We can't know if we expect this delay 54462306a36Sopenharmony_ci * or not because the value of the connector ID status is affected by 54562306a36Sopenharmony_ci * the force mode. We only need to call this once during probe if 54662306a36Sopenharmony_ci * dr_mode == OTG. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci u32 gusbcfg; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Clearing force mode bits\n"); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci gusbcfg = dwc2_readl(hsotg, GUSBCFG); 56062306a36Sopenharmony_ci gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; 56162306a36Sopenharmony_ci gusbcfg &= ~GUSBCFG_FORCEDEVMODE; 56262306a36Sopenharmony_ci dwc2_writel(hsotg, gusbcfg, GUSBCFG); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (dwc2_iddig_filter_enabled(hsotg)) 56562306a36Sopenharmony_ci msleep(100); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* 56962306a36Sopenharmony_ci * Sets or clears force mode based on the dr_mode parameter. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_civoid dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci switch (hsotg->dr_mode) { 57462306a36Sopenharmony_ci case USB_DR_MODE_HOST: 57562306a36Sopenharmony_ci /* 57662306a36Sopenharmony_ci * NOTE: This is required for some rockchip soc based 57762306a36Sopenharmony_ci * platforms on their host-only dwc2. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci if (!dwc2_hw_is_otg(hsotg)) 58062306a36Sopenharmony_ci msleep(50); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 58462306a36Sopenharmony_ci dwc2_force_mode(hsotg, false); 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case USB_DR_MODE_OTG: 58762306a36Sopenharmony_ci dwc2_clear_force_mode(hsotg); 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci default: 59062306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s() Invalid dr_mode=%d\n", 59162306a36Sopenharmony_ci __func__, hsotg->dr_mode); 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/* 59762306a36Sopenharmony_ci * dwc2_enable_acg - enable active clock gating feature 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_civoid dwc2_enable_acg(struct dwc2_hsotg *hsotg) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci if (hsotg->params.acg_enable) { 60262306a36Sopenharmony_ci u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n"); 60562306a36Sopenharmony_ci pcgcctl1 |= PCGCCTL1_GATEEN; 60662306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl1, PCGCCTL1); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci/** 61162306a36Sopenharmony_ci * dwc2_dump_host_registers() - Prints the host registers 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 61462306a36Sopenharmony_ci * 61562306a36Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code 61662306a36Sopenharmony_ci * is integrated and the driver is stable 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_civoid dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci#ifdef DEBUG 62162306a36Sopenharmony_ci u32 __iomem *addr; 62262306a36Sopenharmony_ci int i; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Host Global Registers\n"); 62562306a36Sopenharmony_ci addr = hsotg->regs + HCFG; 62662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", 62762306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCFG)); 62862306a36Sopenharmony_ci addr = hsotg->regs + HFIR; 62962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n", 63062306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFIR)); 63162306a36Sopenharmony_ci addr = hsotg->regs + HFNUM; 63262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n", 63362306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFNUM)); 63462306a36Sopenharmony_ci addr = hsotg->regs + HPTXSTS; 63562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n", 63662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPTXSTS)); 63762306a36Sopenharmony_ci addr = hsotg->regs + HAINT; 63862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n", 63962306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HAINT)); 64062306a36Sopenharmony_ci addr = hsotg->regs + HAINTMSK; 64162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", 64262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HAINTMSK)); 64362306a36Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 64462306a36Sopenharmony_ci addr = hsotg->regs + HFLBADDR; 64562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", 64662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HFLBADDR)); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci addr = hsotg->regs + HPRT0; 65062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n", 65162306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPRT0)); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci for (i = 0; i < hsotg->params.host_channels; i++) { 65462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); 65562306a36Sopenharmony_ci addr = hsotg->regs + HCCHAR(i); 65662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n", 65762306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i))); 65862306a36Sopenharmony_ci addr = hsotg->regs + HCSPLT(i); 65962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n", 66062306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i))); 66162306a36Sopenharmony_ci addr = hsotg->regs + HCINT(i); 66262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n", 66362306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCINT(i))); 66462306a36Sopenharmony_ci addr = hsotg->regs + HCINTMSK(i); 66562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n", 66662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i))); 66762306a36Sopenharmony_ci addr = hsotg->regs + HCTSIZ(i); 66862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n", 66962306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i))); 67062306a36Sopenharmony_ci addr = hsotg->regs + HCDMA(i); 67162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", 67262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HCDMA(i))); 67362306a36Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 67462306a36Sopenharmony_ci addr = hsotg->regs + HCDMAB(i); 67562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", 67662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, 67762306a36Sopenharmony_ci HCDMAB(i))); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci#endif 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci/** 68462306a36Sopenharmony_ci * dwc2_dump_global_registers() - Prints the core global registers 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * NOTE: This function will be removed once the peripheral controller code 68962306a36Sopenharmony_ci * is integrated and the driver is stable 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_civoid dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci#ifdef DEBUG 69462306a36Sopenharmony_ci u32 __iomem *addr; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Core Global Registers\n"); 69762306a36Sopenharmony_ci addr = hsotg->regs + GOTGCTL; 69862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n", 69962306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GOTGCTL)); 70062306a36Sopenharmony_ci addr = hsotg->regs + GOTGINT; 70162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n", 70262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GOTGINT)); 70362306a36Sopenharmony_ci addr = hsotg->regs + GAHBCFG; 70462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n", 70562306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GAHBCFG)); 70662306a36Sopenharmony_ci addr = hsotg->regs + GUSBCFG; 70762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n", 70862306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GUSBCFG)); 70962306a36Sopenharmony_ci addr = hsotg->regs + GRSTCTL; 71062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n", 71162306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRSTCTL)); 71262306a36Sopenharmony_ci addr = hsotg->regs + GINTSTS; 71362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n", 71462306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GINTSTS)); 71562306a36Sopenharmony_ci addr = hsotg->regs + GINTMSK; 71662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n", 71762306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GINTMSK)); 71862306a36Sopenharmony_ci addr = hsotg->regs + GRXSTSR; 71962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n", 72062306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRXSTSR)); 72162306a36Sopenharmony_ci addr = hsotg->regs + GRXFSIZ; 72262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n", 72362306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ)); 72462306a36Sopenharmony_ci addr = hsotg->regs + GNPTXFSIZ; 72562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n", 72662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ)); 72762306a36Sopenharmony_ci addr = hsotg->regs + GNPTXSTS; 72862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n", 72962306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS)); 73062306a36Sopenharmony_ci addr = hsotg->regs + GI2CCTL; 73162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n", 73262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GI2CCTL)); 73362306a36Sopenharmony_ci addr = hsotg->regs + GPVNDCTL; 73462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", 73562306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL)); 73662306a36Sopenharmony_ci addr = hsotg->regs + GGPIO; 73762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", 73862306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GGPIO)); 73962306a36Sopenharmony_ci addr = hsotg->regs + GUID; 74062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", 74162306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GUID)); 74262306a36Sopenharmony_ci addr = hsotg->regs + GSNPSID; 74362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n", 74462306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GSNPSID)); 74562306a36Sopenharmony_ci addr = hsotg->regs + GHWCFG1; 74662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n", 74762306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG1)); 74862306a36Sopenharmony_ci addr = hsotg->regs + GHWCFG2; 74962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n", 75062306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG2)); 75162306a36Sopenharmony_ci addr = hsotg->regs + GHWCFG3; 75262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n", 75362306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG3)); 75462306a36Sopenharmony_ci addr = hsotg->regs + GHWCFG4; 75562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n", 75662306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GHWCFG4)); 75762306a36Sopenharmony_ci addr = hsotg->regs + GLPMCFG; 75862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n", 75962306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GLPMCFG)); 76062306a36Sopenharmony_ci addr = hsotg->regs + GPWRDN; 76162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n", 76262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GPWRDN)); 76362306a36Sopenharmony_ci addr = hsotg->regs + GDFIFOCFG; 76462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n", 76562306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG)); 76662306a36Sopenharmony_ci addr = hsotg->regs + HPTXFSIZ; 76762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", 76862306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ)); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci addr = hsotg->regs + PCGCTL; 77162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", 77262306a36Sopenharmony_ci (unsigned long)addr, dwc2_readl(hsotg, PCGCTL)); 77362306a36Sopenharmony_ci#endif 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/** 77762306a36Sopenharmony_ci * dwc2_flush_tx_fifo() - Flushes a Tx FIFO 77862306a36Sopenharmony_ci * 77962306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 78062306a36Sopenharmony_ci * @num: Tx FIFO to flush 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_civoid dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci u32 greset; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* Wait for AHB master IDLE state */ 78962306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 79062306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 79162306a36Sopenharmony_ci __func__); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci greset = GRSTCTL_TXFFLSH; 79462306a36Sopenharmony_ci greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; 79562306a36Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000)) 79862306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n", 79962306a36Sopenharmony_ci __func__); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* Wait for at least 3 PHY Clocks */ 80262306a36Sopenharmony_ci udelay(1); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci/** 80662306a36Sopenharmony_ci * dwc2_flush_rx_fifo() - Flushes the Rx FIFO 80762306a36Sopenharmony_ci * 80862306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_civoid dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci u32 greset; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* Wait for AHB master IDLE state */ 81762306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) 81862306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n", 81962306a36Sopenharmony_ci __func__); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci greset = GRSTCTL_RXFFLSH; 82262306a36Sopenharmony_ci dwc2_writel(hsotg, greset, GRSTCTL); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Wait for RxFIFO flush done */ 82562306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000)) 82662306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n", 82762306a36Sopenharmony_ci __func__); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Wait for at least 3 PHY Clocks */ 83062306a36Sopenharmony_ci udelay(1); 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cibool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff) 83662306a36Sopenharmony_ci return false; 83762306a36Sopenharmony_ci else 83862306a36Sopenharmony_ci return true; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/** 84262306a36Sopenharmony_ci * dwc2_enable_global_interrupts() - Enables the controller's Global 84362306a36Sopenharmony_ci * Interrupt in the AHB Config register 84462306a36Sopenharmony_ci * 84562306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_civoid dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci ahbcfg |= GAHBCFG_GLBL_INTR_EN; 85262306a36Sopenharmony_ci dwc2_writel(hsotg, ahbcfg, GAHBCFG); 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci/** 85662306a36Sopenharmony_ci * dwc2_disable_global_interrupts() - Disables the controller's Global 85762306a36Sopenharmony_ci * Interrupt in the AHB Config register 85862306a36Sopenharmony_ci * 85962306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_civoid dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; 86662306a36Sopenharmony_ci dwc2_writel(hsotg, ahbcfg, GAHBCFG); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci/* Returns the controller's GHWCFG2.OTG_MODE. */ 87062306a36Sopenharmony_ciunsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >> 87562306a36Sopenharmony_ci GHWCFG2_OP_MODE_SHIFT; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* Returns true if the controller is capable of DRD. */ 87962306a36Sopenharmony_cibool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || 88462306a36Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || 88562306a36Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/* Returns true if the controller is host-only. */ 88962306a36Sopenharmony_cibool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || 89462306a36Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci/* Returns true if the controller is device-only. */ 89862306a36Sopenharmony_cibool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci unsigned int op_mode = dwc2_op_mode(hsotg); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || 90362306a36Sopenharmony_ci (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci/** 90762306a36Sopenharmony_ci * dwc2_hsotg_wait_bit_set - Waits for bit to be set. 90862306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller. 90962306a36Sopenharmony_ci * @offset: Register's offset where bit/bits must be set. 91062306a36Sopenharmony_ci * @mask: Mask of the bit/bits which must be set. 91162306a36Sopenharmony_ci * @timeout: Timeout to wait. 91262306a36Sopenharmony_ci * 91362306a36Sopenharmony_ci * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_ciint dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 91662306a36Sopenharmony_ci u32 timeout) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci u32 i; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 92162306a36Sopenharmony_ci if (dwc2_readl(hsotg, offset) & mask) 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci udelay(1); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return -ETIMEDOUT; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci/** 93062306a36Sopenharmony_ci * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear. 93162306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller. 93262306a36Sopenharmony_ci * @offset: Register's offset where bit/bits must be set. 93362306a36Sopenharmony_ci * @mask: Mask of the bit/bits which must be set. 93462306a36Sopenharmony_ci * @timeout: Timeout to wait. 93562306a36Sopenharmony_ci * 93662306a36Sopenharmony_ci * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout. 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ciint dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, 93962306a36Sopenharmony_ci u32 timeout) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci u32 i; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 94462306a36Sopenharmony_ci if (!(dwc2_readl(hsotg, offset) & mask)) 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci udelay(1); 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci return -ETIMEDOUT; 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci/* 95362306a36Sopenharmony_ci * Initializes the FSLSPClkSel field of the HCFG register depending on the 95462306a36Sopenharmony_ci * PHY type 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_civoid dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci u32 hcfg, val; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 96162306a36Sopenharmony_ci hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 96262306a36Sopenharmony_ci hsotg->params.ulpi_fs_ls) || 96362306a36Sopenharmony_ci hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 96462306a36Sopenharmony_ci /* Full speed PHY */ 96562306a36Sopenharmony_ci val = HCFG_FSLSPCLKSEL_48_MHZ; 96662306a36Sopenharmony_ci } else { 96762306a36Sopenharmony_ci /* High speed PHY running at full speed or high speed */ 96862306a36Sopenharmony_ci val = HCFG_FSLSPCLKSEL_30_60_MHZ; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); 97262306a36Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 97362306a36Sopenharmony_ci hcfg &= ~HCFG_FSLSPCLKSEL_MASK; 97462306a36Sopenharmony_ci hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; 97562306a36Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci u32 usbcfg, ggpio, i2cctl; 98162306a36Sopenharmony_ci int retval = 0; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * core_init() is now called on every switch so only call the 98562306a36Sopenharmony_ci * following for the first time through 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci if (select_phy) { 98862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "FS PHY selected\n"); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 99162306a36Sopenharmony_ci if (!(usbcfg & GUSBCFG_PHYSEL)) { 99262306a36Sopenharmony_ci usbcfg |= GUSBCFG_PHYSEL; 99362306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Reset after a PHY select */ 99662306a36Sopenharmony_ci retval = dwc2_core_reset(hsotg, false); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (retval) { 99962306a36Sopenharmony_ci dev_err(hsotg->dev, 100062306a36Sopenharmony_ci "%s: Reset failed, aborting", __func__); 100162306a36Sopenharmony_ci return retval; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (hsotg->params.activate_stm_fs_transceiver) { 100662306a36Sopenharmony_ci ggpio = dwc2_readl(hsotg, GGPIO); 100762306a36Sopenharmony_ci if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { 100862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Activating transceiver\n"); 100962306a36Sopenharmony_ci /* 101062306a36Sopenharmony_ci * STM32F4x9 uses the GGPIO register as general 101162306a36Sopenharmony_ci * core configuration register. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; 101462306a36Sopenharmony_ci dwc2_writel(hsotg, ggpio, GGPIO); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* 102062306a36Sopenharmony_ci * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also 102162306a36Sopenharmony_ci * do this on HNP Dev/Host mode switches (done in dev_init and 102262306a36Sopenharmony_ci * host_init). 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) 102562306a36Sopenharmony_ci dwc2_init_fs_ls_pclk_sel(hsotg); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (hsotg->params.i2c_enable) { 102862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* Program GUSBCFG.OtgUtmiFsSel to I2C */ 103162306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 103262306a36Sopenharmony_ci usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; 103362306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* Program GI2CCTL.I2CEn */ 103662306a36Sopenharmony_ci i2cctl = dwc2_readl(hsotg, GI2CCTL); 103762306a36Sopenharmony_ci i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; 103862306a36Sopenharmony_ci i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; 103962306a36Sopenharmony_ci i2cctl &= ~GI2CCTL_I2CEN; 104062306a36Sopenharmony_ci dwc2_writel(hsotg, i2cctl, GI2CCTL); 104162306a36Sopenharmony_ci i2cctl |= GI2CCTL_I2CEN; 104262306a36Sopenharmony_ci dwc2_writel(hsotg, i2cctl, GI2CCTL); 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci return retval; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci u32 usbcfg, usbcfg_old; 105162306a36Sopenharmony_ci int retval = 0; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (!select_phy) 105462306a36Sopenharmony_ci return 0; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 105762306a36Sopenharmony_ci usbcfg_old = usbcfg; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* 106062306a36Sopenharmony_ci * HS PHY parameters. These parameters are preserved during soft reset 106162306a36Sopenharmony_ci * so only program the first time. Do a soft reset immediately after 106262306a36Sopenharmony_ci * setting phyif. 106362306a36Sopenharmony_ci */ 106462306a36Sopenharmony_ci switch (hsotg->params.phy_type) { 106562306a36Sopenharmony_ci case DWC2_PHY_TYPE_PARAM_ULPI: 106662306a36Sopenharmony_ci /* ULPI interface */ 106762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); 106862306a36Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_UTMI_SEL; 106962306a36Sopenharmony_ci usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); 107062306a36Sopenharmony_ci if (hsotg->params.phy_ulpi_ddr) 107162306a36Sopenharmony_ci usbcfg |= GUSBCFG_DDRSEL; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* Set external VBUS indicator as needed. */ 107462306a36Sopenharmony_ci if (hsotg->params.oc_disable) 107562306a36Sopenharmony_ci usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | 107662306a36Sopenharmony_ci GUSBCFG_INDICATORPASSTHROUGH); 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci case DWC2_PHY_TYPE_PARAM_UTMI: 107962306a36Sopenharmony_ci /* UTMI+ interface */ 108062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); 108162306a36Sopenharmony_ci usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); 108262306a36Sopenharmony_ci if (hsotg->params.phy_utmi_width == 16) 108362306a36Sopenharmony_ci usbcfg |= GUSBCFG_PHYIF16; 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci default: 108662306a36Sopenharmony_ci dev_err(hsotg->dev, "FS PHY selected at HS!\n"); 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (usbcfg != usbcfg_old) { 109162306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* Reset after setting the PHY parameters */ 109462306a36Sopenharmony_ci retval = dwc2_core_reset(hsotg, false); 109562306a36Sopenharmony_ci if (retval) { 109662306a36Sopenharmony_ci dev_err(hsotg->dev, 109762306a36Sopenharmony_ci "%s: Reset failed, aborting", __func__); 109862306a36Sopenharmony_ci return retval; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return retval; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci u32 usbcfg; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI) 111062306a36Sopenharmony_ci return; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci usbcfg &= ~GUSBCFG_USBTRDTIM_MASK; 111562306a36Sopenharmony_ci if (hsotg->params.phy_utmi_width == 16) 111662306a36Sopenharmony_ci usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT; 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ciint dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci u32 usbcfg; 112662306a36Sopenharmony_ci u32 otgctl; 112762306a36Sopenharmony_ci int retval = 0; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || 113062306a36Sopenharmony_ci hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && 113162306a36Sopenharmony_ci hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { 113262306a36Sopenharmony_ci /* If FS/LS mode with FS/LS PHY */ 113362306a36Sopenharmony_ci retval = dwc2_fs_phy_init(hsotg, select_phy); 113462306a36Sopenharmony_ci if (retval) 113562306a36Sopenharmony_ci return retval; 113662306a36Sopenharmony_ci } else { 113762306a36Sopenharmony_ci /* High speed PHY */ 113862306a36Sopenharmony_ci retval = dwc2_hs_phy_init(hsotg, select_phy); 113962306a36Sopenharmony_ci if (retval) 114062306a36Sopenharmony_ci return retval; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (dwc2_is_device_mode(hsotg)) 114362306a36Sopenharmony_ci dwc2_set_turnaround_time(hsotg); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && 114762306a36Sopenharmony_ci hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && 114862306a36Sopenharmony_ci hsotg->params.ulpi_fs_ls) { 114962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); 115062306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 115162306a36Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_FS_LS; 115262306a36Sopenharmony_ci usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; 115362306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 115462306a36Sopenharmony_ci } else { 115562306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 115662306a36Sopenharmony_ci usbcfg &= ~GUSBCFG_ULPI_FS_LS; 115762306a36Sopenharmony_ci usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; 115862306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (!hsotg->params.activate_ingenic_overcurrent_detection) { 116262306a36Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) { 116362306a36Sopenharmony_ci otgctl = readl(hsotg->regs + GOTGCTL); 116462306a36Sopenharmony_ci otgctl |= GOTGCTL_VBVALOEN | GOTGCTL_VBVALOVAL; 116562306a36Sopenharmony_ci writel(otgctl, hsotg->regs + GOTGCTL); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci return retval; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ciMODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); 117362306a36Sopenharmony_ciMODULE_AUTHOR("Synopsys, Inc."); 117462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1175