Received: by 2002:a05:6a10:17d3:0:0:0:0 with SMTP id hz19csp498220pxb; Wed, 14 Apr 2021 22:40:58 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyF0/6gfHr9ONmROEJL3P6ME/5S7E9obscRNH2YOr/M3NYYI2zanuLQct8v0VNiT27ChXpN X-Received: by 2002:a17:90a:d681:: with SMTP id x1mr2005697pju.82.1618465258795; Wed, 14 Apr 2021 22:40:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1618465258; cv=none; d=google.com; s=arc-20160816; b=lBi8hgls6qXbj5gU4Cf/bvrTXsVc5TJfQB8rprKkMfXTR5g+i1Bg7fHgJ7pp1NvYcO xX6dUtE6l+x3OxgljH0HG4Xf2O2Qu5s7JwvjiFQ4SjKEoioV4HDG0f+h3dKcrdoPnuis Ozre0/coC9SQMGCxMxgFXNO6gNYYiiL4MFq4eCnfb2ni6ZGtMEvu+aYR+2QUqG6/nQ2M 2AVNnOJfqwe5/W9yEXSXffLfFEQhVkrNqpY9UVw+V1ewW8vmxViMe7Dpfi8guthEwACE oDjqrm8zsnK0695j7/0vEL6xtxkdPKoUM5IxQiaoA0LS48Z6ZDE6aB/J1+YdLYQaWle7 s5Rg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:from:references:in-reply-to :message-id:date:dkim-signature; bh=a4iV7m4rf590Xc66jMinMuJ/9RNpB/UHSzCoLP6s+Mg=; b=XiI0Vt8k8fxM9PrrGr9bdBsfmsVBzQ0s9dC2dAWwvwnjwyhFG8eTtvaD6VgjjDmpFR xjRd59qoEnXOyT3rWW9ifJaH5+Ng5uZ8Ai4s+Jz4cCOGMbKeAW4M8dSCzkzbhuVikLe+ 0TzzXU2PLLZLs+zjtmCjBIT8yMjV9dwfe9Z6HjgVKUY7xTPVonu1+JxM5jIcBhZkvPHd HXbWY0e6IdwQmrkABZjVIr9+jkBqrWlffYRngBzgMmW3r06mgq71v2alDpEG8PxlIuW5 yrIECa15/4Z3V+mnuftldtqE7RuSLJX3lAkNaSaUXovKOHqZfRniQKz+VklLTfhidJMi h5pg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@synopsys.com header.s=mail header.b=aCQwl9rO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=synopsys.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id i187si2090183pfb.54.2021.04.14.22.40.46; Wed, 14 Apr 2021 22:40:58 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@synopsys.com header.s=mail header.b=aCQwl9rO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=synopsys.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230286AbhDOFkT (ORCPT + 99 others); Thu, 15 Apr 2021 01:40:19 -0400 Received: from smtprelay-out1.synopsys.com ([149.117.73.133]:56450 "EHLO smtprelay-out1.synopsys.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230239AbhDOFkS (ORCPT ); Thu, 15 Apr 2021 01:40:18 -0400 Received: from mailhost.synopsys.com (mdc-mailhost1.synopsys.com [10.225.0.209]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by smtprelay-out1.synopsys.com (Postfix) with ESMTPS id 26602404B4; Thu, 15 Apr 2021 05:39:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=synopsys.com; s=mail; t=1618465196; bh=hpok5kVHp0MfHWo/Afzmy8pDTmAO8J2XmKEyi0l2Cjk=; h=Date:In-Reply-To:References:From:Subject:To:Cc:From; b=aCQwl9rOgFwK5z+VnGsK1mwzxQLnJLeVZywH8w4MtZPCHdg4z9hTGxcvUYQBI8Xf2 0hPoJ/DKUuuvCT7bj6a+F6qLiBRpDPIrTis5HFOkkWdfuPG3qGQ5d/rofdgiMKc7W9 MCxVUWk3IV/lh2SbFnLnpiHXrbU1dxDQX5h/0Dk+b74De+nQcO3S7NkN9OpWkYpUfH yNAXCMrGI57HtkU/X+tZ1s19kecD75GSds6J0HyzKqzo6UzGhACZ9jGxCFHZFPusEv a7mS8fCmoC0Tq1j6mK8Bh+IDCGS0FmFNTTOtLpcW/A07INmKsiH5C/TS2+4UY154i3 H30AomaBb6IMA== Received: from razpc-HP (razpc-hp.internal.synopsys.com [10.116.126.207]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by mailhost.synopsys.com (Postfix) with ESMTPSA id DA4CCA005C; Thu, 15 Apr 2021 05:39:52 +0000 (UTC) Received: by razpc-HP (sSMTP sendmail emulation); Thu, 15 Apr 2021 09:39:51 +0400 Date: Thu, 15 Apr 2021 09:39:51 +0400 Message-Id: In-Reply-To: References: X-SNPS-Relay: synopsys.com From: Artur Petrosyan Subject: [PATCH 04/15] usb: dwc2: Fix hibernation between host and device modes. To: John Youn , Felipe Balbi , Greg Kroah-Hartman , Artur Petrosyan , Minas Harutyunyan , Vardan Mikayelyan , Grigor Tovmasyan , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Artur Petrosyan , Minas Harutyunyan Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When core is in hibernation in host mode and a device cable was connected then driver exited from device hibernation. However, registers saved for host mode and when exited from device hibernation register restore would be done for device register which was wrong because there was no device registers stored to restore. - Added dwc_handle_gpwrdn_disc_det() function which handles gpwrdn disconnect detect flow and exits hibernation without restoring the registers. - Updated exiting from hibernation in GPWRDN_STS_CHGINT with calling dwc_handle_gpwrdn_disc_det() function. Here no register is restored which is the solution described above. Fixes: 65c9c4c6b01f ("usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler") Signed-off-by: Artur Petrosyan Signed-off-by: Minas Harutyunyan Acked-by: Minas Harutyunyan --- drivers/usb/dwc2/core_intr.c | 154 +++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 71 deletions(-) diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 550c52c1a0c7..27d729fad227 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -680,6 +680,71 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg) return 0; } +/** + * dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect. + * Exits hibernation without restoring registers. + * + * @hsotg: Programming view of DWC_otg controller + * @gpwrdn: GPWRDN register + */ +static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg, + u32 gpwrdn) +{ + u32 gpwrdn_tmp; + + /* Switch-on voltage to the core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Reset core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Disable Power Down Clamp */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Deassert reset core */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp |= GPWRDN_PWRDNRSTN; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + udelay(5); + + /* Disable PMU interrupt */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + + /* De-assert Wakeup Logic */ + gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); + gpwrdn_tmp &= ~GPWRDN_PMUACTV; + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + + hsotg->hibernated = 0; + hsotg->bus_suspended = 0; + + if (gpwrdn & GPWRDN_IDSTS) { + hsotg->op_state = OTG_STATE_B_PERIPHERAL; + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hsotg_core_init_disconnected(hsotg, false); + dwc2_hsotg_core_connect(hsotg); + } else { + hsotg->op_state = OTG_STATE_A_HOST; + + /* Initialize the Core for Host mode */ + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + dwc2_hcd_start(hsotg); + } +} + /* * GPWRDN interrupt handler. * @@ -701,64 +766,14 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) if ((gpwrdn & GPWRDN_DISCONN_DET) && (gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) { - u32 gpwrdn_tmp; - dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__); - - /* Switch-on voltage to the core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Reset core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Disable Power Down Clamp */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Deassert reset core */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp |= GPWRDN_PWRDNRSTN; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - udelay(10); - - /* Disable PMU interrupt */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - - /* De-assert Wakeup Logic */ - gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN); - gpwrdn_tmp &= ~GPWRDN_PMUACTV; - dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); - - hsotg->hibernated = 0; - - if (gpwrdn & GPWRDN_IDSTS) { - hsotg->op_state = OTG_STATE_B_PERIPHERAL; - dwc2_core_init(hsotg, false); - dwc2_enable_global_interrupts(hsotg); - dwc2_hsotg_core_init_disconnected(hsotg, false); - dwc2_hsotg_core_connect(hsotg); - } else { - hsotg->op_state = OTG_STATE_A_HOST; - - /* Initialize the Core for Host mode */ - dwc2_core_init(hsotg, false); - dwc2_enable_global_interrupts(hsotg); - dwc2_hcd_start(hsotg); - } - } - - if ((gpwrdn & GPWRDN_LNSTSCHG) && - (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) { + /* + * Call disconnect detect function to exit from + * hibernation + */ + dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn); + } else if ((gpwrdn & GPWRDN_LNSTSCHG) && + (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) { dev_dbg(hsotg->dev, "%s: GPWRDN_LNSTSCHG\n", __func__); if (hsotg->hw_params.hibernation && hsotg->hibernated) { @@ -769,24 +784,21 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) dwc2_exit_hibernation(hsotg, 1, 0, 1); } } - } - if ((gpwrdn & GPWRDN_RST_DET) && (gpwrdn & GPWRDN_RST_DET_MSK)) { + } else if ((gpwrdn & GPWRDN_RST_DET) && + (gpwrdn & GPWRDN_RST_DET_MSK)) { dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__); if (!linestate && (gpwrdn & GPWRDN_BSESSVLD)) dwc2_exit_hibernation(hsotg, 0, 1, 0); - } - if ((gpwrdn & GPWRDN_STS_CHGINT) && - (gpwrdn & GPWRDN_STS_CHGINT_MSK) && linestate) { + } else if ((gpwrdn & GPWRDN_STS_CHGINT) && + (gpwrdn & GPWRDN_STS_CHGINT_MSK)) { dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__); - if (hsotg->hw_params.hibernation && - hsotg->hibernated) { - if (gpwrdn & GPWRDN_IDSTS) { - dwc2_exit_hibernation(hsotg, 0, 0, 0); - call_gadget(hsotg, resume); - } else { - dwc2_exit_hibernation(hsotg, 1, 0, 1); - } - } + /* + * As GPWRDN_STS_CHGINT exit from hibernation flow is + * the same as in GPWRDN_DISCONN_DET flow. Call + * disconnect detect helper function to exit from + * hibernation. + */ + dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn); } } -- 2.25.1