Received: by 10.213.65.68 with SMTP id h4csp924759imn; Wed, 28 Mar 2018 15:56:10 -0700 (PDT) X-Google-Smtp-Source: AIpwx49Em+C/epDjNSgtP9s3KgVfCM6JgdhmJ/LYfss2RTh+wx5XdS/NXiLmNWTeGxttUisNxWYf X-Received: by 10.98.220.86 with SMTP id t83mr4400961pfg.60.1522277770473; Wed, 28 Mar 2018 15:56:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522277770; cv=none; d=google.com; s=arc-20160816; b=u8px+rXa1qGsJWHId5DquElTTqALQduLvRlrWOPUXWtxWyfc0yhWgwDZuHpEyeuxO2 MbUzD5y1FRCchK2Da5buQCDzQHsZY4kYqYYC58A6AU2VpqGQf87mf4J3DsVh/FQz/AHu op8wCokMHDcsx6xkzTgHiq+1UTj5mRewumMvmXP4Fbvt7EmCJ5hMD9L/rJ08WriBHA3O hT66uYlSwOSB+lL/eRk/78VlyfCMyQnaeJRd006C0QCtjcAElrzjAgQPQwjQ3zBK3+LO 2dfr7xt2beIiWgYbr/plGa9OQaVkUOJW3DSvQXwUSbNMRD/z+u4f29V9B7bkI9Kfmpxs PJbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=WlKboCU4mU6Q7WKPej/Fe3i31qTVYiApRlqiYKMXxWY=; b=hE6dSIsdqaRXDf1giTlOIhn3sxElE2myXjXsoln/k9370cD0dK4+2a06FG2eSMosdd x+yxabSgxzYCJF6jKhletFs6lt1bbPnABxEepi+wuk0BgNEkIBE4KKIKDFxSC9pn1zcY GtsShgEjxM151u2RdkydG58/vMaQrKyv6spWFkKB3uTxMTdGnoa9qFfIBxQ+hiWYzUFS rtwurmGiWs9w+gY5jzWAB1Emhfj42yLDEZNmezKqSFZY3UB5qcmcFB8k/4RtCtk0pHeh HUMxvBmDlcY8Q/IYnCuBXnyT5cL+SXVkcDgztl5lXl3XRfw3xonXVnArr8SxL/Gjh702 xhsA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kDilt78g; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f2-v6si897315plo.434.2018.03.28.15.55.56; Wed, 28 Mar 2018 15:56:10 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kDilt78g; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753615AbeC1WxQ (ORCPT + 99 others); Wed, 28 Mar 2018 18:53:16 -0400 Received: from mail-ua0-f196.google.com ([209.85.217.196]:33953 "EHLO mail-ua0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753500AbeC1WxO (ORCPT ); Wed, 28 Mar 2018 18:53:14 -0400 Received: by mail-ua0-f196.google.com with SMTP id l21so2570009uak.1 for ; Wed, 28 Mar 2018 15:53:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=WlKboCU4mU6Q7WKPej/Fe3i31qTVYiApRlqiYKMXxWY=; b=kDilt78gLIe+pIoC35et1VsCWJXUQ5d6YJtmFTfvLXuEqMoz4ZxyBqqZRChtH5wEvr NgOp4S4XLm4++sURDOUkWQ0nMgDjRQYJSyE4i+iVxh+zrXyGX+v9SmUiNhMCAkBsjJCc BUIbuxZyZfU+/rda2Abq0qwZpvwyrJ7Ac2s+LWGMbR+gvqAN4DesiBDCaKtOhBItptu3 bHJet4EV115AUlCbY6uINNWQxs7NrfJbriFkncmcM6oGLiKSsrkUyucC4UYAkzisLQ4I pPp+Dt08seFlEHA/erXEL2hNcSBvV2v9VTM7iRTOLwrQ864qv9GWypDnE1LCJPxN1uxU UjCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=WlKboCU4mU6Q7WKPej/Fe3i31qTVYiApRlqiYKMXxWY=; b=Hbw17tYv2qBZC5THJEGZM/2Vbz9jgz0R34iwZdVPsiMnE6/34n9ymvYbgsc/PDO1Lh 5QpzTiSAhQkqcEdvYQrbzOJ2m00avcoSALFBk0CddpfEHOWicAkx3pCa9RbCupt7+dtT 8iJEBGHJOJgKCrRtpSZt6uO0LR7jGziQRcx8ZBl+9xoyz7gg0+mM8zzOSQ90qzdUbODT OJfSI2BmmTvSd+Vs67JArkWzvFE4O0J0k14Bhfm9LK93Ri94OrgHxP1bdEIe0CHlEZLn 6aqQ/a25tJyOyG/MF/g3pZg0v19R2KzXM89qGrLbgV3HPZDDIpTmojKT9IKl6x8lR3ol xbCw== X-Gm-Message-State: AElRT7GuJ1ESqwyr4+amMvhhSL/i4rmALjox7v/mRz/1IhrOAztxulhj armuy0cN40DW2hDmBtOmv1jJ8liFFBg0Lq6qpy4/7Q== X-Received: by 10.159.32.81 with SMTP id 75mr3932114uam.53.1522277593400; Wed, 28 Mar 2018 15:53:13 -0700 (PDT) MIME-Version: 1.0 Received: by 10.31.4.8 with HTTP; Wed, 28 Mar 2018 15:53:12 -0700 (PDT) In-Reply-To: <1522242500-10556-3-git-send-email-vviswana@codeaurora.org> References: <1522242500-10556-1-git-send-email-vviswana@codeaurora.org> <1522242500-10556-3-git-send-email-vviswana@codeaurora.org> From: Doug Anderson Date: Wed, 28 Mar 2018 15:53:12 -0700 Message-ID: Subject: Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching To: Vijay Viswanath Cc: Adrian Hunter , Ulf Hansson , linux-mmc@vger.kernel.org, LKML , Shawn Lin , linux-arm-msm@vger.kernel.org, georgi.djakov@linaro.org, asutoshd@codeaurora.org, stummala@codeaurora.org, venkatg@codeaurora.org, pramod.gurav@linaro.org, jeremymc@redhat.com, Bjorn Andersson , riteshh@codeaurora.org, Krishna Konda Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath wrote: > From: Krishna Konda > > The PADs for SD card are dual-voltage that support 3v/1.8v. Those PADs > have a control signal (io_pad_pwr_switch/mode18 ) that indicates > whether the PAD works in 3v or 1.8v. > > SDHC core on msm platforms should have IO_PAD_PWR_SWITCH bit set/unset > based on actual voltage used for IO lines. So when power irq is > triggered for io high or io low, the driver should check the voltages > supported and set the pad accordingly. > > Signed-off-by: Krishna Konda > Signed-off-by: Venkat Gopalakrishnan > Signed-off-by: Vijay Viswanath > --- > drivers/mmc/host/sdhci-msm.c | 64 ++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 62 insertions(+), 2 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c > index 2fcd9010..bbf9626 100644 > --- a/drivers/mmc/host/sdhci-msm.c > +++ b/drivers/mmc/host/sdhci-msm.c > @@ -78,12 +78,15 @@ > #define CORE_HC_MCLK_SEL_DFLT (2 << 8) > #define CORE_HC_MCLK_SEL_HS400 (3 << 8) > #define CORE_HC_MCLK_SEL_MASK (3 << 8) > +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) > +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) > #define CORE_HC_SELECT_IN_EN BIT(18) > #define CORE_HC_SELECT_IN_HS400 (6 << 19) > #define CORE_HC_SELECT_IN_MASK (7 << 19) > > #define CORE_3_0V_SUPPORT (1 << 25) > #define CORE_1_8V_SUPPORT (1 << 26) > +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) > > #define CORE_CSR_CDC_CTLR_CFG0 0x130 > #define CORE_SW_TRIG_FULL_CALIB BIT(16) > @@ -1109,7 +1112,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) > u32 irq_status, irq_ack = 0; > int retry = 10; > u32 pwr_state = 0, io_level = 0; > - > + u32 config; > > irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); > irq_status &= INT_MASK; > @@ -1166,6 +1169,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) > */ > writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); > > + /* > + * If we don't have info regarding the voltage levels supported by > + * regulators, don't change the IO PAD PWR SWITCH. > + */ > + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { > + /* Ensure order between core_mem and hc_mem */ > + mb(); Like in v2, I don't understand why you need a mb() before the read from CORE_VENDOR_SPEC. No reads or writes to the core_mem will affect the value you're reading here, so you need no barrier. If you need a barrier before the _write_ to CORE_VENDOR_SPEC then add it below. Then in the case where the config doesn't change you have no barriers. > + /* > + * We should unset IO PAD PWR switch only if the register write > + * can set IO lines high and the regulator also switches to 3 V. > + * Else, we should keep the IO PAD PWR switch set. > + * This is applicable to certain targets where eMMC vccq supply > + * is only 1.8V. In such targets, even during REQ_IO_HIGH, the > + * IO PAD PWR switch must be kept set to reflect actual > + * regulator voltage. This way, during initialization of > + * controllers with only 1.8V, we will set the IO PAD bit > + * without waiting for a REQ_IO_LOW. > + */ For the above comment, what about just: new_config = config if (msm_host->caps_0 == CORE_1_8V_SUPPORT) { new_config |= CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 == CORE_3_3V_SUPPORT) { new_config &= ~CORE_IO_PAD_PWR_SWITCH; } else if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { if (io_level & REQ_IO_HIGH) new_config &= ~CORE_IO_PAD_PWR_SWITCH; else if (io_level & REQ_IO_LOW) new_config |= CORE_IO_PAD_PWR_SWITCH; } if (config != new_config) { ... } AKA: first check if it only supports one voltage and pick that one. Else if it supports both you can use the request. This might be more important if you get rid of the initial setting in sdhci_msm_set_regulator_caps() as I'm suggesting. > + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); > + > + if (((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & > + CORE_3_0V_SUPPORT)) && > + (config & CORE_IO_PAD_PWR_SWITCH)) { > + config &= ~CORE_IO_PAD_PWR_SWITCH; > + writel_relaxed(config, > + host->ioaddr + CORE_VENDOR_SPEC); > + /* IO PAD register is in different memory space */ > + mb(); Wow, for a driver that tries so hard to use "relaxed" versions of writes to avoid barriers you sure end up needing to sprinkle a lot of these around "just in case". :( ...this one seems extra fishy because: * There are no more accesses after this one in this function. * If you're worried about something that happens outside of the context of the IRQ needing this wb() then that's a silly concern. Presumably if they were doing anything that could race with you they'd have a lock and locking routines are implicit barriers. * In the context of the IRQ itself the next call is sdhci_msm_complete_pwr_irq_wait(), which eventually calls wake_up. This has a locking primitive and thus an implicit barrier. * There's a direct call of sdhci_msm_handle_pwr_irq() from probe, and it has a big fat mb(). I have a hard time believing that matters too because I'd bet "platform_get_irq_byname" has at least one lock in it. IMHO these "_relaxed" calls are just not worth it except in _very_ targeted usage. > + } else if (((io_level & REQ_IO_LOW) || > + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) && > + !(config & CORE_IO_PAD_PWR_SWITCH)) { > + config |= CORE_IO_PAD_PWR_SWITCH; > + writel_relaxed(config, > + host->ioaddr + CORE_VENDOR_SPEC); > + /* IO PAD bit is in different memory space */ > + mb(); > + } > + } > + > if (pwr_state) > msm_host->curr_pwr_state = pwr_state; > if (io_level) > @@ -1322,7 +1364,8 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) > { > struct mmc_host *mmc = msm_host->mmc; > struct regulator *supply = mmc->supply.vqmmc; > - u32 caps = 0; > + u32 caps = 0, config; > + struct sdhci_host *host = mmc_priv(mmc); > > if (!IS_ERR(mmc->supply.vqmmc)) { > if (regulator_is_supported_voltage(supply, 1700000, 1950000)) > @@ -1335,6 +1378,23 @@ static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) > mmc_hostname(mmc), __func__); > } > > + if (caps) { > + /* > + * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH > + * bit can be used as required later on. > + */ > + u32 io_level = msm_host->curr_io_level; > + > + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); > + config |= CORE_IO_PAD_PWR_SWITCH_EN; > + > + if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT)) Slight nit that there's a tab character after "caps &". Please replace it with a space. > + config &= ~CORE_IO_PAD_PWR_SWITCH; > + else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT)) > + config |= CORE_IO_PAD_PWR_SWITCH; Are you sure that's right? In English: * If we requested high and we support high then set to high. * else if we requested low __or__ we support low then set low. Things that are weird above that: * If we request low but don't support low, switch to low anyway. * If we request high but only support low, switch to low anyway. If nothing else seems like this would deserve a comment, but I'd be curious of the justification for that logic. Also: seems like this is duplicated code between here and sdhci_msm_handle_pwr_irq(). Does it even need to be here? Can't you just move the call to sdhci_msm_set_regulator_caps() before the call to sdhci_msm_handle_pwr_irq() in probe? Then just let that first call to to sdhci_msm_handle_pwr_irq() do this work? In sdhci_msm_handle_pwr_irq() you can always just "OR" in CORE_IO_PAD_PWR_SWITCH_EN -Doug