[PATCH 0/5] mmc: sdhci-msm: Corrections to implementation of power irq

2017-08-17 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus on/off
require sdhc controller to be ready before progressing further. Once a
register write which affects IO lines is done, the driver should wait for
power irq from controller. Once the irq comes, the driver should acknowledge
the irq by writing to power control register. If the acknowledgement is not
given to controller, the controller may not complete the corresponding
register write action and this can mess up the controller if drivers proceeds
without power irq completing. 

Sahitya Tummala (2):
  mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset
  mmc: sdhci-msm: Add support to wait for power irq

Subhash Jadavani (1):
  mmc: sdhci-msm: fix issue with power irq

Vijay Viswanath (2):
  mmc: sdhci-msm: Add ops to do sdhc register write
  defconfig: msm: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

 arch/arm64/configs/defconfig |   1 +
 drivers/mmc/host/sdhci-msm.c | 233 ++-
 2 files changed, 229 insertions(+), 5 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH 1/5] mmc: sdhci-msm: fix issue with power irq

2017-08-17 Thread Vijay Viswanath
From: Subhash Jadavani 

SDCC controller reset (SW_RST) during probe may trigger power irq if
previous status of PWRCTL was either BUS_ON or IO_HIGH_V. So before we
enable the power irq interrupt in GIC (by registering the interrupt
handler), we need to ensure that any pending power irq interrupt status
is acknowledged otherwise power irq interrupt handler would be fired
prematurely.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9d601dc..0957199 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1128,6 +1128,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
u16 host_version, core_minor;
u32 core_version, config;
u8 core_major;
+   u32 irq_status, irq_ctl;
 
host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
if (IS_ERR(host))
@@ -1250,6 +1251,28 @@ static int sdhci_msm_probe(struct platform_device *pdev)
   CORE_VENDOR_SPEC_CAPABILITIES0);
}
 
+   /*
+* Power on reset state may trigger power irq if previous status of
+* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
+* interrupt in GIC, any pending power irq interrupt should be
+* acknowledged. Otherwise power irq interrupt handler would be
+* fired prematurely.
+*/
+
+   irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+   writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL);
+   if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+   irq_ctl |= CORE_PWRCTL_BUS_SUCCESS;
+   if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW))
+   irq_ctl |= CORE_PWRCTL_IO_SUCCESS;
+   writel_relaxed(irq_ctl, msm_host->core_mem + CORE_PWRCTL_CTL);
+   /*
+* Ensure that above writes are propogated before interrupt enablement
+* in GIC.
+*/
+   mb();
+
/* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -1259,6 +1282,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto clk_disable;
}
 
+   /* Enable pwr irq interrupts */
+   writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
+
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH 2/5] mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset

2017-08-17 Thread Vijay Viswanath
From: Sahitya Tummala 

There is a rare scenario in HW, where the first clear pulse could
be lost when the actual reset and clear/read of status register
are happening at the same time. Fix this by retrying upto 10 times
to ensure the status register gets cleared. Otherwise, this will
lead to a spurious power IRQ which results in system instability.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 43 ---
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 0957199..f3e0489 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -995,17 +995,51 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 
0x%08x\n",
+   mmc_hostname(host->mmc),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
 {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
+   int retry = 10;
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK;
 
writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
 
+   /*
+* There is a rare HW scenario where the first clear pulse could be
+* lost when actual reset and clear/read of status register is
+* happening at a time. Hence, retry for at least 10 times to make
+* sure status register is cleared. Otherwise, this will result in
+* a spurious power IRQ resulting in system instability.
+*/
+   while (irq_status & readl_relaxed(msm_host->core_mem +
+   CORE_PWRCTL_STATUS)) {
+   if (retry == 0) {
+   pr_err("%s: Timedout clearing (0x%x) pwrctl status 
register\n",
+   mmc_hostname(host->mmc), irq_status);
+   sdhci_msm_dump_pwr_ctrl_regs(host);
+   WARN_ON(1);
+   }
+   writel_relaxed(irq_status,
+   msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   retry--;
+   udelay(10);
+   }
+
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
@@ -1017,13 +1051,17 @@ static void sdhci_msm_voltage_switch(struct sdhci_host 
*host)
 * switches are handled by the sdhci core, so just report success.
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+
+   pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
+   mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
+   irq_ack);
 }
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
struct sdhci_host *host = (struct sdhci_host *)data;
 
-   sdhci_msm_voltage_switch(host);
+   sdhci_msm_handle_pwr_irq(host, irq);
 
return IRQ_HANDLED;
 }
@@ -1106,7 +1144,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-   .voltage_switch = sdhci_msm_voltage_switch,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH 4/5] mmc: sdhci-msm: Add ops to do sdhc register write

2017-08-17 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus
on/off require controller to be ready before progressing further. When
the controller is ready, it will generate a power irq which needs to be
handled. The thread which initiated the register write should wait for
power irq to complete. This will be done through the new sdhc msm write
APIs which will check whether the particular write can trigger a power
irq and wait for it with a timeout if it is expected.
The SDHC core power control IRQ gets triggered when -
* There is a state change in power control bit (bit 0)
  of SDHCI_POWER_CONTROL register.
* There is a state change in 1.8V enable bit (bit 3) of
  SDHCI_HOST_CONTROL2 register.
* Bit 1 of SDHCI_SOFTWARE_RESET is set.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 6d3b1fd..6571880 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1250,6 +1250,41 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
__sdhci_msm_set_clock(host, clock);
 }
 
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+static void __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
+{
+   u32 req_type = 0;
+
+   switch (reg) {
+   case SDHCI_HOST_CONTROL2:
+   req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
+   REQ_IO_HIGH;
+   break;
+   case SDHCI_SOFTWARE_RESET:
+   if (host->pwr && (val & SDHCI_RESET_ALL))
+   req_type = REQ_BUS_OFF;
+   break;
+   case SDHCI_POWER_CONTROL:
+   req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
+   break;
+   }
+
+   if (req_type)
+   sdhci_msm_check_power_status(host, req_type);
+}
+
+static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
+{
+   writew_relaxed(val, host->ioaddr + reg);
+   __sdhci_msm_check_write(host, val, reg);
+}
+
+static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+   writeb_relaxed(val, host->ioaddr + reg);
+   __sdhci_msm_check_write(host, val, reg);
+}
+#endif
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1264,6 +1299,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   .write_w = sdhci_msm_writew,
+   .write_b = sdhci_msm_writeb,
+#endif
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH 5/5] defconfig: msm: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

2017-08-17 Thread Vijay Viswanath
Enable CONFIG_MMC_SDHCI_IO_ACCESSORS so that SDHC controller specific
register read and write APIs, if registered, can be used.

Signed-off-by: Vijay Viswanath 
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 65cdd87..a3c93ed 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -398,6 +398,7 @@ CONFIG_MMC_SDHCI_CADENCE=y
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_MESON_GX=y
 CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
 CONFIG_MMC_SPI=y
 CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH 3/5] mmc: sdhci-msm: Add support to wait for power irq

2017-08-17 Thread Vijay Viswanath
From: Sahitya Tummala 

Add support API which will check if power irq is expected to be
generated and wait for the power irq to come and complete if the irq is
expected.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 125 ++-
 1 file changed, 123 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index f3e0489..6d3b1fd 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -123,6 +123,10 @@
 #define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
 
 #define MSM_MMC_AUTOSUSPEND_DELAY_MS   50
+
+/* Timeout value to avoid infinite waiting for pwr_irq */
+#define MSM_PWR_IRQ_TIMEOUT_MS 5000
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -138,6 +142,11 @@ struct sdhci_msm_host {
bool calibration_done;
u8 saved_tuning_phase;
bool use_cdclp533;
+   u32 curr_pwr_state;
+   u32 curr_io_level;
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   struct completion pwr_irq_completion;
+#endif
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -995,6 +1004,90 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+static inline void sdhci_msm_init_pwr_irq_completion(
+   struct sdhci_msm_host *msm_host)
+{
+   init_completion(&msm_host->pwr_irq_completion);
+}
+
+static inline void sdhci_msm_complete_pwr_irq_completion(
+   struct sdhci_msm_host *msm_host)
+{
+   complete(&msm_host->pwr_irq_completion);
+}
+
+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   unsigned long flags;
+   bool done = false;
+
+   spin_lock_irqsave(&host->lock, flags);
+   pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+   mmc_hostname(host->mmc), __func__, req_type,
+   msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+   /*
+* The IRQ for request type IO High/LOW will be generated when -
+* there is a state change in 1.8V enable bit (bit 3) of
+* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+* which indicates 3.3V IO voltage. So, when MMC core layer tries
+* to set it to 3.3V before card detection happens, the
+* IRQ doesn't get triggered as there is no state change in this bit.
+* The driver already handles this case by changing the IO voltage
+* level to high as part of controller power up sequence. Hence, check
+* for host->pwr to handle a case where IO voltage high request is
+* issued even before controller power up.
+*/
+   if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+   pr_debug("%s: do not wait for power IRQ that never comes\n",
+   mmc_hostname(host->mmc));
+   spin_unlock_irqrestore(&host->lock, flags);
+   return;
+   }
+   if ((req_type & msm_host->curr_pwr_state) ||
+   (req_type & msm_host->curr_io_level))
+   done = true;
+   spin_unlock_irqrestore(&host->lock, flags);
+   /*
+* This is needed here to hanlde a case where IRQ gets
+* triggered even before this function is called so that
+* x->done counter of completion gets reset. Otherwise,
+* next call to wait_for_completion returns immediately
+* without actually waiting for the IRQ to be handled.
+*/
+   if (done)
+   init_completion(&msm_host->pwr_irq_completion);
+   else if (!wait_for_completion_timeout(&msm_host->pwr_irq_completion,
+   msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+   __WARN_printf("%s: request(%d) timed out waiting for pwr_irq\n",
+   mmc_hostname(host->mmc), req_type);
+   pr_debug("%s: %s: request %d done\n", mmc_hostname(host-&g

[PATCH RFC 0/2] Internal voltage control for platform drivers

2018-06-21 Thread Vijay Viswanath
Certain SDHC controllers may require that voltage switching happen after
sepcial conditions. Added a QUIRK for such controllers to use.

For SDHCI-MSM controllers, power irq is a signal from controller to SW
that it is ready for voltage switch. So added support to register
voltage regulators from the msm driver and use them.
Voltage switching from core layer is causing CRC/cmd timeout errors in
some chipsets.

Tested on: sdm845, db410c
Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version"

Vijay Viswanath (2):
  mmc: sdhci: Allow platform controlled voltage switching
  mmc: sdhci-msm: Use internal voltage control

 drivers/mmc/host/sdhci-msm.c | 99 ++--
 drivers/mmc/host/sdhci.c | 20 ++---
 drivers/mmc/host/sdhci.h |  2 +
 3 files changed, 104 insertions(+), 17 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

2018-06-21 Thread Vijay Viswanath
Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

Add a quirk, which can be used by drivers of such controllers.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci.c | 20 +++-
 drivers/mmc/host/sdhci.h |  2 ++
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..f0346d4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, 
unsigned char mode,
 void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 unsigned short vdd)
 {
-   if (IS_ERR(host->mmc->supply.vmmc))
+   if (IS_ERR(host->mmc->supply.vmmc) ||
+   (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))
sdhci_set_power_noreg(host, mode, vdd);
else
sdhci_set_power_reg(host, mode, vdd);
@@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host 
*mmc,
ctrl &= ~SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
-   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   !(host->quirks2 &
+   SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
pr_warn("%s: Switching to 3.3V signalling 
voltage failed\n",
@@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host 
*mmc,
case MMC_SIGNAL_VOLTAGE_180:
if (!(host->flags & SDHCI_SIGNALING_180))
return -EINVAL;
-   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
pr_warn("%s: Switching to 1.8V signalling 
voltage failed\n",
@@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host)
 * the host can take the appropriate action if regulators are not
 * available.
 */
-   ret = mmc_regulator_get_supply(mmc);
+   if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))
+   ret = mmc_regulator_get_supply(mmc);
+   else
+   ret = 0;
if (ret)
return ret;
 
@@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host)
 
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
if (!IS_ERR(mmc->supply.vqmmc)) {
-   ret = regulator_enable(mmc->supply.vqmmc);
+   if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))
+   ret = regulator_enable(mmc->supply.vqmmc);
+   else
+   ret = 0;
if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170,
195))
host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 23966f8..3b0c97a 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -450,6 +450,8 @@ struct sdhci_host {
  * obtainable timeout.
  */
 #define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT(1<<17)
+/* Regulator voltage changes are being done from platform layer */
+#define SDHCI_QUIRK2_INTERNAL_PWR_CTL  (1<<18)
 
int irq;/* Device IRQ */
void __iomem *ioaddr;   /* Mapped address */
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 2/2] mmc: sdhci-msm: Use internal voltage control

2018-06-21 Thread Vijay Viswanath
Some sdhci-msm controllers require that voltage switching be done after
the HW is ready for it. The HW informs its readiness through power irq.
The voltage switching should happen only then.

Use the quirk for internal voltage switching and then control the
voltage switching using power irq.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 99 ++--
 1 file changed, 87 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a0dc3e1..ebdde29 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -43,7 +43,9 @@
 #define CORE_PWRCTL_IO_LOW BIT(2)
 #define CORE_PWRCTL_IO_HIGHBIT(3)
 #define CORE_PWRCTL_BUS_SUCCESS BIT(0)
+#define CORE_PWRCTL_BUS_FAILBIT(1)
 #define CORE_PWRCTL_IO_SUCCESS BIT(2)
+#define CORE_PWRCTL_IO_FAIL BIT(3)
 #define REQ_BUS_OFFBIT(0)
 #define REQ_BUS_ON BIT(1)
 #define REQ_IO_LOW BIT(2)
@@ -258,6 +260,7 @@ struct sdhci_msm_host {
bool mci_removed;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
+   bool pltfm_init_done;
 };
 
 static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host 
*host)
@@ -1314,8 +1317,9 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   struct mmc_host *mmc = host->mmc;
u32 irq_status, irq_ack = 0;
-   int retry = 10;
+   int retry = 10, ret = 0;
u32 pwr_state = 0, io_level = 0;
u32 config;
const struct sdhci_msm_offset *msm_offset = msm_host->offset;
@@ -1351,14 +1355,59 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 
/* Handle BUS ON/OFF*/
if (irq_status & CORE_PWRCTL_BUS_ON) {
-   pwr_state = REQ_BUS_ON;
-   io_level = REQ_IO_HIGH;
-   irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+   if (mmc->supply.vmmc) {
+   ret = regulator_set_load(mmc->supply.vmmc, 80);
+   ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+   mmc->ios.vdd);
+   if (ret)
+   pr_err("%s: vmmc enable failed: %d\n",
+   mmc_hostname(mmc), ret);
+   }
+   if (mmc->supply.vqmmc && !ret) {
+   ret = regulator_set_load(mmc->supply.vqmmc, 22000);
+   ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vqmmc,
+   mmc->ios.vdd);
+   if (!ret)
+   ret = regulator_enable(mmc->supply.vqmmc);
+   if (ret)
+   pr_err("%s: vqmmc enable failed: %d\n",
+   mmc_hostname(mmc), ret);
+   }
+   if (!ret) {
+   pwr_state = REQ_BUS_ON;
+   io_level = REQ_IO_HIGH;
+   irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+   } else {
+   pr_err("%s: BUS_ON req failed(%d). irq_status: 
0x%08x\n",
+   mmc_hostname(mmc), ret, irq_status);
+   irq_ack |= CORE_PWRCTL_BUS_FAIL;
+   }
}
if (irq_status & CORE_PWRCTL_BUS_OFF) {
-   pwr_state = REQ_BUS_OFF;
-   io_level = REQ_IO_LOW;
-   irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+   if (mmc->supply.vmmc && msm_host->pltfm_init_done) {
+   ret = regulator_set_load(mmc->supply.vmmc, 0);
+   ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+   mmc->ios.vdd);
+   if (ret)
+   pr_err("%s: vqmmc disabling failed: %d\n",
+   mmc_hostname(mmc), ret);
+   }
+   if (mmc->supply.vqmmc && msm_host->pltfm_init_done && !ret) {
+   ret = regulator_set_load(mmc->supply.vqmmc, 0);
+   ret |= regulator_disable(mmc->supply.vqmmc);
+   if (ret)
+   pr_err("%s: vqmmc disabling failed: %d\n",
+   mmc_hostname(mmc), ret);
+   }
+   if (!ret) {
+   pwr_state = REQ_BUS_OFF;
+   io_level = REQ_IO_LOW;
+   irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+   } el

[PATCH V1 0/3] Internal voltage control for platform drivers

2018-07-20 Thread Vijay Viswanath
Certain SDHC controllers may require that voltage switching happen after
sepcial conditions. Added a QUIRK for such controllers to use.

For SDHCI-MSM controllers, power irq is a signal from controller to SW
that it is ready for voltage switch. So added support to register
voltage regulators from the msm driver and use them.
Voltage switching from core layer is causing CRC/cmd timeout errors in
some chipsets.

Changes since RFC:
- Added DT option to pass regulator load values the sdhci-msm driver
should vote during BUS_ON and BUS_OFF power irq.
- Removed quirk and used local flags in sdhci_add_host to to avoid
scenario of both sdhci & sdhci-msm layer controlling the regulators.
- Introduced two sdhci msm layer APIs to replace the respective
sdhci layer APIs. This is again to stop sdhci layer from
controlling regulators if sdhci_msm layer is present.

Tested on: sdm845
Requies patch series:"[PATCH V3 0/4] Changes for SDCC5 version"

Vijay Viswanath (3):
  mmc: sdhci: Allow platform controlled voltage switching
  Documentation: sdhci-msm: Add entries for passing load values
  mmc: sdhci-msm: Use internal voltage control

 .../devicetree/bindings/mmc/sdhci-msm.txt  |   6 +
 drivers/mmc/host/sdhci-msm.c   | 220 +++--
 drivers/mmc/host/sdhci.c   |  21 +-
 3 files changed, 231 insertions(+), 16 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching

2018-07-20 Thread Vijay Viswanath
Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

During setup/cleanup of host, check whether regulator enable/disable
was already done by platform driver.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci.c | 21 -
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..494a1e2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host)
unsigned int override_timeout_clk;
u32 max_clk;
int ret;
+   bool enable_vqmmc = false;
 
WARN_ON(host == NULL);
if (host == NULL)
@@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host)
 * the host can take the appropriate action if regulators are not
 * available.
 */
-   ret = mmc_regulator_get_supply(mmc);
+   if (!mmc->supply.vmmc) {
+   ret = mmc_regulator_get_supply(mmc);
+   enable_vqmmc  = true;
+   } else {
+   ret = 0;
+   }
if (ret)
return ret;
 
@@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host)
 
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
if (!IS_ERR(mmc->supply.vqmmc)) {
-   ret = regulator_enable(mmc->supply.vqmmc);
+   if (enable_vqmmc)
+   ret = regulator_enable(mmc->supply.vqmmc);
+   else
+   ret = 0;
if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170,
195))
host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
@@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host)
return 0;
 
 unreg:
-   if (!IS_ERR(mmc->supply.vqmmc))
+   if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc)
regulator_disable(mmc->supply.vqmmc);
 undma:
if (host->align_buffer)
@@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host)
 {
struct mmc_host *mmc = host->mmc;
 
-   if (!IS_ERR(mmc->supply.vqmmc))
+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   (regulator_is_enabled(mmc->supply.vqmmc) > 0))
regulator_disable(mmc->supply.vqmmc);
 
if (host->align_buffer)
@@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 
tasklet_kill(&host->finish_tasklet);
 
-   if (!IS_ERR(mmc->supply.vqmmc))
+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   (regulator_is_enabled(mmc->supply.vqmmc) > 0))
regulator_disable(mmc->supply.vqmmc);
 
if (host->align_buffer)
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V1 2/3] Documentation: sdhci-msm: Add entries for passing load values

2018-07-20 Thread Vijay Viswanath
The load a particular sdhc controller should request from a regulator
is device specific and hence each device should individually vote for
the required load.

Signed-off-by: Vijay Viswanath 
---
 Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 502b3b8..ee34f28 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -26,6 +26,11 @@ Required properties:
"cal"   - reference clock for RCLK delay calibration (optional)
"sleep" - sleep clock for RCLK delay calibration (optional)
 
+Optional properties:
+- -current-level - specifies load levels for supply during BUS_ON
+   and BUS_OFF states in power irq. Should be specified in
+   pairs (lpm, hpm), for BUS_OFF and BUS_ON respectively.
+   Units uA.
 Example:
 
sdhc_1: sdhci@f9824900 {
@@ -37,6 +42,7 @@ Example:
 
vmmc-supply = <&pm8941_l20>;
vqmmc-supply = <&pm8941_s3>;
+   vqmmc-current-level = <200 22000>;
 
pinctrl-names = "default";
pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V1 3/3] mmc: sdhci-msm: Use internal voltage control

2018-07-20 Thread Vijay Viswanath
Some sdhci-msm controllers require that voltage switching be done after
the HW is ready for it. The HW informs its readiness through power irq.
The voltage switching should happen only then.

Use the quirk for internal voltage switching and then control the
voltage switching using power irq.

Signed-off-by: Asutosh Das 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Veerabhadrarao Badiganti 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 220 ---
 1 file changed, 209 insertions(+), 11 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a0dc3e1..47732a2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -43,7 +43,9 @@
 #define CORE_PWRCTL_IO_LOW BIT(2)
 #define CORE_PWRCTL_IO_HIGHBIT(3)
 #define CORE_PWRCTL_BUS_SUCCESS BIT(0)
+#define CORE_PWRCTL_BUS_FAILBIT(1)
 #define CORE_PWRCTL_IO_SUCCESS BIT(2)
+#define CORE_PWRCTL_IO_FAIL BIT(3)
 #define REQ_BUS_OFFBIT(0)
 #define REQ_BUS_ON BIT(1)
 #define REQ_IO_LOW BIT(2)
@@ -236,6 +238,14 @@ struct sdhci_msm_variant_info {
const struct sdhci_msm_offset *offset;
 };
 
+/* Holds voltage regulator information to be used by the driver*/
+struct sdhci_msm_vreg_info {
+   bool vmmc_load;
+   u32 vmmc_level[2];
+   bool vqmmc_load;
+   u32 vqmmc_level[2];
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -258,6 +268,8 @@ struct sdhci_msm_host {
bool mci_removed;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
+   struct sdhci_msm_vreg_info vreg_info;
+   bool pltfm_init_done;
 };
 
 static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host 
*host)
@@ -1314,11 +1326,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   struct mmc_host *mmc = host->mmc;
u32 irq_status, irq_ack = 0;
-   int retry = 10;
+   int retry = 10, ret = 0;
u32 pwr_state = 0, io_level = 0;
u32 config;
const struct sdhci_msm_offset *msm_offset = msm_host->offset;
+   struct sdhci_msm_vreg_info vreg_info = msm_host->vreg_info;
 
irq_status = msm_host_readl(msm_host, host,
msm_offset->core_pwrctl_status);
@@ -1351,14 +1365,91 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 
/* Handle BUS ON/OFF*/
if (irq_status & CORE_PWRCTL_BUS_ON) {
-   pwr_state = REQ_BUS_ON;
-   io_level = REQ_IO_HIGH;
-   irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+   if (!IS_ERR(mmc->supply.vmmc)) {
+   if (vreg_info.vmmc_load)
+   ret = regulator_set_load(mmc->supply.vmmc,
+   vreg_info.vmmc_level[1]);
+   ret |= mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+   mmc->ios.vdd);
+   if (ret)
+   pr_err("%s: vmmc enable failed: %d\n",
+   mmc_hostname(mmc), ret);
+   }
+
+   if (!IS_ERR(mmc->supply.vqmmc) && !ret) {
+   struct mmc_ios ios;
+
+   if (vreg_info.vqmmc_load)
+   ret = regulator_set_load(mmc->supply.vqmmc,
+   vreg_info.vqmmc_level[1]);
+   /*
+* The IO voltage regulator maynot always support
+* a voltage close to vdd. Set IO voltage based on
+* capability of the regulator.
+*/
+   if (msm_host->caps_0 & CORE_3_0V_SUPPORT)
+   ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330;
+   else if (msm_host->caps_0 & CORE_1_8V_SUPPORT)
+   ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180;
+   if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
+   pr_err("%s: %s: setting signal voltage: %d\n",
+   mmc_hostname(mmc), __func__,
+   ios.signal_voltage);
+   ret |= mmc_regulator_set_vqmmc(mmc, &ios);
+   }
+
+   if (!ret)
+   ret = regulator_enable(mmc->supply.vqmmc);
+   if (ret)
+   pr_err("%s: vqm

Re: [PATCH RFC 2/7] mmc: core: devfreq: Add devfreq based clock scaling support

2018-07-23 Thread Vijay Viswanath

Hi Sayali,

On 7/13/2018 3:22 PM, Sayali Lokhande wrote:

This change adds the use of devfreq to MMC.
Both eMMC and SD card will use it.
For some workloads, such as video playback, it isn't
necessary for these cards to run at high speed.
Running at lower frequency, for example 52MHz, in such
cases can still meet the deadlines for data transfers.
Scaling down the clock frequency dynamically has power
savings not only because the bus is running at lower frequency
but also has an advantage of scaling down the system core
voltage, if supported.
Provide an ondemand clock scaling support similar to the
cpufreq ondemand governor having two thresholds,
up_threshold and down_threshold to decide whether to
increase the frequency or scale it down respectively.
The sampling interval is in the order of milliseconds.
If sampling interval is too low, frequent switching of
frequencies can lead to high power consumption and if
sampling interval is too high, the clock scaling logic
would take long time to realize that the underlying
hardware (controller and card) is busy and scale up
the clocks.

Signed-off-by: Talel Shenhar 
Signed-off-by: Sayali Lokhande 
---
  .../devicetree/bindings/mmc/sdhci-msm.txt  |  10 +
  drivers/mmc/core/core.c| 560 +
  drivers/mmc/core/core.h|   7 +
  drivers/mmc/core/debugfs.c |  46 ++
  drivers/mmc/core/host.c|   8 +
  drivers/mmc/core/mmc.c | 200 +++-
  drivers/mmc/core/sd.c  |  72 ++-
  drivers/mmc/host/sdhci-msm.c   |  37 ++
  drivers/mmc/host/sdhci-pltfm.c |  11 +
  drivers/mmc/host/sdhci.c   |  27 +
  drivers/mmc/host/sdhci.h   |   8 +
  include/linux/mmc/card.h   |   5 +
  include/linux/mmc/host.h   |  70 +++
  13 files changed, 1059 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 502b3b8..bd8470a 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -26,6 +26,15 @@ Required properties:
"cal" - reference clock for RCLK delay calibration (optional)
"sleep"   - sleep clock for RCLK delay calibration (optional)
  
+Optional Properties:

+- qcom,devfreq,freq-table - specifies supported frequencies for clock scaling.
+   Clock scaling logic shall toggle between 
these frequencies based
+   on card load. In case the defined 
frequencies are over or below
+   the supported card frequencies, they will 
be overridden
+   during card init. In case this entry is not 
supplied,
+   the driver will construct one based on the 
card
+   supported max and min frequencies.
+   The frequencies must be ordered from lowest 
to highest.
  Example:
  
  	sdhc_1: sdhci@f9824900 {

@@ -43,6 +52,7 @@ Example:
  
  		clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;

clock-names = "core", "iface";
+   qcom,devfreq,freq-table = <5200 2>;
};
  
  	sdhc_2: sdhci@f98a4900 {

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 281826d..0eaee42 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -14,6 +14,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -112,6 +113,556 @@ static inline void mmc_should_fail_request(struct 
mmc_host *host,
  
  #endif /* CONFIG_FAIL_MMC_REQUEST */
  
+static bool mmc_is_data_request(struct mmc_request *mmc_request)

+{
+   switch (mmc_request->cmd->opcode) {
+   case MMC_READ_SINGLE_BLOCK:
+   case MMC_READ_MULTIPLE_BLOCK:
+   case MMC_WRITE_BLOCK:
+   case MMC_WRITE_MULTIPLE_BLOCK:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static void mmc_clk_scaling_start_busy(struct mmc_host *host, bool lock_needed)
+{
+   struct mmc_devfeq_clk_scaling *clk_scaling = &host->clk_scaling;
+
+   if (!clk_scaling->enable)
+   return;
+
+   if (lock_needed)
+   spin_lock_bh(&clk_scaling->lock);
+
+   clk_scaling->start_busy = ktime_get();
+   clk_scaling->is_busy_started = true;
+
+   if (lock_needed)
+   spin_unlock_bh(&clk_scaling->lock);
+}
+
+static void mmc_clk_scaling_stop_busy(struct mmc_host *host, bool lock_needed)
+{
+   struct mmc_devfeq_clk_scaling *clk_scaling = &host->clk_scaling;
+
+   if (!clk_scaling->enable)
+   return;
+
+   if (lock_needed)
+   s

Re: [PATCH V1 1/3] mmc: sdhci: Allow platform controlled voltage switching

2018-07-25 Thread Vijay Viswanath

Hi Adrian,


On 7/25/2018 5:23 PM, Adrian Hunter wrote:

On 20/07/18 13:46, Vijay Viswanath wrote:

Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

During setup/cleanup of host, check whether regulator enable/disable
was already done by platform driver.

Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci.c | 21 -
  1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..494a1e2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3472,6 +3472,7 @@ int sdhci_setup_host(struct sdhci_host *host)
unsigned int override_timeout_clk;
u32 max_clk;
int ret;
+   bool enable_vqmmc = false;
  
  	WARN_ON(host == NULL);

if (host == NULL)
@@ -3485,7 +3486,12 @@ int sdhci_setup_host(struct sdhci_host *host)
 * the host can take the appropriate action if regulators are not
 * available.
 */
-   ret = mmc_regulator_get_supply(mmc);
+   if (!mmc->supply.vmmc) {
+   ret = mmc_regulator_get_supply(mmc);
+   enable_vqmmc  = true;
+   } else {
+   ret = 0;
+   }
if (ret)
return ret;


Why not

if (!mmc->supply.vmmc) {
ret = mmc_regulator_get_supply(mmc);
if (ret)
return ret;
enable_vqmmc  = true;
}



looks neater. Will do.

  
@@ -3736,7 +3742,10 @@ int sdhci_setup_host(struct sdhci_host *host)
  
  	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */

if (!IS_ERR(mmc->supply.vqmmc)) {
-   ret = regulator_enable(mmc->supply.vqmmc);
+   if (enable_vqmmc)
+   ret = regulator_enable(mmc->supply.vqmmc);


Please introduce host->vqmmc_enabled = !ret;



Any reason to introduce vqmmc_enabled variable in sdhci_host structure ? 
We can get around with a local variable and using regulator_is_enabled API.



+   else
+   ret = 0;
if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 170,
195))
host->caps1 &= ~(SDHCI_SUPPORT_SDR104 |
@@ -3984,7 +3993,7 @@ int sdhci_setup_host(struct sdhci_host *host)
return 0;
  
  unreg:

-   if (!IS_ERR(mmc->supply.vqmmc))
+   if (!IS_ERR(mmc->supply.vqmmc) && enable_vqmmc)


And just make this

if (host->vqmmc_enabled)


regulator_disable(mmc->supply.vqmmc);
  undma:
if (host->align_buffer)
@@ -4002,7 +4011,8 @@ void sdhci_cleanup_host(struct sdhci_host *host)
  {
struct mmc_host *mmc = host->mmc;
  
-	if (!IS_ERR(mmc->supply.vqmmc))

+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   (regulator_is_enabled(mmc->supply.vqmmc) > 0))


if (host->vqmmc_enabled)


regulator_disable(mmc->supply.vqmmc);
  
  	if (host->align_buffer)

@@ -4135,7 +4145,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
  
  	tasklet_kill(&host->finish_tasklet);
  
-	if (!IS_ERR(mmc->supply.vqmmc))

+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   (regulator_is_enabled(mmc->supply.vqmmc) > 0))


if (host->vqmmc_enabled)


regulator_disable(mmc->supply.vqmmc);
  
  	if (host->align_buffer)




--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Thanks,
Vijay


[PATCH RFC 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm

2018-01-18 Thread Vijay Viswanath
>From the HPG:
In some platform, SDCC controller can be connected to either an eMMC device or
an SD card. 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.

For SD usage the default value of this signal is ???0???, and SD driver changes 
it
to ???1??? as a part of voltage switching sequence.
For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to 
PADs
before starting any activity on the eMMC BUS.

To set this signal, write the following in the
SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register:
HC_IO_PAD_PWR_SWITCH: bit 16
HC_IO_PAD_PWR_SWITCH_EN: bit 15

Krishna Konda (1):
  mmc: sdhci-msm: support voltage pad switching

Vijay Viswanath (1):
  mmc: sdhci-msm: Add support to store supported vdd-io voltages

 drivers/mmc/host/sdhci-msm.c | 76 
 1 file changed, 76 insertions(+)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-01-18 Thread Vijay Viswanath
During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..5c23e92 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "sdhci-pltfm.h"
+#include 
 
 #define CORE_MCI_VERSION   0x50
 #define CORE_VERSION_MAJOR_SHIFT   28
@@ -81,6 +82,9 @@
 #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_CSR_CDC_CTLR_CFG0 0x130
 #define CORE_SW_TRIG_FULL_CALIBBIT(16)
 #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
+   u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1313,6 +1318,35 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
sdhci_msm_check_power_status(host, req_type);
 }
 
+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;
+   int i, count;
+   u32 caps = 0, vdd_uV;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   count = regulator_count_voltages(supply);
+   if (count < 0)
+   return count;
+   for (i = 0; i < count; i++) {
+   vdd_uV = regulator_list_voltage(supply, i);
+   if (vdd_uV <= 0)
+   continue;
+   if (vdd_uV > 270)
+   caps |= CORE_3_0V_SUPPORT;
+   if (vdd_uV < 195)
+   caps |= CORE_1_8V_SUPPORT;
+   }
+   }
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+   __func__, caps);
+
+   return 0;
+}
+
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1530,6 +1564,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
+   ret = sdhci_msm_set_regulator_caps(msm_host);
+   if (ret)
+   dev_err(&pdev->dev, "%s: Failed to set regulator caps: %d\n",
+   __func__, ret);
 
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 2/2] mmc: sdhci-msm: support voltage pad switching

2018-01-18 Thread Vijay Viswanath
From: Krishna Konda 

The PADs for sdhc controller 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 | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5c23e92..f5728a8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -78,6 +78,8 @@
 #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)
@@ -1166,6 +1168,35 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
 
+   /*
+* SDHC has core_mem and hc_mem device memory and these memory
+* addresses do not fall within 1KB region. Hence, any update to
+* core_mem address space would require an mb() to ensure this gets
+* completed before its next update to registers within hc_mem.
+*/
+   mb();
+   /*
+* 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.
+*/
+   if ((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & CORE_3_0V_SUPPORT))
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+   ~CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+   CORE_VENDOR_SPEC);
+   else if ((io_level & REQ_IO_LOW) ||
+   (msm_host->caps_0 & CORE_1_8V_SUPPORT))
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+   CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+   CORE_VENDOR_SPEC);
+   /* Ensure that the IO PAD switches are updated before proceeding */
+   mb();
+
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
@@ -1518,6 +1549,13 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
 
/*
+* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH bit can
+* be used as required later on.
+*/
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+   CORE_IO_PAD_PWR_SWITCH_EN), host->ioaddr +
+   CORE_VENDOR_SPEC);
+   /*
 * Power on reset state may trigger power irq if previous status of
 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
 * interrupt in GIC, any pending power irq interrupt should be
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH V2 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-03-06 Thread Vijay Viswanath

Hi Dough, Jeremy,

On 3/3/2018 4:38 AM, Jeremy McNicoll wrote:

On 2018-03-02 10:23 AM, Doug Anderson wrote:

Hi,

On Sun, Feb 11, 2018 at 10:01 PM, Vijay Viswanath
 wrote:

During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 38 
++

  1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..5c23e92 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -23,6 +23,7 @@
  #include 

  #include "sdhci-pltfm.h"
+#include 


This is a strange sort order for this include file.  Why is it after
the local include?



  #define CORE_MCI_VERSION   0x50
  #define CORE_VERSION_MAJOR_SHIFT   28
@@ -81,6 +82,9 @@
  #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)
+


Is there something magical about 25 and 26?  This is a new caps field,
so I'd have expected 0 and 1.




Yes, these bits are the same corresponding to the capabilities in the 
Capabilities Register (offset 0x40). The bit positions become important 
when capabilities register doesn't show support to some voltages, but we 
can support those voltages. At that time, we will have to fake 
capabilities. The changes for those are currently not yet pushed up.



  #define CORE_CSR_CDC_CTLR_CFG0 0x130
  #define CORE_SW_TRIG_FULL_CALIB    BIT(16)
  #define CORE_HW_AUTOCAL_ENA    BIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
 u32 curr_io_level;
 wait_queue_head_t pwr_irq_wait;
 bool pwr_irq_flag;
+   u32 caps_0;
  };

  static unsigned int msm_get_clock_rate_for_bus_mode(struct 
sdhci_host *host,
@@ -1313,6 +1318,35 @@ static void sdhci_msm_writeb(struct sdhci_host 
*host, u8 val, int reg)

 sdhci_msm_check_power_status(host, req_type);
  }

+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;
+   int i, count;
+   u32 caps = 0, vdd_uV;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   count = regulator_count_voltages(supply);
+   if (count < 0)
+   return count;
+   for (i = 0; i < count; i++) {
+   vdd_uV = regulator_list_voltage(supply, i);
+   if (vdd_uV <= 0)
+   continue;
+   if (vdd_uV > 270)
+   caps |= CORE_3_0V_SUPPORT;
+   if (vdd_uV < 195)
+   caps |= CORE_1_8V_SUPPORT;
+   }


Shouldn't you be using regulator_is_supported_voltage() rather than
open coding?  Also: I've never personally worked on a device where it
was used, but there is definitely a concept floating about of a
voltage level of 1.2V.  Maybe should copy the ranges from
mmc_regulator_set_vqmmc()?




regulator_is_supported_voltage() checks for a range and it also uses 
regulator_list_voltage() internally. regulator_list_voltage() is also an 
exported API for use by drivers AFAIK. Please correct if it is not.



Also: seems like you should have some way to deal with "caps" ending
up w/ no bits set.  IIRC you can have a regulator that can be enabled
/ disabled but doesn't list a voltage, so if someone messed up their
device tree you could end up in this case.  Should you print a
warning?  ...or treat it as if we support "3.0V"?  ...or ?  I guess it
depends on how do you want patch #2 to behave in that case.


Both, initialize it to sane value and print something.  This way at
least you have a good chance of booting and not hard hanging and you
are given a reasonable message indicating what needs to be fixed.

-jeremy





+   }


How should things behave if vqmmc is an error?  In that case is it
important to not set "CORE_IO_PAD_PWR_SWITCH_EN" in patch set #2?
...or should you set "CORE_IO_PAD_PWR_SWITCH_EN" but then make sure
you don't set "CORE_IO_PAD_PWR_SWITCH"?




Thanks for the suggestion. If the regulators exit and doesn't list the 
voltages, then I believe initialization itself will not happen. We will 
not have any available ocr and in sdhci_setup_host it should fail.
But these enhancements can be incorporated. Since this patch is already 
acknowledged, I will incorporate these changes in a subsequent patch.



+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+  

Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching

2018-04-06 Thread Vijay Viswanath



On 3/29/2018 4:23 AM, Doug Anderson wrote:

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_CALIBBIT(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;
}


This looks a big mess of if/else. Does the above implementation have 
better performance compared to having two if/else with bit operations 
inside ? The latter looks much cleaner and faster.


If regulator only supports 3V and we get a io_low from BUS_OFF ( 
REQ_IO_LOW should never come if we don't support 1.8V), it is ok to set 
io pad.



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)) {
+   

Re: [PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map

2018-05-24 Thread Vijay Viswanath



On 5/22/2018 11:39 PM, Evan Green wrote:

Hi Vijay,
On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath 
wrote:


From: Sayali Lokhande 



For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC.
Define a new data structure where we can statically define
the address offsets for the registers in different SDCC versions.



Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
   drivers/mmc/host/sdhci-msm.c | 89



   1 file changed, 89 insertions(+)



diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..2524455 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -137,6 +137,95 @@
   /* Timeout value to avoid infinite waiting for pwr_irq */
   #define MSM_PWR_IRQ_TIMEOUT_MS 5000



+struct sdhci_msm_offset {
+   u32 core_hc_mode;
+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x24c,
+   .core_sdcc_debug_reg = 0x358,
+   .core_dll_config = 0x200,
+   .core_dll_status = 0x208,
+   .core_vendor_spec = 0x20c,
+   .core_vendor_spec_adma_err_addr0 = 0x214,
+   .core_vendor_spec_adma_err_addr1 = 0x218,
+   .core_vendor_spec_func2 = 0x210,
+   .core_vendor_spec_capabilities0 = 0x21c,
+   .core_ddr_200_cfg = 0x224,
+   .core_vendor_spec3 = 0x250,
+   .core_dll_config_2 = 0x254,
+   .core_ddr_config = 0x258,
+   .core_ddr_config_2 = 0x25c,
+};
+
+static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
+   .core_hc_mode = 0x78,
+   .core_mci_data_cnt = 0x30,
+   .core_mci_status = 0x34,
+   .core_mci_fifo_cnt = 0x44,
+   .core_mci_version = 0x050,
+   .core_generics = 0x70,
+   .core_testbus_config = 0x0CC,
+   .core_testbus_sel2_bit = 4,
+   .core_testbus_ena = (1 << 3),
+   .core_testbus_sel2 = (1 << 4),
+   .core_pwrctl_status = 0xDC,
+   .core_pwrctl_mask = 0xE0,
+   .core_pwrctl_clear = 0xE4,
+   .core_pwrctl_ctl = 0xE8,
+   .core_sdcc_debug_reg = 0x124,
+   .core_dll_config = 0x100,
+   .core_dll_status = 0x108,
+   .core_vendor_spec = 0x10C,
+   .core_vendor_spec_adma_err_addr0 = 0x114,
+   .core_vendor_spec_adma_err_addr1 = 0x118,
+   .core_vendor_spec_func2 = 0x110,
+   .core_vendor_spec_capabilities0 = 0x11C,
+   .core_ddr_200_cfg = 0x184,
+   .core_vendor_spec3 = 0x1B0,
+   .core_dll_config_2 = 0x1B4,
+   .core_ddr_config = 0x1B8,
+   .core_ddr_config_2 = 0x1BC,
+};
+


I notice a lot of these are never used in the subsequent patches of this
series. I guess more register definitions are always better than fewer,
it's just a shame that they take up space now. Did you just add everything
that was different between v4 and v5, or how did you come up with this set?

Also, I think lowercase hex letters are preferred.

I verified that the v5 register offsets look good, at least for the
registers I have documentation for.

Yeah, felt it better to include all registers even they are not used 
currently.


Will change to use  lowercase hex letters


-Evan



Re: [PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures

2018-05-24 Thread Vijay Viswanath



On 5/22/2018 11:40 PM, Evan Green wrote:

On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath 
wrote:


In addition to offsets of certain registers changing, the registers in
core_mem have been shifted to HC mem as well. To access these registers,
define msm version specific functions. These functions can be loaded
into the function pointers at the time of probe based on the msm version
detected.



Also defind new data structure to hold version specific Ops and register
addresses.



Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
   drivers/mmc/host/sdhci-msm.c | 112

+++

   1 file changed, 112 insertions(+)



diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2524455..bb2bb59 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -226,6 +226,25 @@ struct sdhci_msm_offset {
  .core_ddr_config_2 = 0x1BC,
   };



+struct sdhci_msm_variant_ops {
+   u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset);


I don't see any uses of msm_readb_relaxed or msm_writeb_relaxed in this
patch or the next one. Are these needed?


They are not used as of now. Kept them since they can have use later. 
Felt it better to define base functions and addresses now itself.





+   u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
+   void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32

offset);

+   void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
+   u32 offset);
+};
+
+/*
+ * From V5, register spaces have changed. Wrap this info in a structure
+ * and choose the data_structure based on version info mentioned in DT.
+ */
+struct sdhci_msm_variant_info {
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
+};
+
+


Remove extra blank line.


   struct sdhci_msm_host {
  struct platform_device *pdev;
  void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -245,8 +264,75 @@ struct sdhci_msm_host {
  wait_queue_head_t pwr_irq_wait;
  bool pwr_irq_flag;
  u32 caps_0;
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
   };



+/*
+ * APIs to read/write to vendor specific registers which were there in

the

+ * core_mem region before MCI was removed.
+ */
+static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readb_relaxed(msm_host->core_mem + offset);
+}
+
+static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readb_relaxed(host->ioaddr + offset);
+}
+
+static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readl_relaxed(msm_host->core_mem + offset);
+}
+
+static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readl_relaxed(host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writeb_relaxed(u8 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writeb_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct

sdhci_host *host,

+   u32 offset)
+{
+   writeb_relaxed(val, host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writel_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct

sdhci_host *host,

You squeaked over 80 characters here. Move the second parameter down with
the third.

-Evan



Thanks for going through the patch thoroughly. Will address the comments.

Thanks,
Vijay


Re: [PATCH V1 3/3] mmc: host: Register changes for sdcc V5

2018-05-24 Thread Vijay Viswanath



On 5/22/2018 11:42 PM, Evan Green wrote:

Hi Vijay. Thanks for this patch.

On Thu, May 17, 2018 at 3:30 AM Vijay Viswanath 
wrote:


From: Sayali Lokhande 



For SDCC version 5.0.0 and higher, new compatible string
"qcom,sdhci-msm-v5" is added.



Based on the msm variant, pick the relevant variant data and
use it for register read/write to msm specific registers.



Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
   .../devicetree/bindings/mmc/sdhci-msm.txt  |   5 +-
   drivers/mmc/host/sdhci-msm.c   | 344

+

   2 files changed, 222 insertions(+), 127 deletions(-)



diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt

b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt

index bfdcdc4..c2b7b2b 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,10 @@ This file documents differences between the core

properties in mmc.txt

   and the properties used by the sdhci-msm driver.



   Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5".
+For SDCC version 5.0.0, MCI registers are removed from

SDCC

+interface and some registers are moved to HC. New

compatible

+string is added to support this change -

"qcom,sdhci-msm-v5".

   - reg: Base address and length of the register in the following order:
  - Host controller register map (required)
  - SD Core register map (required)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb2bb59..408e6b2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -33,16 +33,11 @@
   #define CORE_MCI_GENERICS  0x70
   #define SWITCHABLE_SIGNALING_VOLTAGE   BIT(29)



-#define CORE_HC_MODE   0x78


Remove CORE_MCI_VERSION as well.



Missed it. Will remove


   #define HC_MODE_EN 0x1
   #define CORE_POWER 0x0
   #define CORE_SW_RSTBIT(7)
   #define FF_CLK_SW_RST_DIS  BIT(13)



-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK   0xe0
-#define CORE_PWRCTL_CLEAR  0xe4
-#define CORE_PWRCTL_CTL0xe8
   #define CORE_PWRCTL_BUS_OFFBIT(0)
   #define CORE_PWRCTL_BUS_ON BIT(1)
   #define CORE_PWRCTL_IO_LOW BIT(2)
@@ -63,17 +58,13 @@
   #define CORE_CDR_EXT_ENBIT(19)
   #define CORE_DLL_PDN   BIT(29)
   #define CORE_DLL_RST   BIT(30)
-#define CORE_DLL_CONFIG0x100
   #define CORE_CMD_DAT_TRACK_SEL BIT(0)
-#define CORE_DLL_STATUS0x108



-#define CORE_DLL_CONFIG_2  0x1b4
   #define CORE_DDR_CAL_ENBIT(0)
   #define CORE_FLL_CYCLE_CNT BIT(18)
   #define CORE_DLL_CLOCK_DISABLE BIT(21)



-#define CORE_VENDOR_SPEC   0x10c
-#define CORE_VENDOR_SPEC_POR_VAL   0xa1c
+#define CORE_VENDOR_SPEC_POR_VAL 0xa1c
   #define CORE_CLK_PWRSAVE   BIT(1)
   #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
   #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -111,17 +102,14 @@
   #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
   #define CORE_CDC_SWITCH_RC_EN  BIT(1)



-#define CORE_DDR_200_CFG   0x184
   #define CORE_CDC_T4_DLY_SELBIT(0)
   #define CORE_CMDIN_RCLK_EN BIT(1)
   #define CORE_START_CDC_TRAFFIC BIT(6)
-#define CORE_VENDOR_SPEC3  0x1b0
+
   #define CORE_PWRSAVE_DLL   BIT(3)



-#define CORE_DDR_CONFIG0x1b8
   #define DDR_CONFIG_POR_VAL 0x80040853



-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c



   #define INVALID_TUNING_PHASE   -1
   #define SDHCI_MSM_MIN_CLOCK40
@@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct

sdhci_host *host, u8 poll)

  u32 wait_cnt = 50;
  u8 ck_out_en;
  struct mmc_host *mmc = host->mmc;
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   const struct sdhci_msm_offset *msm_offset =
+   msm_host->offset;


I notice this pattern is pasted all over the place in order to get to the
offsets. Maybe a macro or inlined function would be cleaner to get you to
directly to the sdhci_msm_offset struct from sdhci_host, rather than this
blob of paste soup everywhere. In some places you do seem to use the
intermediate locals, so those cases wouldn't need to use the new helper.



  /* Poll for CK_OUT_EN bit.  max. poll time = 50us */
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);



 

[PATCH V3 1/4] mmc: sdhci-msm: Define new Register address map

2018-06-18 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC.
Define a new data structure where we can statically define
the address offsets for the registers in different SDCC versions.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
Reviewed-by: Evan Green 
Acked-by: Adrian Hunter 
---
 drivers/mmc/host/sdhci-msm.c | 89 
 1 file changed, 89 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..4050c99 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -137,6 +137,95 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+struct sdhci_msm_offset {
+   u32 core_hc_mode;
+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x24c,
+   .core_sdcc_debug_reg = 0x358,
+   .core_dll_config = 0x200,
+   .core_dll_status = 0x208,
+   .core_vendor_spec = 0x20c,
+   .core_vendor_spec_adma_err_addr0 = 0x214,
+   .core_vendor_spec_adma_err_addr1 = 0x218,
+   .core_vendor_spec_func2 = 0x210,
+   .core_vendor_spec_capabilities0 = 0x21c,
+   .core_ddr_200_cfg = 0x224,
+   .core_vendor_spec3 = 0x250,
+   .core_dll_config_2 = 0x254,
+   .core_ddr_config = 0x258,
+   .core_ddr_config_2 = 0x25c,
+};
+
+static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
+   .core_hc_mode = 0x78,
+   .core_mci_data_cnt = 0x30,
+   .core_mci_status = 0x34,
+   .core_mci_fifo_cnt = 0x44,
+   .core_mci_version = 0x050,
+   .core_generics = 0x70,
+   .core_testbus_config = 0x0cc,
+   .core_testbus_sel2_bit = 4,
+   .core_testbus_ena = (1 << 3),
+   .core_testbus_sel2 = (1 << 4),
+   .core_pwrctl_status = 0xdc,
+   .core_pwrctl_mask = 0xe0,
+   .core_pwrctl_clear = 0xe4,
+   .core_pwrctl_ctl = 0xe8,
+   .core_sdcc_debug_reg = 0x124,
+   .core_dll_config = 0x100,
+   .core_dll_status = 0x108,
+   .core_vendor_spec = 0x10c,
+   .core_vendor_spec_adma_err_addr0 = 0x114,
+   .core_vendor_spec_adma_err_addr1 = 0x118,
+   .core_vendor_spec_func2 = 0x110,
+   .core_vendor_spec_capabilities0 = 0x11c,
+   .core_ddr_200_cfg = 0x184,
+   .core_vendor_spec3 = 0x1b0,
+   .core_dll_config_2 = 0x1b4,
+   .core_ddr_config = 0x1b8,
+   .core_ddr_config_2 = 0x1bc,
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 0/4] Changes for SDCC5 version

2018-06-18 Thread Vijay Viswanath
With SDCC5, the MCI register space got removed and the offset/order of
several registers have changed. Based on SDCC version used and the register,
we need to pick the base address and offset.

Depends on patch series: "[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD 
support for sdhci-msm"

Changes since RFC:
Dropped voltage regulator changes in sdhci-msm
Split the "Register changes for sdcc V5" patch
Instead of checking mci removal for deciding which base addr to use,
new function pointers are defined for the 2 variants of sdcc: 
1) MCI present
2) V5 (mci removed)
Instead of string comparing with the compatible string from DT file,
the sdhci_msm_probe will now pick the data associated with the
compatible entry and use it to load variant specific address offsets
and msm variant specific read/write ops.

Changes since V1:
Removed unused msm_reab & msm_writeb APIs
Changed certain register addresses from uppercase to lowercase hex
letters
Removed extra lines and spaces
Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two,
one for Documentation and other for the driver changes.

Changes since V2:
Used lower case for macro function defenitions
Removed unused function pointers for msm_readb & msm_writeb


Sayali Lokhande (3):
  mmc: sdhci-msm: Define new Register address map
  Documentation: sdhci-msm: Add new compatible string for SDCC v5
  mmc: host: Register changes for sdcc V5

Vijay Viswanath (1):
  mmc: sdhci-msm: Add msm version specific ops and data structures

 .../devicetree/bindings/mmc/sdhci-msm.txt  |   7 +-
 drivers/mmc/host/sdhci-msm.c   | 511 -
 2 files changed, 391 insertions(+), 127 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures

2018-06-18 Thread Vijay Viswanath
In addition to offsets of certain registers changing, the registers in
core_mem have been shifted to HC mem as well. To access these
registers, define msm version specific functions. These functions can
be loaded into the function pointers at the time of probe based on
the msm version detected.

Also defind new data structure to hold version specific Ops and
register addresses.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
Reviewed-by: Evan Green 
---
 drivers/mmc/host/sdhci-msm.c | 75 
 1 file changed, 75 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4050c99..3d01bc2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -226,6 +226,22 @@ struct sdhci_msm_offset {
.core_ddr_config_2 = 0x1bc,
 };
 
+struct sdhci_msm_variant_ops {
+   u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
+   void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
+   u32 offset);
+};
+
+/*
+ * From V5, register spaces have changed. Wrap this info in a structure
+ * and choose the data_structure based on version info mentioned in DT.
+ */
+struct sdhci_msm_variant_info {
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -245,8 +261,45 @@ struct sdhci_msm_host {
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
u32 caps_0;
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
 };
 
+/*
+ * APIs to read/write to vendor specific registers which were there in the
+ * core_mem region before MCI was removed.
+ */
+static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readl_relaxed(msm_host->core_mem + offset);
+}
+
+static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readl_relaxed(host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writel_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   writel_relaxed(val, host->ioaddr + offset);
+}
+
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
unsigned int clock)
 {
@@ -1481,6 +1534,28 @@ static void sdhci_msm_set_regulator_caps(struct 
sdhci_msm_host *msm_host)
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
 }
 
+static const struct sdhci_msm_variant_ops mci_var_ops = {
+   .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_ops v5_var_ops = {
+   .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
+   .mci_removed = false,
+   .var_ops = &mci_var_ops,
+   .offset = &sdhci_msm_mci_offset,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
+   .mci_removed = true,
+   .var_ops = &v5_var_ops,
+   .offset = &sdhci_msm_v5_offset,
+};
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5

2018-06-18 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0 and higher, new compatible string
"qcom,sdhci-msm-v5" is added.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
Acked-by: Rob Herring 
---
 Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index bfdcdc4..502b3b8 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,12 @@ This file documents differences between the core properties in 
mmc.txt
 and the properties used by the sdhci-msm driver.
 
 Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain:
+   "qcom,sdhci-msm-v4" for sdcc versions less than 5.0
+   "qcom,sdhci-msm-v5" for sdcc versions >= 5.0
+   For SDCC version 5.0.0, MCI registers are removed from SDCC
+   interface and some registers are moved to HC. New compatible
+   string is added to support this change - "qcom,sdhci-msm-v5".
 - reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 4/4] mmc: host: Register changes for sdcc V5

2018-06-18 Thread Vijay Viswanath
From: Sayali Lokhande 

Add support to use the new compatible string "qcom,sdhci-msm-v5".

Based on the msm variant, pick the relevant variant data and
use it for register read/write to msm specific registers.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
Reviewed-by: Evan Green 
---
 drivers/mmc/host/sdhci-msm.c | 347 +++
 1 file changed, 221 insertions(+), 126 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 3d01bc2..418dbb0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -33,16 +33,11 @@
 #define CORE_MCI_GENERICS  0x70
 #define SWITCHABLE_SIGNALING_VOLTAGE   BIT(29)
 
-#define CORE_HC_MODE   0x78
 #define HC_MODE_EN 0x1
 #define CORE_POWER 0x0
 #define CORE_SW_RSTBIT(7)
 #define FF_CLK_SW_RST_DIS  BIT(13)
 
-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK   0xe0
-#define CORE_PWRCTL_CLEAR  0xe4
-#define CORE_PWRCTL_CTL0xe8
 #define CORE_PWRCTL_BUS_OFFBIT(0)
 #define CORE_PWRCTL_BUS_ON BIT(1)
 #define CORE_PWRCTL_IO_LOW BIT(2)
@@ -63,17 +58,13 @@
 #define CORE_CDR_EXT_ENBIT(19)
 #define CORE_DLL_PDN   BIT(29)
 #define CORE_DLL_RST   BIT(30)
-#define CORE_DLL_CONFIG0x100
 #define CORE_CMD_DAT_TRACK_SEL BIT(0)
-#define CORE_DLL_STATUS0x108
 
-#define CORE_DLL_CONFIG_2  0x1b4
 #define CORE_DDR_CAL_ENBIT(0)
 #define CORE_FLL_CYCLE_CNT BIT(18)
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
-#define CORE_VENDOR_SPEC   0x10c
-#define CORE_VENDOR_SPEC_POR_VAL   0xa1c
+#define CORE_VENDOR_SPEC_POR_VAL 0xa1c
 #define CORE_CLK_PWRSAVE   BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -111,17 +102,14 @@
 #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
 #define CORE_CDC_SWITCH_RC_EN  BIT(1)
 
-#define CORE_DDR_200_CFG   0x184
 #define CORE_CDC_T4_DLY_SELBIT(0)
 #define CORE_CMDIN_RCLK_EN BIT(1)
 #define CORE_START_CDC_TRAFFIC BIT(6)
-#define CORE_VENDOR_SPEC3  0x1b0
+
 #define CORE_PWRSAVE_DLL   BIT(3)
 
-#define CORE_DDR_CONFIG0x1b8
 #define DDR_CONFIG_POR_VAL 0x80040853
 
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
 
 #define INVALID_TUNING_PHASE   -1
 #define SDHCI_MSM_MIN_CLOCK40
@@ -137,6 +125,12 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+#define msm_host_readl(msm_host, host, offset) \
+   msm_host->var_ops->msm_readl_relaxed(host, offset)
+
+#define msm_host_writel(msm_host, val, host, offset) \
+   msm_host->var_ops->msm_writel_relaxed(val, host, offset)
+
 struct sdhci_msm_offset {
u32 core_hc_mode;
u32 core_mci_data_cnt;
@@ -266,6 +260,14 @@ struct sdhci_msm_host {
const struct sdhci_msm_offset *offset;
 };
 
+static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host 
*host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return msm_host->offset;
+}
+
 /*
  * APIs to read/write to vendor specific registers which were there in the
  * core_mem region before MCI was removed.
@@ -347,10 +349,12 @@ static inline int msm_dll_poll_ck_out_en(struct 
sdhci_host *host, u8 poll)
u32 wait_cnt = 50;
u8 ck_out_en;
struct mmc_host *mmc = host->mmc;
+   const struct sdhci_msm_offset *msm_offset =
+   sdhci_priv_msm_offset(host);
 
/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
 
while (ck_out_en != poll) {
if (--wait_cnt == 0) {
@@ -360,8 +364,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host 
*host, u8 poll)
}
udelay(1);
 
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
}
 
return 0;
@@ -377,16 +381,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host 
*host, u8 phase)
unsigned long flags;
u32 config;
struct mmc_host *mmc = host->mmc;
+   const struct sdhci_msm_offset *msm_offset =
+   sdhci_priv_msm_offset(host);
 
if (phase > 0xf)
return -EINVAL;
 
spin

Re: [PATCH v2 4/4] mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr irq

2018-05-30 Thread Vijay Viswanath

Hi Georgi,

Thanks for testing the patch on 8096 and pointing out this issue.
The issue is coming because, when card is removed, the HOST_CONTROL2 
register is retaining the 1.8V Signalling enable bit till SDHCI reset 
happens after a new card is inserted.


Adding the change you suggested can avoid this wait, but I feel a better 
solution is to clear the 1.8V signalling bit when the card is removed. 
When a new card is inserted, we shouldn't be keeping the 1.8V bit set 
until we send cmd11 to the SD card. A new SD card should start with 3V.


One solution is to explicitly clear the HOST_CONTROL2 register when card 
is removed.


Other way is to revert the commit: 
9718f84b85396e090ca42fafa730410d286d61e3 "mmc: sdhci-msm: Do not reset 
the controller if no card in the slot"


The sdhci-msm doesn't require "SDHCI_QUIRK_NO_CARD_NO_RESET". The issue 
which above commit is trying to avoid is fixed by the pwr-irq patches. 
Resetting the controller will clear the HOST_CONTROL2 register and avoid 
this issue.


Can you please try this ? I tested reverting the QUIRK on two platforms: 
db410c(8916) and sdm845. SD card insert/remove worked fine after that 
and I didn't get any "Reset 0x1 never completed" error during card 
insert/remove or shutdown.


Thanks,
Vijay

On 5/29/2018 5:49 PM, Georgi Djakov wrote:

Hello Vijay,

On 09/27/2017 08:34 AM, Vijay Viswanath wrote:

Register writes which change voltage of IO lines or turn the IO bus
on/off require controller to be ready before progressing further. When
the controller is ready, it will generate a power irq which needs to be
handled. The thread which initiated the register write should wait for
power irq to complete. This will be done through the new sdhc msm write
APIs which will check whether the particular write can trigger a power
irq and wait for it with a timeout if it is expected.
The SDHC core power control IRQ gets triggered when -
* There is a state change in power control bit (bit 0)
   of SDHCI_POWER_CONTROL register.
* There is a state change in 1.8V enable bit (bit 3) of
   SDHCI_HOST_CONTROL2 register.
* Bit 1 of SDHCI_SOFTWARE_RESET is set.

Also add support APIs which are used by sdhc msm write APIs to check
if power irq is expected to be generated and wait for the power irq
to come and complete if the irq is expected.

This patch requires CONFIG_MMC_SDHCI_IO_ACCESSORS to be enabled.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 173 ++-
  1 file changed, 171 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c


[..]


+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   bool done = false;
+
+   pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+   mmc_hostname(host->mmc), __func__, req_type,
+   msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+   /*
+* The IRQ for request type IO High/LOW will be generated when -
+* there is a state change in 1.8V enable bit (bit 3) of
+* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+* which indicates 3.3V IO voltage. So, when MMC core layer tries
+* to set it to 3.3V before card detection happens, the
+* IRQ doesn't get triggered as there is no state change in this bit.
+* The driver already handles this case by changing the IO voltage
+* level to high as part of controller power up sequence. Hence, check
+* for host->pwr to handle a case where IO voltage high request is
+* issued even before controller power up.
+*/
+   if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+   pr_debug("%s: do not wait for power IRQ that never comes, req_type: 
%d\n",
+   mmc_hostname(host->mmc), req_type);
+   return;
+   }
+   if ((req_type & msm_host->curr_pwr_state) ||
+   (req_type & msm_host->curr_io_level))
+   done = true;
+   /*
+* This is needed here to handle cases where register writes will
+* not change the 

Re: [PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures

2018-06-14 Thread Vijay Viswanath

Hi Stephen,

On 6/13/2018 5:06 AM, Stephen Boyd wrote:

Quoting Vijay Viswanath (2018-05-29 02:52:39)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4050c99..2a66aa0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -226,6 +226,24 @@ struct sdhci_msm_offset {
 .core_ddr_config_2 = 0x1bc,
  };
  
+struct sdhci_msm_variant_ops {

+   u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset);
+   u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
+   void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset);
+   void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
+   u32 offset);
+};
+
+/*
+ * From V5, register spaces have changed. Wrap this info in a structure
+ * and choose the data_structure based on version info mentioned in DT.
+ */


This is sort of odd. Usually we have a read/write function that swizzles
based on register variants, and that's contained with that function. Now
it's the other way.


+struct sdhci_msm_variant_info {
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
+};
+
  struct sdhci_msm_host {
 struct platform_device *pdev;
 void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -245,8 +263,45 @@ struct sdhci_msm_host {
 wait_queue_head_t pwr_irq_wait;
 bool pwr_irq_flag;
 u32 caps_0;
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
  };
  
+/*

+ * APIs to read/write to vendor specific registers which were there in the
+ * core_mem region before MCI was removed.
+ */
+static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readl_relaxed(msm_host->core_mem + offset);


Is core_mem assigned in the new hardware? Maybe that needs to be
'repurposed' for vendor specific registers on v5 and renamed to
something like msm_host::vendor_base or something like that.



There is no core_mem in the new hardware. We can assign hc_mem address 
to core_mem variable (if SDCC5) and do away with the need of special 
read/write functions, but I feel thats a bad approach and misleading.



+}
+
+static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readl_relaxed(host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writel_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   writel_relaxed(val, host->ioaddr + offset);
+}
+
  static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
 unsigned int clock)
  {
@@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct 
sdhci_msm_host *msm_host)
 pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
  }
  
+static const struct sdhci_msm_variant_ops mci_var_ops = {

+   .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_ops v5_var_ops = {
+   .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
+   .mci_removed = 0,


Please use true and false instead of 0 and 1 when the type is bool.



Will do


+   .var_ops = &mci_var_ops,
+   .offset = &sdhci_msm_mci_offset,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
+   .mci_removed = 1,
+   .var_ops = &v5_var_ops,
+   .offset = &sdhci_msm_v5_offset,
+};

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Re: [PATCH V2 4/4] mmc: host: Register changes for sdcc V5

2018-06-14 Thread Vijay Viswanath




On 6/13/2018 4:55 AM, Stephen Boyd wrote:

Quoting Vijay Viswanath (2018-05-29 02:52:41)

@@ -137,6 +125,12 @@
  /* Timeout value to avoid infinite waiting for pwr_irq */
  #define MSM_PWR_IRQ_TIMEOUT_MS 5000
  
+#define MSM_HOST_READL(msm_host, host, offset) \

+   msm_host->var_ops->msm_readl_relaxed(host, offset)
+
+#define MSM_HOST_WRITEL(msm_host, val, host, offset) \
+   msm_host->var_ops->msm_writel_relaxed(val, host, offset)


Is there a reason these macros are capitalized? We don't have READL and
WRITEL macros in the kernel because function-like macros are typically
lowercase.



will change them to lower case. Didn't notice that...


+
  struct sdhci_msm_offset {
 u32 core_hc_mode;
 u32 core_mci_data_cnt;
@@ -268,6 +262,14 @@ struct sdhci_msm_host {
 const struct sdhci_msm_offset *offset;
  };
  
+const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)


static?



will do


+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return msm_host->offset;
+}
+

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[PATCH V1 1/3] mmc: sdhci-msm: Define new Register address map

2018-05-17 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC.
Define a new data structure where we can statically define
the address offsets for the registers in different SDCC versions.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 89 
 1 file changed, 89 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..2524455 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -137,6 +137,95 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+struct sdhci_msm_offset {
+   u32 core_hc_mode;
+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x24c,
+   .core_sdcc_debug_reg = 0x358,
+   .core_dll_config = 0x200,
+   .core_dll_status = 0x208,
+   .core_vendor_spec = 0x20c,
+   .core_vendor_spec_adma_err_addr0 = 0x214,
+   .core_vendor_spec_adma_err_addr1 = 0x218,
+   .core_vendor_spec_func2 = 0x210,
+   .core_vendor_spec_capabilities0 = 0x21c,
+   .core_ddr_200_cfg = 0x224,
+   .core_vendor_spec3 = 0x250,
+   .core_dll_config_2 = 0x254,
+   .core_ddr_config = 0x258,
+   .core_ddr_config_2 = 0x25c,
+};
+
+static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
+   .core_hc_mode = 0x78,
+   .core_mci_data_cnt = 0x30,
+   .core_mci_status = 0x34,
+   .core_mci_fifo_cnt = 0x44,
+   .core_mci_version = 0x050,
+   .core_generics = 0x70,
+   .core_testbus_config = 0x0CC,
+   .core_testbus_sel2_bit = 4,
+   .core_testbus_ena = (1 << 3),
+   .core_testbus_sel2 = (1 << 4),
+   .core_pwrctl_status = 0xDC,
+   .core_pwrctl_mask = 0xE0,
+   .core_pwrctl_clear = 0xE4,
+   .core_pwrctl_ctl = 0xE8,
+   .core_sdcc_debug_reg = 0x124,
+   .core_dll_config = 0x100,
+   .core_dll_status = 0x108,
+   .core_vendor_spec = 0x10C,
+   .core_vendor_spec_adma_err_addr0 = 0x114,
+   .core_vendor_spec_adma_err_addr1 = 0x118,
+   .core_vendor_spec_func2 = 0x110,
+   .core_vendor_spec_capabilities0 = 0x11C,
+   .core_ddr_200_cfg = 0x184,
+   .core_vendor_spec3 = 0x1B0,
+   .core_dll_config_2 = 0x1B4,
+   .core_ddr_config = 0x1B8,
+   .core_ddr_config_2 = 0x1BC,
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V1 3/3] mmc: host: Register changes for sdcc V5

2018-05-17 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0 and higher, new compatible string
"qcom,sdhci-msm-v5" is added.

Based on the msm variant, pick the relevant variant data and
use it for register read/write to msm specific registers.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 .../devicetree/bindings/mmc/sdhci-msm.txt  |   5 +-
 drivers/mmc/host/sdhci-msm.c   | 344 +
 2 files changed, 222 insertions(+), 127 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index bfdcdc4..c2b7b2b 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,10 @@ This file documents differences between the core properties in 
mmc.txt
 and the properties used by the sdhci-msm driver.
 
 Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5".
+For SDCC version 5.0.0, MCI registers are removed from SDCC
+interface and some registers are moved to HC. New compatible
+string is added to support this change - "qcom,sdhci-msm-v5".
 - reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb2bb59..408e6b2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -33,16 +33,11 @@
 #define CORE_MCI_GENERICS  0x70
 #define SWITCHABLE_SIGNALING_VOLTAGE   BIT(29)
 
-#define CORE_HC_MODE   0x78
 #define HC_MODE_EN 0x1
 #define CORE_POWER 0x0
 #define CORE_SW_RSTBIT(7)
 #define FF_CLK_SW_RST_DIS  BIT(13)
 
-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK   0xe0
-#define CORE_PWRCTL_CLEAR  0xe4
-#define CORE_PWRCTL_CTL0xe8
 #define CORE_PWRCTL_BUS_OFFBIT(0)
 #define CORE_PWRCTL_BUS_ON BIT(1)
 #define CORE_PWRCTL_IO_LOW BIT(2)
@@ -63,17 +58,13 @@
 #define CORE_CDR_EXT_ENBIT(19)
 #define CORE_DLL_PDN   BIT(29)
 #define CORE_DLL_RST   BIT(30)
-#define CORE_DLL_CONFIG0x100
 #define CORE_CMD_DAT_TRACK_SEL BIT(0)
-#define CORE_DLL_STATUS0x108
 
-#define CORE_DLL_CONFIG_2  0x1b4
 #define CORE_DDR_CAL_ENBIT(0)
 #define CORE_FLL_CYCLE_CNT BIT(18)
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
-#define CORE_VENDOR_SPEC   0x10c
-#define CORE_VENDOR_SPEC_POR_VAL   0xa1c
+#define CORE_VENDOR_SPEC_POR_VAL 0xa1c
 #define CORE_CLK_PWRSAVE   BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -111,17 +102,14 @@
 #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
 #define CORE_CDC_SWITCH_RC_EN  BIT(1)
 
-#define CORE_DDR_200_CFG   0x184
 #define CORE_CDC_T4_DLY_SELBIT(0)
 #define CORE_CMDIN_RCLK_EN BIT(1)
 #define CORE_START_CDC_TRAFFIC BIT(6)
-#define CORE_VENDOR_SPEC3  0x1b0
+
 #define CORE_PWRSAVE_DLL   BIT(3)
 
-#define CORE_DDR_CONFIG0x1b8
 #define DDR_CONFIG_POR_VAL 0x80040853
 
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
 
 #define INVALID_TUNING_PHASE   -1
 #define SDHCI_MSM_MIN_CLOCK40
@@ -380,10 +368,14 @@ static inline int msm_dll_poll_ck_out_en(struct 
sdhci_host *host, u8 poll)
u32 wait_cnt = 50;
u8 ck_out_en;
struct mmc_host *mmc = host->mmc;
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   const struct sdhci_msm_offset *msm_offset =
+   msm_host->offset;
 
/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
 
while (ck_out_en != poll) {
if (--wait_cnt == 0) {
@@ -393,8 +385,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host 
*host, u8 poll)
}
udelay(1);
 
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
}
 
return 0;
@@ -410,16 +402,20 @@ static int msm_config_cm_dll_phase(struct sdhci_host 
*host, u8 phase)
unsigned long flags;
u32 config;
struct mmc

[PATCH V1 0/3] Changes for SDCC5 version

2018-05-17 Thread Vijay Viswanath
With SDCC5, the MCI register space got removed and the offset/order of
several registers have changed. Based on SDCC version used and the register,
we need to pick the base address and offset.

Changes since RFC:
Dropped voltage regulator changes in sdhci-msm
Split the "Register changes for sdcc V5" patch
Instead of checking mci removal for deciding which base addr to use,
new function pointers are defined for the 2 variants of sdcc: 
1) MCI present
2) V5 (mci removed)
Instead of string comparing with the compatible string from DT file,
the sdhci_msm_probe will now pick the data associated with the
compatible entry and use it to load variant specific address offsets
and msm variant specific read/write ops. 

Sayali Lokhande (2):
  mmc: sdhci-msm: Define new Register address map
  mmc: host: Register changes for sdcc V5

Vijay Viswanath (1):
  mmc: sdhci-msm: Add msm version specific ops and data structures

 .../devicetree/bindings/mmc/sdhci-msm.txt  |   5 +-
 drivers/mmc/host/sdhci-msm.c   | 545 -
 2 files changed, 423 insertions(+), 127 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V1 2/3] mmc: sdhci-msm: Add msm version specific ops and data structures

2018-05-17 Thread Vijay Viswanath
In addition to offsets of certain registers changing, the registers in
core_mem have been shifted to HC mem as well. To access these registers,
define msm version specific functions. These functions can be loaded
into the function pointers at the time of probe based on the msm version
detected.

Also defind new data structure to hold version specific Ops and register
addresses.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 112 +++
 1 file changed, 112 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2524455..bb2bb59 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -226,6 +226,25 @@ struct sdhci_msm_offset {
.core_ddr_config_2 = 0x1BC,
 };
 
+struct sdhci_msm_variant_ops {
+   u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset);
+   u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
+   void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset);
+   void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
+   u32 offset);
+};
+
+/*
+ * From V5, register spaces have changed. Wrap this info in a structure
+ * and choose the data_structure based on version info mentioned in DT.
+ */
+struct sdhci_msm_variant_info {
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
+};
+
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -245,8 +264,75 @@ struct sdhci_msm_host {
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
u32 caps_0;
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
 };
 
+/*
+ * APIs to read/write to vendor specific registers which were there in the
+ * core_mem region before MCI was removed.
+ */
+static u8 sdhci_msm_mci_variant_readb_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readb_relaxed(msm_host->core_mem + offset);
+}
+
+static u8 sdhci_msm_v5_variant_readb_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readb_relaxed(host->ioaddr + offset);
+}
+
+static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readl_relaxed(msm_host->core_mem + offset);
+}
+
+static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readl_relaxed(host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writeb_relaxed(u8 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writeb_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writeb_relaxed(u8 val, struct sdhci_host 
*host,
+   u32 offset)
+{
+   writeb_relaxed(val, host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writel_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writel_relaxed(u32 val, struct sdhci_host 
*host,
+   u32 offset)
+{
+   writel_relaxed(val, host->ioaddr + offset);
+}
+
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
unsigned int clock)
 {
@@ -1481,6 +1567,32 @@ static void sdhci_msm_set_regulator_caps(struct 
sdhci_msm_host *msm_host)
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
 }
 
+static const struct sdhci_msm_variant_ops mci_var_ops = {
+   .msm_readb_relaxed = sdhci_msm_mci_variant_readb_relaxed,
+   .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
+   .msm_writeb_relaxed = sdhci_msm_mci_variant_writeb_relaxed,
+   .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_ops v5_var_ops = {
+   .msm_readb_relaxed = sdhci_msm_v5_variant_readb_relaxed,
+   .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
+   .msm_writeb_relaxed = sdhci_msm_v5_variant_writeb_relaxed,
+   .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
+};
+
+static const struct sdhci_

Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

2018-07-16 Thread Vijay Viswanath




On 7/10/2018 4:37 PM, Adrian Hunter wrote:

On 21/06/18 15:23, Vijay Viswanath wrote:

Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

Add a quirk, which can be used by drivers of such controllers.

Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci.c | 20 +++-
  drivers/mmc/host/sdhci.h |  2 ++
  2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..f0346d4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, 
unsigned char mode,
  void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 unsigned short vdd)
  {
-   if (IS_ERR(host->mmc->supply.vmmc))
+   if (IS_ERR(host->mmc->supply.vmmc) ||
+   (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


I think you should provide your own ->set_power() instead of this



will do


sdhci_set_power_noreg(host, mode, vdd);
else
sdhci_set_power_reg(host, mode, vdd);
@@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host 
*mmc,
ctrl &= ~SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
  
-		if (!IS_ERR(mmc->supply.vqmmc)) {

+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   !(host->quirks2 &
+   SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {


And your own ->start_signal_voltage_switch()



sdhci_msm_start_signal_voltage_switch() would be an exact copy of 
sdhci_start_signal_voltage_switch(). will incorporate this if not 
using quirk.



ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
pr_warn("%s: Switching to 3.3V signalling voltage 
failed\n",
@@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host 
*mmc,
case MMC_SIGNAL_VOLTAGE_180:
if (!(host->flags & SDHCI_SIGNALING_180))
return -EINVAL;
-   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (!IS_ERR(mmc->supply.vqmmc) &&
+   !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
pr_warn("%s: Switching to 1.8V signalling voltage 
failed\n",
@@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host)
 * the host can take the appropriate action if regulators are not
 * available.
 */
-   ret = mmc_regulator_get_supply(mmc);
+   if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


Since we expect mmc_regulator_get_supply() to have been called, this could be:

if (!mmc->supply.vmmc) {
ret = mmc_regulator_get_supply(mmc);
enable_vqmmc = true;
} else {
ret = 0;
}
>> +  ret = mmc_regulator_get_supply(mmc);

+   else
+   ret = 0;
if (ret)
return ret;
  
@@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host)
  
  	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */

if (!IS_ERR(mmc->supply.vqmmc)) {
-   ret = regulator_enable(mmc->supply.vqmmc);
+   if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


And this could be:

if (enable_vqmmc)
ret = regulator_enable(mmc->supply.vqmmc);
else
ret = 0;
 > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is
only called if regulator_enable() was called.

I missed this. Will cover it.

Also I missed one more place where we are doing regulator_disable. 
During sdhci-msm unbinding, we would end up doing an extra regulator 
disable (thanks Evan for pointing it out) in sdhci_remove_host.


To avoid the quirk( or having any flag), it would require copying the 
code of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and 
creating 2 new functions in sdhci_msm layer which would do the exact 
same as above, with just the regulator parts removed.


This looks messy (considering any future changes to the 2 sdhci API will 
need to be copied to their duplicate sdhci_msm API) and a bit overkill 
to avoid quirk. At the same time, I don't know how useful such a quirk 
would be to other platform drivers.


Please let me know your view/suggestions.



+   ret = regulator_enable(mmc-&g

Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

2018-07-17 Thread Vijay Viswanath




On 7/17/2018 1:00 PM, Adrian Hunter wrote:

On 17/07/18 08:14, Vijay Viswanath wrote:



On 7/10/2018 4:37 PM, Adrian Hunter wrote:

On 21/06/18 15:23, Vijay Viswanath wrote:

Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

Add a quirk, which can be used by drivers of such controllers.

Signed-off-by: Vijay Viswanath 
---
   drivers/mmc/host/sdhci.c | 20 +++-
   drivers/mmc/host/sdhci.h |  2 ++
   2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..f0346d4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host,
unsigned char mode,
   void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
    unsigned short vdd)
   {
-    if (IS_ERR(host->mmc->supply.vmmc))
+    if (IS_ERR(host->mmc->supply.vmmc) ||
+    (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


I think you should provide your own ->set_power() instead of this



will do


   sdhci_set_power_noreg(host, mode, vdd);
   else
   sdhci_set_power_reg(host, mode, vdd);
@@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
   ctrl &= ~SDHCI_CTRL_VDD_180;
   sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
   -    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 &
+    SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {


And your own ->start_signal_voltage_switch()



sdhci_msm_start_signal_voltage_switch() would be an exact copy of
sdhci_start_signal_voltage_switch(). will incorporate this if not using
quirk.


   ret = mmc_regulator_set_vqmmc(mmc, ios);
   if (ret) {
   pr_warn("%s: Switching to 3.3V signalling voltage
failed\n",
@@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
   case MMC_SIGNAL_VOLTAGE_180:
   if (!(host->flags & SDHCI_SIGNALING_180))
   return -EINVAL;
-    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
   ret = mmc_regulator_set_vqmmc(mmc, ios);
   if (ret) {
   pr_warn("%s: Switching to 1.8V signalling voltage
failed\n",
@@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host)
    * the host can take the appropriate action if regulators are not
    * available.
    */
-    ret = mmc_regulator_get_supply(mmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


Since we expect mmc_regulator_get_supply() to have been called, this could
be:

 if (!mmc->supply.vmmc) {
     ret = mmc_regulator_get_supply(mmc);
     enable_vqmmc = true;
 } else {
     ret = 0;
 }

+    ret = mmc_regulator_get_supply(mmc);

+    else
+    ret = 0;
   if (ret)
   return ret;
   @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host)
     /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
   if (!IS_ERR(mmc->supply.vqmmc)) {
-    ret = regulator_enable(mmc->supply.vqmmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


And this could be:

     if (enable_vqmmc)
     ret = regulator_enable(mmc->supply.vqmmc);
     else
     ret = 0;
  > However, you still need to ensure regulator_disable(mmc->supply.vqmmc) is
only called if regulator_enable() was called.

I missed this. Will cover it.

Also I missed one more place where we are doing regulator_disable. During
sdhci-msm unbinding, we would end up doing an extra regulator disable
(thanks Evan for pointing it out) in sdhci_remove_host.

To avoid the quirk( or having any flag), it would require copying the code
of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating


You do not need to duplicate sdhci_remove_host(), just change it so that it
only  disables what was enabled i.e.

if (host->vqmmc_enabled)
regulator_disable(mmc->supply.vqmmc);



Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ?
Just wanted to clarify


2 new functions in sdhci_msm layer which would do the exact same as above,
with just the regulator parts removed.

This looks messy (considering any future changes to the 2 sdhci API will
need to be copied to their duplicate sdhci_msm API) and a bit overkill to
avoid quirk. At the same time, I don't know how useful such a quirk would be
to other platform drivers.

Please let me know your vi

Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

2018-07-17 Thread Vijay Viswanath




On 7/17/2018 2:12 PM, Adrian Hunter wrote:

On 17/07/18 11:40, Vijay Viswanath wrote:



On 7/17/2018 1:00 PM, Adrian Hunter wrote:

On 17/07/18 08:14, Vijay Viswanath wrote:



On 7/10/2018 4:37 PM, Adrian Hunter wrote:

On 21/06/18 15:23, Vijay Viswanath wrote:

Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

Add a quirk, which can be used by drivers of such controllers.

Signed-off-by: Vijay Viswanath 
---
    drivers/mmc/host/sdhci.c | 20 +++-
    drivers/mmc/host/sdhci.h |  2 ++
    2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..f0346d4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host,
unsigned char mode,
    void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
     unsigned short vdd)
    {
-    if (IS_ERR(host->mmc->supply.vmmc))
+    if (IS_ERR(host->mmc->supply.vmmc) ||
+    (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


I think you should provide your own ->set_power() instead of this



will do


    sdhci_set_power_noreg(host, mode, vdd);
    else
    sdhci_set_power_reg(host, mode, vdd);
@@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
    ctrl &= ~SDHCI_CTRL_VDD_180;
    sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
    -    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 &
+    SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {


And your own ->start_signal_voltage_switch()



sdhci_msm_start_signal_voltage_switch() would be an exact copy of
sdhci_start_signal_voltage_switch(). will incorporate this if not using
quirk.


    ret = mmc_regulator_set_vqmmc(mmc, ios);
    if (ret) {
    pr_warn("%s: Switching to 3.3V signalling voltage
failed\n",
@@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
    case MMC_SIGNAL_VOLTAGE_180:
    if (!(host->flags & SDHCI_SIGNALING_180))
    return -EINVAL;
-    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
    ret = mmc_regulator_set_vqmmc(mmc, ios);
    if (ret) {
    pr_warn("%s: Switching to 1.8V signalling voltage
failed\n",
@@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host)
     * the host can take the appropriate action if regulators are not
     * available.
     */
-    ret = mmc_regulator_get_supply(mmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


Since we expect mmc_regulator_get_supply() to have been called, this could
be:

  if (!mmc->supply.vmmc) {
  ret = mmc_regulator_get_supply(mmc);
  enable_vqmmc = true;
  } else {
  ret = 0;
  }

+    ret = mmc_regulator_get_supply(mmc);

+    else
+    ret = 0;
    if (ret)
    return ret;
    @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host)
      /* If vqmmc regulator and no 1.8V signalling, then there's no
UHS */
    if (!IS_ERR(mmc->supply.vqmmc)) {
-    ret = regulator_enable(mmc->supply.vqmmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


And this could be:

  if (enable_vqmmc)
  ret = regulator_enable(mmc->supply.vqmmc);
  else
  ret = 0;
   > However, you still need to ensure
regulator_disable(mmc->supply.vqmmc) is
only called if regulator_enable() was called.

I missed this. Will cover it.

Also I missed one more place where we are doing regulator_disable. During
sdhci-msm unbinding, we would end up doing an extra regulator disable
(thanks Evan for pointing it out) in sdhci_remove_host.

To avoid the quirk( or having any flag), it would require copying the code
of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and creating


You do not need to duplicate sdhci_remove_host(), just change it so that it
only  disables what was enabled i.e.

 if (host->vqmmc_enabled)
     regulator_disable(mmc->supply.vqmmc);



Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ?


Yes



Ok.
Any particular reason why we are avoiding quirk and instead adding a new 
flag ?



Just wanted to clarify


2 new functions in sdhci_msm layer which would do the exact same as above,
with just the regulator parts removed.

This looks messy (considering any future changes to the 2 sdhci API will
need to 

Re: [PATCH RFC 1/2] mmc: sdhci: Allow platform controlled voltage switching

2018-07-17 Thread Vijay Viswanath




On 7/17/2018 3:24 PM, Adrian Hunter wrote:

On 17/07/18 12:45, Vijay Viswanath wrote:



On 7/17/2018 2:12 PM, Adrian Hunter wrote:

On 17/07/18 11:40, Vijay Viswanath wrote:



On 7/17/2018 1:00 PM, Adrian Hunter wrote:

On 17/07/18 08:14, Vijay Viswanath wrote:



On 7/10/2018 4:37 PM, Adrian Hunter wrote:

On 21/06/18 15:23, Vijay Viswanath wrote:

Some controllers can have internal mechanism to inform the SW that it
is ready for voltage switching. For such controllers, changing voltage
before the HW is ready can result in various issues.

Add a quirk, which can be used by drivers of such controllers.

Signed-off-by: Vijay Viswanath 
---
     drivers/mmc/host/sdhci.c | 20 +++-
     drivers/mmc/host/sdhci.h |  2 ++
     2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1c828e0..f0346d4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1615,7 +1615,8 @@ void sdhci_set_power_noreg(struct sdhci_host
*host,
unsigned char mode,
     void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
  unsigned short vdd)
     {
-    if (IS_ERR(host->mmc->supply.vmmc))
+    if (IS_ERR(host->mmc->supply.vmmc) ||
+    (host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


I think you should provide your own ->set_power() instead of this



will do


     sdhci_set_power_noreg(host, mode, vdd);
     else
     sdhci_set_power_reg(host, mode, vdd);
@@ -2009,7 +2010,9 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
     ctrl &= ~SDHCI_CTRL_VDD_180;
     sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
     -    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 &
+    SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {


And your own ->start_signal_voltage_switch()



sdhci_msm_start_signal_voltage_switch() would be an exact copy of
sdhci_start_signal_voltage_switch(). will incorporate this if not
using
quirk.


     ret = mmc_regulator_set_vqmmc(mmc, ios);
     if (ret) {
     pr_warn("%s: Switching to 3.3V signalling voltage
failed\n",
@@ -2032,7 +2035,8 @@ int sdhci_start_signal_voltage_switch(struct
mmc_host *mmc,
     case MMC_SIGNAL_VOLTAGE_180:
     if (!(host->flags & SDHCI_SIGNALING_180))
     return -EINVAL;
-    if (!IS_ERR(mmc->supply.vqmmc)) {
+    if (!IS_ERR(mmc->supply.vqmmc) &&
+    !(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL)) {
     ret = mmc_regulator_set_vqmmc(mmc, ios);
     if (ret) {
     pr_warn("%s: Switching to 1.8V signalling voltage
failed\n",
@@ -3485,7 +3489,10 @@ int sdhci_setup_host(struct sdhci_host *host)
  * the host can take the appropriate action if regulators are
not
  * available.
  */
-    ret = mmc_regulator_get_supply(mmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


Since we expect mmc_regulator_get_supply() to have been called, this
could
be:

   if (!mmc->supply.vmmc) {
   ret = mmc_regulator_get_supply(mmc);
   enable_vqmmc = true;
   } else {
   ret = 0;
   }

+    ret = mmc_regulator_get_supply(mmc);

+    else
+    ret = 0;
     if (ret)
     return ret;
     @@ -3736,7 +3743,10 @@ int sdhci_setup_host(struct sdhci_host *host)
       /* If vqmmc regulator and no 1.8V signalling, then there's no
UHS */
     if (!IS_ERR(mmc->supply.vqmmc)) {
-    ret = regulator_enable(mmc->supply.vqmmc);
+    if (!(host->quirks2 & SDHCI_QUIRK2_INTERNAL_PWR_CTL))


And this could be:

   if (enable_vqmmc)
   ret = regulator_enable(mmc->supply.vqmmc);
   else
   ret = 0;
    > However, you still need to ensure
regulator_disable(mmc->supply.vqmmc) is
only called if regulator_enable() was called.

I missed this. Will cover it.

Also I missed one more place where we are doing regulator_disable. During
sdhci-msm unbinding, we would end up doing an extra regulator disable
(thanks Evan for pointing it out) in sdhci_remove_host.

To avoid the quirk( or having any flag), it would require copying the code
of sdhci_start_signal_voltage_switch() and sdhci_remove_host() and
creating


You do not need to duplicate sdhci_remove_host(), just change it so that it
only  disables what was enabled i.e.

  if (host->vqmmc_enabled)
  regulator_disable(mmc->supply.vqmmc);



Ok, so we will be adding a new flag "vqmmc_enabled" in sdhci_host, ryt ?


Yes



Ok.
Any particular reason why we are avoiding quirk and instead adding a new flag ?


It moves more in the direction of letting drivers do what they want, rather
than trying to mak

[PATCH V3 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-03-28 Thread Vijay Viswanath
During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 36 +++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..a822f10 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sdhci-pltfm.h"
 
@@ -81,6 +82,9 @@
 #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_CSR_CDC_CTLR_CFG0 0x130
 #define CORE_SW_TRIG_FULL_CALIBBIT(16)
 #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
+   u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
int retry = 10;
-   int pwr_state = 0, io_level = 0;
+   u32 pwr_state = 0, io_level = 0;
 
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
@@ -1313,6 +1318,31 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
sdhci_msm_check_power_status(host, req_type);
 }
 
+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;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (regulator_is_supported_voltage(supply, 170, 195))
+   caps |= CORE_1_8V_SUPPORT;
+   if (regulator_is_supported_voltage(supply, 270, 360))
+   caps |= CORE_3_0V_SUPPORT;
+
+   if (!caps)
+   pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n",
+   mmc_hostname(mmc), __func__);
+   }
+
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+   __func__, caps);
+
+   return 0;
+}
+
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1530,6 +1560,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
+   ret = sdhci_msm_set_regulator_caps(msm_host);
+   if (ret)
+   dev_err(&pdev->dev, "Failed to set regulator caps: %d\n",
+   ret);
 
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm

2018-03-28 Thread Vijay Viswanath
>From the HPG:
In some platform, SDCC controller can be connected to either an eMMC device or
an SD card. 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.

For SD usage the default value of this signal is ???0???, and SD driver changes 
it
to ???1??? as a part of voltage switching sequence.
For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to 
PADs
before starting any activity on the eMMC BUS.

To set this signal, write the following in the
SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register:
HC_IO_PAD_PWR_SWITCH: bit 16
HC_IO_PAD_PWR_SWITCH_EN: bit 15

Changes since v1:
Modified comments on io_pad related changes.
Split some read+modify+write commands to multiple lines

Changes since v2:
IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what
voltage is suported by the regulators.
Replaced regulator_list_voltage() API with
regulator_is_supported_voltage().


Krishna Konda (1):
  mmc: sdhci-msm: support voltage pad switching

Vijay Viswanath (1):
  mmc: sdhci-msm: Add support to store supported vdd-io voltages

 drivers/mmc/host/sdhci-msm.c | 99 +++-
 1 file changed, 97 insertions(+), 2 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V3 2/2] mmc: sdhci-msm: support voltage pad switching

2018-03-28 Thread Vijay Viswanath
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 | 65 ++--
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a822f10..2ffb7bb 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_CALIBBIT(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,11 +1169,51 @@ 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();
+   /*
+* 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.
+*/
+   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();
+   } 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)
msm_host->curr_io_level = io_level;
 
+
pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
irq_ack);
@@ -1322,7 +1365,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, 170, 195))
@@ -1335,6 +1379,23

[PATCH V4 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm

2018-03-28 Thread Vijay Viswanath
>From the HPG:
In some platform, SDCC controller can be connected to either an eMMC device or
an SD card. 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.

For SD usage the default value of this signal is ???0???, and SD driver changes 
it
to ???1??? as a part of voltage switching sequence.
For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to 
PADs
before starting any activity on the eMMC BUS.

To set this signal, write the following in the
SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register:
HC_IO_PAD_PWR_SWITCH: bit 16
HC_IO_PAD_PWR_SWITCH_EN: bit 15

Changes since v1:
Modified comments on io_pad related changes.
Split some read+modify+write commands to multiple lines

Changes since v2:
IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what
voltage is supported by the regulators.
Replaced regulator_list_voltage() API with
regulator_is_supported_voltage().

Changes since v3:
Removed unnecessary prints and extra lines.

Krishna Konda (1):
  mmc: sdhci-msm: support voltage pad switching

Vijay Viswanath (1):
  mmc: sdhci-msm: Add support to store supported vdd-io voltages

 drivers/mmc/host/sdhci-msm.c | 99 +++-
 1 file changed, 97 insertions(+), 2 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-03-28 Thread Vijay Viswanath
During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 35 ++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..2fcd9010 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sdhci-pltfm.h"
 
@@ -81,6 +82,9 @@
 #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_CSR_CDC_CTLR_CFG0 0x130
 #define CORE_SW_TRIG_FULL_CALIBBIT(16)
 #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
+   u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
int retry = 10;
-   int pwr_state = 0, io_level = 0;
+   u32 pwr_state = 0, io_level = 0;
 
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
@@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
sdhci_msm_check_power_status(host, req_type);
 }
 
+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;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (regulator_is_supported_voltage(supply, 170, 195))
+   caps |= CORE_1_8V_SUPPORT;
+   if (regulator_is_supported_voltage(supply, 270, 360))
+   caps |= CORE_3_0V_SUPPORT;
+
+   if (!caps)
+   pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n",
+   mmc_hostname(mmc), __func__);
+   }
+
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+   __func__, caps);
+
+   return 0;
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
+   ret = sdhci_msm_set_regulator_caps(msm_host);
+   if (ret)
+   dev_err(&pdev->dev, "Failed to set regulator caps: %d\n",
+   ret);
 
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching

2018-03-28 Thread Vijay Viswanath
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_CALIBBIT(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();
+   /*
+* 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.
+*/
+   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();
+   } 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, 170, 195))
@@ -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 bi

[PATCH RFC 0/4] Changes for SDCC5 version

2018-05-01 Thread Vijay Viswanath
With SDCC5, the MCI register space got removed and the offset/order of
several registers have changed. Based on SDCC version used and the register,
we need to pick the base address and offset.
Also power irq is a signal from controller to SW that it is ready for
voltage switch. So added support to register voltage regulators in the
msm driver and use them. With this core layer will not have to take care of
voltage regulators. Chips which are currently using core layer regulator APIs
can continue to do so, while newer chips can utilize power irq for voltage
switch.

Depends on patch series:
[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm
https://lkml.org/lkml/2018/4/20/370

Asutosh Das (1):
  mmc: sdhci-msm: Add and use voltage regulator related APIs

Sahitya Tummala (2):
  host: sdhci: fix current caps when there is no host->vmmc
  host: sdhci-msm: implement get_current_limit() host op

Sayali Lokhande (1):
  mmc: host: Register changes for sdcc V5

 .../devicetree/bindings/mmc/sdhci-msm.txt  |   32 +-
 drivers/mmc/host/sdhci-msm.c   | 1027 +---
 drivers/mmc/host/sdhci.c   |   11 +-
 drivers/mmc/host/sdhci.h   |1 +
 4 files changed, 912 insertions(+), 159 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 1/4] mmc: host: Register changes for sdcc V5

2018-05-01 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC. This change is
to support MCI register removal for msmfalcon. New compatible
string "qcom,sdhci-msm-v5" is added for msmfalcon to support
this change.

Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781
Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 .../devicetree/bindings/mmc/sdhci-msm.txt  |   5 +-
 drivers/mmc/host/sdhci-msm.c   | 485 +++--
 2 files changed, 365 insertions(+), 125 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index bfdcdc4..c2b7b2b 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,10 @@ This file documents differences between the core properties in 
mmc.txt
 and the properties used by the sdhci-msm driver.
 
 Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5".
+For SDCC version 5.0.0, MCI registers are removed from SDCC
+interface and some registers are moved to HC. New compatible
+string is added to support this change - "qcom,sdhci-msm-v5".
 - reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..d4d432b 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -39,10 +39,6 @@
 #define CORE_SW_RSTBIT(7)
 #define FF_CLK_SW_RST_DIS  BIT(13)
 
-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK   0xe0
-#define CORE_PWRCTL_CLEAR  0xe4
-#define CORE_PWRCTL_CTL0xe8
 #define CORE_PWRCTL_BUS_OFFBIT(0)
 #define CORE_PWRCTL_BUS_ON BIT(1)
 #define CORE_PWRCTL_IO_LOW BIT(2)
@@ -63,17 +59,13 @@
 #define CORE_CDR_EXT_ENBIT(19)
 #define CORE_DLL_PDN   BIT(29)
 #define CORE_DLL_RST   BIT(30)
-#define CORE_DLL_CONFIG0x100
 #define CORE_CMD_DAT_TRACK_SEL BIT(0)
-#define CORE_DLL_STATUS0x108
 
-#define CORE_DLL_CONFIG_2  0x1b4
 #define CORE_DDR_CAL_ENBIT(0)
 #define CORE_FLL_CYCLE_CNT BIT(18)
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
-#define CORE_VENDOR_SPEC   0x10c
-#define CORE_VENDOR_SPEC_POR_VAL   0xa1c
+#define CORE_VENDOR_SPEC_POR_VAL 0xa1c
 #define CORE_CLK_PWRSAVE   BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -111,17 +103,14 @@
 #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
 #define CORE_CDC_SWITCH_RC_EN  BIT(1)
 
-#define CORE_DDR_200_CFG   0x184
 #define CORE_CDC_T4_DLY_SELBIT(0)
 #define CORE_CMDIN_RCLK_EN BIT(1)
 #define CORE_START_CDC_TRAFFIC BIT(6)
-#define CORE_VENDOR_SPEC3  0x1b0
+
 #define CORE_PWRSAVE_DLL   BIT(3)
 
-#define CORE_DDR_CONFIG0x1b8
 #define DDR_CONFIG_POR_VAL 0x80040853
 
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
 
 #define INVALID_TUNING_PHASE   -1
 #define SDHCI_MSM_MIN_CLOCK40
@@ -137,6 +126,93 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+struct sdhci_msm_offset {
+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+struct sdhci_msm_offset sdhci_msm_offset_mci_removed = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x2

[PATCH RFC 3/4] host: sdhci: fix current caps when there is no host->vmmc

2018-05-01 Thread Vijay Viswanath
From: Sahitya Tummala 

When the regulators are not managed by SDHCI host driver (i.e.,
when host->vmmc and host->vmmcq are absent), get the regulator
current capabilities through a new host op get_current_limit().

Signed-off-by: Sahitya Tummala 
Signed-off-by: Sayali Lokhande 
[vvisw...@codeaurora.org: fixed trivial merge conflicts]
Signed-off-by: Vijay Viswanath 

Change-Id: I3370a2411beec1f03cc5f102bf95cd816c60351e
---
 drivers/mmc/host/sdhci.c | 11 ---
 drivers/mmc/host/sdhci.h |  1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0d5fcca..edc2ccd 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3570,10 +3570,15 @@ int sdhci_setup_host(struct sdhci_host *host)
 * value.
 */
max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
-   if (!max_current_caps && !IS_ERR(mmc->supply.vmmc)) {
-   int curr = regulator_get_current_limit(mmc->supply.vmmc);
-   if (curr > 0) {
+   if (!max_current_caps) {
+   u32 curr = 0;
+
+   if (!IS_ERR(mmc->supply.vmmc))
+   curr = regulator_get_current_limit(mmc->supply.vmmc);
+   else if (host->ops->get_current_limit)
+   curr = host->ops->get_current_limit(host);
 
+   if (curr > 0) {
/* convert to SDHCI_MAX_CURRENT format */
curr = curr/1000;  /* convert to mA */
curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 54bc444..a01af78 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -584,6 +584,7 @@ struct sdhci_ops {
void(*adma_workaround)(struct sdhci_host *host, u32 intmask);
void(*card_event)(struct sdhci_host *host);
void(*voltage_switch)(struct sdhci_host *host);
+   unsigned int(*get_current_limit)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 4/4] host: sdhci-msm: implement get_current_limit() host op

2018-05-01 Thread Vijay Viswanath
From: Sahitya Tummala 

This is needed to get the current capabilities of vdd
regulator that is not managed by SDHCI driver.

Change-Id: I927c14b9890f1d672fe8a3e89d0b334f43463b36
Signed-off-by: Sahitya Tummala 
Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 0e0f12d..083b4a5 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2079,6 +2079,18 @@ static void sdhci_msm_set_default_hw_caps(struct device 
*dev,
{},
 };
 
+static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   struct sdhci_msm_reg_data *vdd_data = msm_host->pdata.vdd_data;
+   u32 max_curr = 0;
+
+   if (vdd_data)
+   max_curr = vdd_data->hpm_uA;
+   return max_curr;
+}
+
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
 static const struct sdhci_ops sdhci_msm_ops = {
@@ -2090,6 +2102,7 @@ static void sdhci_msm_set_default_hw_caps(struct device 
*dev,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.write_w = sdhci_msm_writew,
.write_b = sdhci_msm_writeb,
+   .get_current_limit = sdhci_msm_get_current_limit,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs

2018-05-01 Thread Vijay Viswanath
From: Asutosh Das 

Some platforms require that the voltage switching happen only after
the register write occurs and controller is ready for the switch. When
the controller is ready, it will inform through power irq.

Add voltage regulator APIs and use them during power irq to switch
voltage instead of relying on core layer voltage switching.

Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60
Signed-off-by: Asutosh Das 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
 .../devicetree/bindings/mmc/sdhci-msm.txt  |  27 +-
 drivers/mmc/host/sdhci-msm.c   | 537 +++--
 2 files changed, 529 insertions(+), 35 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index c2b7b2b..c454046 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -23,6 +23,22 @@ Required properties:
"xo"- TCXO clock (optional)
"cal"   - reference clock for RCLK delay calibration (optional)
"sleep" - sleep clock for RCLK delay calibration (optional)
+- -supply: phandle to the regulator device tree node if voltage
+   regulators needs to be handled from within sdhci-msm layer.
+   Supported "supply-name" are "vdd" and "vdd-io".
+
+Optional Properties:
+   - qcom,-always-on - specifies whether supply should be kept
+   "on" always.
+   - qcom,-lpm_sup - specifies whether supply can be kept in low
+   power mode (lpm).
+   - qcom,-voltage_level - specifies voltage levels for supply.
+   Should be specified in pairs (min, max), units uV.
+   - qcom,-current_level - specifies load levels for supply in lpm
+   or high power mode (hpm). Should be specified in
+   pairs (lpm, hpm), units uA.
+
+
 
 Example:
 
@@ -33,8 +49,15 @@ Example:
bus-width = <8>;
non-removable;
 
-   vmmc-supply = <&pm8941_l20>;
-   vqmmc-supply = <&pm8941_s3>;
+   vdd-supply = <&pm8941_l20>;
+   qcom,vdd-voltage-level = <295 295>;
+   qcom,vdd-current-level = <9000 80>;
+
+   vdd-io-supply = <&pm8941_s3>;
+   qcom,vdd-io-always-on;
+   qcom,vdd-io-lpm-sup;
+   qcom,vdd-io-voltage-level = <180 295>;
+   qcom,vdd-io-current-level = <6 22000>;
 
pinctrl-names = "default";
pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d4d432b..0e0f12d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = {
.core_ddr_config_2 = 0x1BC,
 };
 
+/* This structure keeps information per regulator */
+struct sdhci_msm_reg_data {
+   /* voltage regulator handle */
+   struct regulator *reg;
+   /* regulator name */
+   const char *name;
+   /* voltage level to be set */
+   u32 low_vol_level;
+   u32 high_vol_level;
+   /* Load values for low power and high power mode */
+   u32 lpm_uA;
+   u32 hpm_uA;
+   /* is this regulator enabled? */
+   bool is_enabled;
+   /* is this regulator needs to be always on? */
+   bool is_always_on;
+   /* is low power mode setting required for this regulator? */
+   bool lpm_sup;
+   bool set_voltage_sup;
+};
+
+struct sdhci_msm_pltfm_data {
+   /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */
+   struct sdhci_msm_reg_data *vdd_data;
+   struct sdhci_msm_reg_data *vdd_io_data;
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -234,6 +261,8 @@ struct sdhci_msm_host {
u32 caps_0;
bool mci_removed;
const struct sdhci_msm_offset *offset;
+   bool pltfm_init_done;
+   struct sdhci_msm_pltfm_data pdata;
 };
 
 /*
@@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct 
sdhci_host *host,
writel_relaxed(val, base_addr + offset);
 }
 
+enum vdd_io_level {
+   /* set vdd_io_data->low_vol_level */
+   VDD_IO_LOW,
+   /* set vdd_io_data->high_vol_level */
+   VDD_IO_HIGH,
+   /*
+* set whatever there in voltage_level (third argument) of
+* sdhci_msm_set_vdd_io_vol() function.
+*/
+   VDD_IO_SET_LEVEL,
+};
+
+#define MAX_PROP_SIZE 32
+static int sdhci_msm_dt_parse_vreg_info(struct device *dev,
+   struct sdhci_msm_reg_data **vreg_data, const char *vreg_name)

[PATCH V2 0/4] Changes for SDCC5 version

2018-05-29 Thread Vijay Viswanath
With SDCC5, the MCI register space got removed and the offset/order of
several registers have changed. Based on SDCC version used and the register,
we need to pick the base address and offset.

Changes since RFC:
Dropped voltage regulator changes in sdhci-msm
Split the "Register changes for sdcc V5" patch
Instead of checking mci removal for deciding which base addr to use,
new function pointers are defined for the 2 variants of sdcc: 
1) MCI present
2) V5 (mci removed)
Instead of string comparing with the compatible string from DT file,
the sdhci_msm_probe will now pick the data associated with the
compatible entry and use it to load variant specific address offsets
and msm variant specific read/write ops.

Changes since V1:
Removed unused msm_reab & msm_writeb APIs
Changed certain register addresses from uppercase to lowercase hex
letters
Removed extra lines and spaces
Split "[PATCH V1 0/3] Changes for SDCC5 version" patch into two,
one for Documentation and other for the driver changes.

Sayali Lokhande (2):
  mmc: sdhci-msm: Define new Register address map
  Documentation: sdhci-msm: Add new compatible string for SDCC v5

Vijay Viswanath (2):
  mmc: sdhci-msm: Add msm version specific ops and data structures
  mmc: host: Register changes for sdcc V5

 .../devicetree/bindings/mmc/sdhci-msm.txt  |   7 +-
 drivers/mmc/host/sdhci-msm.c   | 513 -
 2 files changed, 393 insertions(+), 127 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 1/4] mmc: sdhci-msm: Define new Register address map

2018-05-29 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC.
Define a new data structure where we can statically define
the address offsets for the registers in different SDCC versions.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 89 
 1 file changed, 89 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..4050c99 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -137,6 +137,95 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+struct sdhci_msm_offset {
+   u32 core_hc_mode;
+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+static const struct sdhci_msm_offset sdhci_msm_v5_offset = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x24c,
+   .core_sdcc_debug_reg = 0x358,
+   .core_dll_config = 0x200,
+   .core_dll_status = 0x208,
+   .core_vendor_spec = 0x20c,
+   .core_vendor_spec_adma_err_addr0 = 0x214,
+   .core_vendor_spec_adma_err_addr1 = 0x218,
+   .core_vendor_spec_func2 = 0x210,
+   .core_vendor_spec_capabilities0 = 0x21c,
+   .core_ddr_200_cfg = 0x224,
+   .core_vendor_spec3 = 0x250,
+   .core_dll_config_2 = 0x254,
+   .core_ddr_config = 0x258,
+   .core_ddr_config_2 = 0x25c,
+};
+
+static const struct sdhci_msm_offset sdhci_msm_mci_offset = {
+   .core_hc_mode = 0x78,
+   .core_mci_data_cnt = 0x30,
+   .core_mci_status = 0x34,
+   .core_mci_fifo_cnt = 0x44,
+   .core_mci_version = 0x050,
+   .core_generics = 0x70,
+   .core_testbus_config = 0x0cc,
+   .core_testbus_sel2_bit = 4,
+   .core_testbus_ena = (1 << 3),
+   .core_testbus_sel2 = (1 << 4),
+   .core_pwrctl_status = 0xdc,
+   .core_pwrctl_mask = 0xe0,
+   .core_pwrctl_clear = 0xe4,
+   .core_pwrctl_ctl = 0xe8,
+   .core_sdcc_debug_reg = 0x124,
+   .core_dll_config = 0x100,
+   .core_dll_status = 0x108,
+   .core_vendor_spec = 0x10c,
+   .core_vendor_spec_adma_err_addr0 = 0x114,
+   .core_vendor_spec_adma_err_addr1 = 0x118,
+   .core_vendor_spec_func2 = 0x110,
+   .core_vendor_spec_capabilities0 = 0x11c,
+   .core_ddr_200_cfg = 0x184,
+   .core_vendor_spec3 = 0x1b0,
+   .core_dll_config_2 = 0x1b4,
+   .core_ddr_config = 0x1b8,
+   .core_ddr_config_2 = 0x1bc,
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 2/4] mmc: sdhci-msm: Add msm version specific ops and data structures

2018-05-29 Thread Vijay Viswanath
In addition to offsets of certain registers changing, the registers in
core_mem have been shifted to HC mem as well. To access these
registers, define msm version specific functions. These functions can
be loaded into the function pointers at the time of probe based on
the msm version detected.

Also defind new data structure to hold version specific Ops and
register addresses.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 77 
 1 file changed, 77 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4050c99..2a66aa0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -226,6 +226,24 @@ struct sdhci_msm_offset {
.core_ddr_config_2 = 0x1bc,
 };
 
+struct sdhci_msm_variant_ops {
+   u8 (*msm_readb_relaxed)(struct sdhci_host *host, u32 offset);
+   u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset);
+   void (*msm_writeb_relaxed)(u8 val, struct sdhci_host *host, u32 offset);
+   void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host,
+   u32 offset);
+};
+
+/*
+ * From V5, register spaces have changed. Wrap this info in a structure
+ * and choose the data_structure based on version info mentioned in DT.
+ */
+struct sdhci_msm_variant_info {
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
+};
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -245,8 +263,45 @@ struct sdhci_msm_host {
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
u32 caps_0;
+   bool mci_removed;
+   const struct sdhci_msm_variant_ops *var_ops;
+   const struct sdhci_msm_offset *offset;
 };
 
+/*
+ * APIs to read/write to vendor specific registers which were there in the
+ * core_mem region before MCI was removed.
+ */
+static u32 sdhci_msm_mci_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return readl_relaxed(msm_host->core_mem + offset);
+}
+
+static u32 sdhci_msm_v5_variant_readl_relaxed(struct sdhci_host *host,
+   u32 offset)
+{
+   return readl_relaxed(host->ioaddr + offset);
+}
+
+static void sdhci_msm_mci_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   writel_relaxed(val, msm_host->core_mem + offset);
+}
+
+static void sdhci_msm_v5_variant_writel_relaxed(u32 val,
+   struct sdhci_host *host, u32 offset)
+{
+   writel_relaxed(val, host->ioaddr + offset);
+}
+
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
unsigned int clock)
 {
@@ -1481,6 +1536,28 @@ static void sdhci_msm_set_regulator_caps(struct 
sdhci_msm_host *msm_host)
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
 }
 
+static const struct sdhci_msm_variant_ops mci_var_ops = {
+   .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_ops v5_var_ops = {
+   .msm_readl_relaxed = sdhci_msm_v5_variant_readl_relaxed,
+   .msm_writel_relaxed = sdhci_msm_v5_variant_writel_relaxed,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
+   .mci_removed = 0,
+   .var_ops = &mci_var_ops,
+   .offset = &sdhci_msm_mci_offset,
+};
+
+static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
+   .mci_removed = 1,
+   .var_ops = &v5_var_ops,
+   .offset = &sdhci_msm_v5_offset,
+};
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 3/4] Documentation: sdhci-msm: Add new compatible string for SDCC v5

2018-05-29 Thread Vijay Viswanath
From: Sayali Lokhande 

For SDCC version 5.0.0 and higher, new compatible string
"qcom,sdhci-msm-v5" is added.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index bfdcdc4..502b3b8 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,12 @@ This file documents differences between the core properties in 
mmc.txt
 and the properties used by the sdhci-msm driver.
 
 Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain:
+   "qcom,sdhci-msm-v4" for sdcc versions less than 5.0
+   "qcom,sdhci-msm-v5" for sdcc versions >= 5.0
+   For SDCC version 5.0.0, MCI registers are removed from SDCC
+   interface and some registers are moved to HC. New compatible
+   string is added to support this change - "qcom,sdhci-msm-v5".
 - reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 4/4] mmc: host: Register changes for sdcc V5

2018-05-29 Thread Vijay Viswanath
Add support to use the new compatible string "qcom,sdhci-msm-v5".

Based on the msm variant, pick the relevant variant data and
use it for register read/write to msm specific registers.

Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 347 +++
 1 file changed, 221 insertions(+), 126 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2a66aa0..4d0fd2d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -33,16 +33,11 @@
 #define CORE_MCI_GENERICS  0x70
 #define SWITCHABLE_SIGNALING_VOLTAGE   BIT(29)
 
-#define CORE_HC_MODE   0x78
 #define HC_MODE_EN 0x1
 #define CORE_POWER 0x0
 #define CORE_SW_RSTBIT(7)
 #define FF_CLK_SW_RST_DIS  BIT(13)
 
-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK   0xe0
-#define CORE_PWRCTL_CLEAR  0xe4
-#define CORE_PWRCTL_CTL0xe8
 #define CORE_PWRCTL_BUS_OFFBIT(0)
 #define CORE_PWRCTL_BUS_ON BIT(1)
 #define CORE_PWRCTL_IO_LOW BIT(2)
@@ -63,17 +58,13 @@
 #define CORE_CDR_EXT_ENBIT(19)
 #define CORE_DLL_PDN   BIT(29)
 #define CORE_DLL_RST   BIT(30)
-#define CORE_DLL_CONFIG0x100
 #define CORE_CMD_DAT_TRACK_SEL BIT(0)
-#define CORE_DLL_STATUS0x108
 
-#define CORE_DLL_CONFIG_2  0x1b4
 #define CORE_DDR_CAL_ENBIT(0)
 #define CORE_FLL_CYCLE_CNT BIT(18)
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
-#define CORE_VENDOR_SPEC   0x10c
-#define CORE_VENDOR_SPEC_POR_VAL   0xa1c
+#define CORE_VENDOR_SPEC_POR_VAL 0xa1c
 #define CORE_CLK_PWRSAVE   BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
@@ -111,17 +102,14 @@
 #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0)
 #define CORE_CDC_SWITCH_RC_EN  BIT(1)
 
-#define CORE_DDR_200_CFG   0x184
 #define CORE_CDC_T4_DLY_SELBIT(0)
 #define CORE_CMDIN_RCLK_EN BIT(1)
 #define CORE_START_CDC_TRAFFIC BIT(6)
-#define CORE_VENDOR_SPEC3  0x1b0
+
 #define CORE_PWRSAVE_DLL   BIT(3)
 
-#define CORE_DDR_CONFIG0x1b8
 #define DDR_CONFIG_POR_VAL 0x80040853
 
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
 
 #define INVALID_TUNING_PHASE   -1
 #define SDHCI_MSM_MIN_CLOCK40
@@ -137,6 +125,12 @@
 /* Timeout value to avoid infinite waiting for pwr_irq */
 #define MSM_PWR_IRQ_TIMEOUT_MS 5000
 
+#define MSM_HOST_READL(msm_host, host, offset) \
+   msm_host->var_ops->msm_readl_relaxed(host, offset)
+
+#define MSM_HOST_WRITEL(msm_host, val, host, offset) \
+   msm_host->var_ops->msm_writel_relaxed(val, host, offset)
+
 struct sdhci_msm_offset {
u32 core_hc_mode;
u32 core_mci_data_cnt;
@@ -268,6 +262,14 @@ struct sdhci_msm_host {
const struct sdhci_msm_offset *offset;
 };
 
+const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   return msm_host->offset;
+}
+
 /*
  * APIs to read/write to vendor specific registers which were there in the
  * core_mem region before MCI was removed.
@@ -349,10 +351,12 @@ static inline int msm_dll_poll_ck_out_en(struct 
sdhci_host *host, u8 poll)
u32 wait_cnt = 50;
u8 ck_out_en;
struct mmc_host *mmc = host->mmc;
+   const struct sdhci_msm_offset *msm_offset =
+   sdhci_priv_msm_offset(host);
 
/* Poll for CK_OUT_EN bit.  max. poll time = 50us */
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
 
while (ck_out_en != poll) {
if (--wait_cnt == 0) {
@@ -362,8 +366,8 @@ static inline int msm_dll_poll_ck_out_en(struct sdhci_host 
*host, u8 poll)
}
udelay(1);
 
-   ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
-   CORE_CK_OUT_EN);
+   ck_out_en = !!(readl_relaxed(host->ioaddr +
+   msm_offset->core_dll_config) & CORE_CK_OUT_EN);
}
 
return 0;
@@ -379,16 +383,18 @@ static int msm_config_cm_dll_phase(struct sdhci_host 
*host, u8 phase)
unsigned long flags;
u32 config;
struct mmc_host *mmc = host->mmc;
+   const struct sdhci_msm_offset *msm_offset =
+   sdhci_priv_msm_offset(host);
 
if (phase > 0xf)
return -EINVAL;
 
spin_lock_irqsave(&host->lock, flags);
 
-   config = rea

Re: [PATCH V4 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-04-01 Thread Vijay Viswanath



On 3/29/2018 4:22 AM, Doug Anderson wrote:

Hi,

On Wed, Mar 28, 2018 at 6:08 AM, Vijay Viswanath
 wrote:

During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 35 ++-
  1 file changed, 34 insertions(+), 1 deletion(-)


Since I commented on v2, please copy me for this series going forward.  Thanks.




Will do. Sorry I missed.


diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..2fcd9010 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -21,6 +21,7 @@
  #include 
  #include 
  #include 
+#include 

  #include "sdhci-pltfm.h"

@@ -81,6 +82,9 @@
  #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_CSR_CDC_CTLR_CFG0 0x130
  #define CORE_SW_TRIG_FULL_CALIBBIT(16)
  #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
 u32 curr_io_level;
 wait_queue_head_t pwr_irq_wait;
 bool pwr_irq_flag;
+   u32 caps_0;
  };

  static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
 u32 irq_status, irq_ack = 0;
 int retry = 10;
-   int pwr_state = 0, io_level = 0;
+   u32 pwr_state = 0, io_level = 0;


 irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
@@ -1313,6 +1318,30 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
 sdhci_msm_check_power_status(host, req_type);
  }

+static int sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)


This function always returns 0.  Make it void.



+{
+   struct mmc_host *mmc = msm_host->mmc;
+   struct regulator *supply = mmc->supply.vqmmc;
+   u32 caps = 0;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (regulator_is_supported_voltage(supply, 170, 195))
+   caps |= CORE_1_8V_SUPPORT;
+   if (regulator_is_supported_voltage(supply, 270, 360))
+   caps |= CORE_3_0V_SUPPORT;
+
+   if (!caps)
+   pr_warn("%s: %s: 1.8/3V not supported for vqmmc\n",
+   mmc_hostname(mmc), __func__);


Please remove __func__.  You already have the unique thing to find the
right driver (AKA mmc_hostname(mmc)) and the string itself should be
enough from there.



+   }
+
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+   __func__, caps);


Same, no need for __func__.




will remove all unnecessary __func__ references.


+
+   return 0;
+}
+
  static const struct of_device_id sdhci_msm_dt_match[] = {
 { .compatible = "qcom,sdhci-msm-v4" },
 {},
@@ -1530,6 +1559,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
 ret = sdhci_add_host(host);
 if (ret)
 goto pm_runtime_disable;
+   ret = sdhci_msm_set_regulator_caps(msm_host);
+   if (ret)
+   dev_err(&pdev->dev, "Failed to set regulator caps: %d\n",
+   ret);


If you find some reason _not_ to make sdhci_msm_set_regulator_caps()
return "void" as per above, you should actually do something about
this error.  You've used "dev_err" which makes me feel like you
consider this a serious error.  Presumably it should cause the probe
to fail?
>
-Doug



yeah, we don't need to print anything here as a warning is printed in 
sdhci_msm_set_regulator_caps() anyway.


Re: [PATCH V2 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-03-19 Thread Vijay Viswanath



On 3/7/2018 9:42 PM, Doug Anderson wrote:

Hi,

On Tue, Mar 6, 2018 at 11:13 PM, Vijay Viswanath
 wrote:

Hi Dough, Jeremy,


On 3/3/2018 4:38 AM, Jeremy McNicoll wrote:


On 2018-03-02 10:23 AM, Doug Anderson wrote:


Hi,

On Sun, Feb 11, 2018 at 10:01 PM, Vijay Viswanath
 wrote:


During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
   drivers/mmc/host/sdhci-msm.c | 38
++
   1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..5c23e92 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -23,6 +23,7 @@
   #include 

   #include "sdhci-pltfm.h"
+#include 



This is a strange sort order for this include file.  Why is it after
the local include?



   #define CORE_MCI_VERSION   0x50
   #define CORE_VERSION_MAJOR_SHIFT   28
@@ -81,6 +82,9 @@
   #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)
+



Is there something magical about 25 and 26?  This is a new caps field,
so I'd have expected 0 and 1.




Yes, these bits are the same corresponding to the capabilities in the
Capabilities Register (offset 0x40). The bit positions become important when
capabilities register doesn't show support to some voltages, but we can
support those voltages. At that time, we will have to fake capabilities. The
changes for those are currently not yet pushed up.



   #define CORE_CSR_CDC_CTLR_CFG0 0x130
   #define CORE_SW_TRIG_FULL_CALIBBIT(16)
   #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
  u32 curr_io_level;
  wait_queue_head_t pwr_irq_wait;
  bool pwr_irq_flag;
+   u32 caps_0;
   };

   static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host
*host,
@@ -1313,6 +1318,35 @@ static void sdhci_msm_writeb(struct sdhci_host
*host, u8 val, int reg)
  sdhci_msm_check_power_status(host, req_type);
   }

+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;
+   int i, count;
+   u32 caps = 0, vdd_uV;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   count = regulator_count_voltages(supply);
+   if (count < 0)
+   return count;
+   for (i = 0; i < count; i++) {
+   vdd_uV = regulator_list_voltage(supply, i);
+   if (vdd_uV <= 0)
+   continue;
+   if (vdd_uV > 270)
+   caps |= CORE_3_0V_SUPPORT;
+   if (vdd_uV < 195)
+   caps |= CORE_1_8V_SUPPORT;
+   }



Shouldn't you be using regulator_is_supported_voltage() rather than
open coding?  Also: I've never personally worked on a device where it
was used, but there is definitely a concept floating about of a
voltage level of 1.2V.  Maybe should copy the ranges from
mmc_regulator_set_vqmmc()?




regulator_is_supported_voltage() checks for a range and it also uses
regulator_list_voltage() internally. regulator_list_voltage() is also an
exported API for use by drivers AFAIK. Please correct if it is not.


Sure, regulator_list_voltage() is valid to call.  I'm not saying that
your code is wrong or violates abstractions, just that it's
essentially re-implementing regulator_is_supported_voltage() for very
little gain.  Calling regulator_is_supported_voltage() is better
because:

1. In theory, it should generate less code.  Sure, it might loop twice
with the current implementation of regulator_is_supported_voltage(),
but for a non-time-critical section like this smaller code is likely
better than faster code (decreases kernel size / uses up less cache
space, etc).

2. If regulator_is_supported_voltage() is ever improved to be more
efficient you'll get that improvement automatically.  If someone
happened to source vqmmc from a PWM regulator, for instance, trying to
enumerate all voltages like this would be a disaster.

3. Code will be simpler to understand.

You can replace your whole loop with:

if (regulator_is_supported_voltage(mmc->supply.vqmmc, 170, 195))
   caps |= CORE_1_8V_SUPPORT
if (regulator_is_supported_voltage(mmc->supply.vqmmc, 270, 360))
   caps |= CORE_3_0V_SUPPORT



Also: seems like you should have some way to deal with "caps" ending
up w/ no bits set.  IIRC you can have a regulator that can be enabled
/ disabled but doesn't list a voltage, so if som

Re: [PATCH RFC 1/4] mmc: host: Register changes for sdcc V5

2018-05-03 Thread Vijay Viswanath



On 5/2/2018 1:58 PM, Ulf Hansson wrote:

On 1 May 2018 at 12:39, Vijay Viswanath  wrote:

From: Sayali Lokhande 

For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC. This change is
to support MCI register removal for msmfalcon. New compatible
string "qcom,sdhci-msm-v5" is added for msmfalcon to support
this change.


To simplify review, I would recommend to split this up in a few more
pieces, a few re-factoring while the final change adds the
qcom,sdhci-msm-v5 support.



Will do



Change-Id: I0febfd9bb436a8eff20c20107dd4180c9781
Signed-off-by: Sayali Lokhande 
Signed-off-by: Vijay Viswanath 
---
  .../devicetree/bindings/mmc/sdhci-msm.txt  |   5 +-


Please move DT changes into separate patches and make sure to sent it
to DT maintainers as well.


  drivers/mmc/host/sdhci-msm.c   | 485 +++--
  2 files changed, 365 insertions(+), 125 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index bfdcdc4..c2b7b2b 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -4,7 +4,10 @@ This file documents differences between the core properties in 
mmc.txt
  and the properties used by the sdhci-msm driver.

  Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
+- compatible: Should contain "qcom,sdhci-msm-v4" or "qcom,sdhci-msm-v5".
+For SDCC version 5.0.0, MCI registers are removed from SDCC
+interface and some registers are moved to HC. New compatible
+string is added to support this change - "qcom,sdhci-msm-v5".
  - reg: Base address and length of the register in the following order:
 - Host controller register map (required)
 - SD Core register map (required)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bb11916..d4d432b 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c


[...]



+struct sdhci_msm_offset {


I think a better idea is to create a struct sdhci_msm_variant and make
it contain all the variant specific data. So, not only the offsets,
but other variant data as well.

More comments below.


+   u32 core_mci_data_cnt;
+   u32 core_mci_status;
+   u32 core_mci_fifo_cnt;
+   u32 core_mci_version;
+   u32 core_generics;
+   u32 core_testbus_config;
+   u32 core_testbus_sel2_bit;
+   u32 core_testbus_ena;
+   u32 core_testbus_sel2;
+   u32 core_pwrctl_status;
+   u32 core_pwrctl_mask;
+   u32 core_pwrctl_clear;
+   u32 core_pwrctl_ctl;
+   u32 core_sdcc_debug_reg;
+   u32 core_dll_config;
+   u32 core_dll_status;
+   u32 core_vendor_spec;
+   u32 core_vendor_spec_adma_err_addr0;
+   u32 core_vendor_spec_adma_err_addr1;
+   u32 core_vendor_spec_func2;
+   u32 core_vendor_spec_capabilities0;
+   u32 core_ddr_200_cfg;
+   u32 core_vendor_spec3;
+   u32 core_dll_config_2;
+   u32 core_ddr_config;
+   u32 core_ddr_config_2;
+};
+
+struct sdhci_msm_offset sdhci_msm_offset_mci_removed = {
+   .core_mci_data_cnt = 0x35c,
+   .core_mci_status = 0x324,
+   .core_mci_fifo_cnt = 0x308,
+   .core_mci_version = 0x318,
+   .core_generics = 0x320,
+   .core_testbus_config = 0x32c,
+   .core_testbus_sel2_bit = 3,
+   .core_testbus_ena = (1 << 31),
+   .core_testbus_sel2 = (1 << 3),
+   .core_pwrctl_status = 0x240,
+   .core_pwrctl_mask = 0x244,
+   .core_pwrctl_clear = 0x248,
+   .core_pwrctl_ctl = 0x24c,
+   .core_sdcc_debug_reg = 0x358,
+   .core_dll_config = 0x200,
+   .core_dll_status = 0x208,
+   .core_vendor_spec = 0x20c,
+   .core_vendor_spec_adma_err_addr0 = 0x214,
+   .core_vendor_spec_adma_err_addr1 = 0x218,
+   .core_vendor_spec_func2 = 0x210,
+   .core_vendor_spec_capabilities0 = 0x21c,
+   .core_ddr_200_cfg = 0x224,
+   .core_vendor_spec3 = 0x250,
+   .core_dll_config_2 = 0x254,
+   .core_ddr_config = 0x258,
+   .core_ddr_config_2 = 0x25c,
+};
+
+struct sdhci_msm_offset sdhci_msm_offset_mci_present = {
+   .core_mci_data_cnt = 0x30,
+   .core_mci_status = 0x34,
+   .core_mci_fifo_cnt = 0x44,
+   .core_mci_version = 0x050,
+   .core_generics = 0x70,
+   .core_testbus_config = 0x0CC,
+   .core_testbus_sel2_bit = 4,
+   .core_testbus_ena = (1 << 3),
+   .core_testbus_sel2 = (1 << 4),
+   .core_pwrctl_status = 0xDC,
+   .core_pwrctl_mask = 0xE0,
+   .core_pwrctl_clear = 0xE4,
+   .core_pwrctl_ctl = 0xE8,
+   .core_sdcc_debug_reg = 0x124,
+   .core_dll_config = 0x100,
+   .core_dll_status = 0x108,
+   .core_vendor_spec = 0x10C,
+   .core_vendor_spe

Re: [PATCH RFC 2/4] mmc: sdhci-msm: Add and use voltage regulator related APIs

2018-05-03 Thread Vijay Viswanath



On 5/2/2018 2:19 PM, Ulf Hansson wrote:

On 1 May 2018 at 12:39, Vijay Viswanath  wrote:

From: Asutosh Das 

Some platforms require that the voltage switching happen only after
the register write occurs and controller is ready for the switch. When
the controller is ready, it will inform through power irq.

Add voltage regulator APIs and use them during power irq to switch
voltage instead of relying on core layer voltage switching.


This is way to simplified. 529 lines of new code deserves some more
explanations.



Change-Id: Iaa98686e71a5bfe0092c68e9ffa563b060c5ac60


Remove this.


Signed-off-by: Asutosh Das 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
  .../devicetree/bindings/mmc/sdhci-msm.txt  |  27 +-


Split DT changes and add DT maintainers.



Will do


  drivers/mmc/host/sdhci-msm.c   | 537 +++--
  2 files changed, 529 insertions(+), 35 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt 
b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index c2b7b2b..c454046 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -23,6 +23,22 @@ Required properties:
 "xo"- TCXO clock (optional)
 "cal"   - reference clock for RCLK delay calibration (optional)
 "sleep" - sleep clock for RCLK delay calibration (optional)
+- -supply: phandle to the regulator device tree node if voltage
+   regulators needs to be handled from within sdhci-msm layer.
+   Supported "supply-name" are "vdd" and "vdd-io".
+
+Optional Properties:
+   - qcom,-always-on - specifies whether supply should be kept
+   "on" always.
+   - qcom,-lpm_sup - specifies whether supply can be kept in low
+   power mode (lpm).
+   - qcom,-voltage_level - specifies voltage levels for supply.
+   Should be specified in pairs (min, max), units uV.
+   - qcom,-current_level - specifies load levels for supply in lpm
+   or high power mode (hpm). Should be specified in
+   pairs (lpm, hpm), units uA.
+
+


This looks really weird.

What's so special here that requires you to have your own specific
regulator bindings?



  Example:

@@ -33,8 +49,15 @@ Example:
 bus-width = <8>;
 non-removable;

-   vmmc-supply = <&pm8941_l20>;
-   vqmmc-supply = <&pm8941_s3>;
+   vdd-supply = <&pm8941_l20>;
+   qcom,vdd-voltage-level = <295 295>;
+   qcom,vdd-current-level = <9000 80>;
+
+   vdd-io-supply = <&pm8941_s3>;
+   qcom,vdd-io-always-on;
+   qcom,vdd-io-lpm-sup;
+   qcom,vdd-io-voltage-level = <180 295>;
+   qcom,vdd-io-current-level = <6 22000>;

 pinctrl-names = "default";
 pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d4d432b..0e0f12d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -213,6 +213,33 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = {
 .core_ddr_config_2 = 0x1BC,
  };

+/* This structure keeps information per regulator */
+struct sdhci_msm_reg_data {
+   /* voltage regulator handle */
+   struct regulator *reg;
+   /* regulator name */
+   const char *name;
+   /* voltage level to be set */
+   u32 low_vol_level;
+   u32 high_vol_level;
+   /* Load values for low power and high power mode */
+   u32 lpm_uA;
+   u32 hpm_uA;
+   /* is this regulator enabled? */
+   bool is_enabled;
+   /* is this regulator needs to be always on? */
+   bool is_always_on;
+   /* is low power mode setting required for this regulator? */
+   bool lpm_sup;
+   bool set_voltage_sup;
+};
+
+struct sdhci_msm_pltfm_data {
+   /* Change-Id: Ide3a658ad51a3c3d4a05c47c0e8f013f647c9516 */
+   struct sdhci_msm_reg_data *vdd_data;
+   struct sdhci_msm_reg_data *vdd_io_data;
+};
+
  struct sdhci_msm_host {
 struct platform_device *pdev;
 void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -234,6 +261,8 @@ struct sdhci_msm_host {
 u32 caps_0;
 bool mci_removed;
 const struct sdhci_msm_offset *offset;
+   bool pltfm_init_done;
+   struct sdhci_msm_pltfm_data pdata;
  };

  /*
@@ -298,6 +327,336 @@ void sdhci_msm_vendor_writel_relaxed(u32 val, struct 
sdhci_host *host,
 writel_relaxed(val, base_addr + offset);
  }

+enum vdd_io_level {
+   /* set vdd_io_data->low_vol_level */
+   VDD_IO_LOW,
+   /* set 

[PATCH V5 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm

2018-04-20 Thread Vijay Viswanath
>From the HPG:
In some platform, SDCC controller can be connected to either an eMMC device or
an SD card. 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.

For SD usage the default value of this signal is ???0???, and SD driver changes 
it
to ???1??? as a part of voltage switching sequence.
For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to 
PADs
before starting any activity on the eMMC BUS.

To set this signal, write the following in the
SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register:
HC_IO_PAD_PWR_SWITCH: bit 16
HC_IO_PAD_PWR_SWITCH_EN: bit 15

Changes since v1:
Modified comments on io_pad related changes.
Split some read+modify+write commands to multiple lines

Changes since v2:
IO_PAD_PWR_SWITCH_EN will be set only if we have info regarding what
voltage is supported by the regulators.
Replaced regulator_list_voltage() API with
regulator_is_supported_voltage().

Changes since v3:
Removed unnecessary prints and extra lines.

Changes since v4:
Removed unnecessary mb() within sdhci_msm_handle_pwr_irq() since
wakeup calls have implicit write barriers.

Krishna Konda (1):
  mmc: sdhci-msm: support voltage pad switching

Vijay Viswanath (1):
  mmc: sdhci-msm: Add support to store supported vdd-io voltages

 drivers/mmc/host/sdhci-msm.c | 99 +++-
 1 file changed, 97 insertions(+), 2 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V5 2/2] mmc: sdhci-msm: support voltage pad switching

2018-04-20 Thread Vijay Viswanath
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 
Reviewed-by: Douglas Anderson 
---
 drivers/mmc/host/sdhci-msm.c | 57 ++--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index edd30a2..bb11916 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_CALIBBIT(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,38 @@ 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) {
+   u32 new_config;
+   /*
+* 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.
+*/
+   config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+   new_config = config;
+
+   if ((io_level & REQ_IO_HIGH) &&
+   (msm_host->caps_0 & CORE_3_0V_SUPPORT))
+   new_config &= ~CORE_IO_PAD_PWR_SWITCH;
+   else if ((io_level & REQ_IO_LOW) ||
+   (msm_host->caps_0 & CORE_1_8V_SUPPORT))
+   new_config |= CORE_IO_PAD_PWR_SWITCH;
+
+   if (config ^ new_config)
+   writel_relaxed(new_config,
+   host->ioaddr + CORE_VENDOR_SPEC);
+   }
+
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
@@ -1322,7 +1357,8 @@ static void 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, 170, 195))
@@ -1335,6 +1371,23 @@ static void sdhci_msm_set_regulator_caps(struct 
sdhci_msm_host *msm_host)
mmc_hostname(mmc));
}
 
+   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))
+   config &= ~CORE_IO_PAD_PWR_SWITCH;
+   else if ((io_lev

[PATCH V5 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-04-20 Thread Vijay Viswanath
During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
Reviewed-by: Douglas Anderson 
---
 drivers/mmc/host/sdhci-msm.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..edd30a2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sdhci-pltfm.h"
 
@@ -81,6 +82,9 @@
 #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_CSR_CDC_CTLR_CFG0 0x130
 #define CORE_SW_TRIG_FULL_CALIBBIT(16)
 #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
+   u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1103,7 +1108,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
int retry = 10;
-   int pwr_state = 0, io_level = 0;
+   u32 pwr_state = 0, io_level = 0;
 
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
@@ -1313,6 +1318,27 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
sdhci_msm_check_power_status(host, req_type);
 }
 
+static void 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;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   if (regulator_is_supported_voltage(supply, 170, 195))
+   caps |= CORE_1_8V_SUPPORT;
+   if (regulator_is_supported_voltage(supply, 270, 360))
+   caps |= CORE_3_0V_SUPPORT;
+
+   if (!caps)
+   pr_warn("%s: 1.8/3V not supported for vqmmc\n",
+   mmc_hostname(mmc));
+   }
+
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1530,6 +1556,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
+   sdhci_msm_set_regulator_caps(msm_host);
 
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH V4 2/2] mmc: sdhci-msm: support voltage pad switching

2018-04-18 Thread Vijay Viswanath



On 4/13/2018 10:38 PM, Doug Anderson wrote:

Hi,

On Fri, Apr 6, 2018 at 2:48 AM, Vijay Viswanath  wrote:



On 3/29/2018 4:23 AM, Doug Anderson wrote:


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_CALIBBIT(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;
}



This looks a big mess of if/else. Does the above implementation have better
performance compared to having two if/else with bit operations inside ? The
latter looks much cleaner and faster.

If regulator only supports 3V and we get a io_low from BUS_OFF ( REQ_IO_LOW
should never come if we don't support 1.8V), it is ok to set io pad.


Yeah, I think it's ugly no matter what.  Personally I find the
if/then/else easier to follow than the complicated conditions split
across multiple lines.  I seem to remember there was something that my
version did differently than yours too (hence the "this might be more
important if you get rid of the initial setting"), let's see if I can
figure it out again.

Mine says:
- if it has exactly 1.8 or 3.3 support: set that.
- else if it supports both: set whatev

Re: [PATCH RFC 2/2] mmc: sdhci-msm: support voltage pad switching

2018-02-07 Thread Vijay Viswanath



On 2/3/2018 3:21 AM, Bjorn Andersson wrote:

On Thu 18 Jan 00:05 PST 2018, Vijay Viswanath wrote:


From: Krishna Konda 

The PADs for sdhc controller 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.



I'll try to find some time to check that this doesn't break 8916 and
8974...again...



Thanks! Btwn, I had tested the code in db410c.


Signed-off-by: Krishna Konda 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 38 ++
  1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5c23e92..f5728a8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -78,6 +78,8 @@
  #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)
@@ -1166,6 +1168,35 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
  
+	/*

+* SDHC has core_mem and hc_mem device memory and these memory
+* addresses do not fall within 1KB region. Hence, any update to
+* core_mem address space would require an mb() to ensure this gets
+* completed before its next update to registers within hc_mem.
+*/
+   mb();


If you just use writel() instead of writel_relaxed() you don't need to
sprinkle the driver with comments like this. And you really should be
able to just say "Ensure ordering between core_mem and hc_mem writes" if
you really feel like making it explicit.


+   /*
+* 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.
+*/
+   if ((io_level & REQ_IO_HIGH) && (msm_host->caps_0 & CORE_3_0V_SUPPORT))
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+   ~CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+   CORE_VENDOR_SPEC);


Please split this up in read, modify and write operations.



Will do


+   else if ((io_level & REQ_IO_LOW) ||
+   (msm_host->caps_0 & CORE_1_8V_SUPPORT))
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+   CORE_IO_PAD_PWR_SWITCH), host->ioaddr +
+   CORE_VENDOR_SPEC);
+   /* Ensure that the IO PAD switches are updated before proceeding */


That's not what "mb()" does, it ensures that any writes that was done
before this line will hit the hardware before any writes that is done
after this line.



Will update the comments.


But again, using writel() would save us from doing this explicitly
throughout the code.


+   mb();
+
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
@@ -1518,6 +1549,13 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
  
  	/*

+* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH bit can
+* be used as required later on.
+*/
+   writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+   CORE_IO_PAD_PWR_SWITCH_EN), host->ioaddr +
+   CORE_VENDOR_SPEC);


Please rewrite as 3 operations.

Do we need to set the pwr switch value as well? Or we're fine relying on
the existing value here?


After the IO_PAD_PWR_SWTCH is enabled, we will call 
sdhci_msm_handle_pwr_irq. If there is any pending power irq interrupt, 
that will set the appropriate pwr switch value. Otherwise, an 
appropriate value will get set during REQ_BUS_ON event.




Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[PATCH V2 0/2] mmc: sdhci-msm: Configuring IO_PAD support for sdhci-msm

2018-02-11 Thread Vijay Viswanath
>From the HPG:
In some platform, SDCC controller can be connected to either an eMMC device or
an SD card. 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.

For SD usage the default value of this signal is ???0???, and SD driver changes 
it
to ???1??? as a part of voltage switching sequence.
For eMMC usage, SW should configure this signal to ???1??? and supply 1.8v to 
PADs
before starting any activity on the eMMC BUS.

To set this signal, write the following in the
SDC1_SDCC_HC_VENDOR_SPECIFIC_FUNC register:
HC_IO_PAD_PWR_SWITCH: bit 16
HC_IO_PAD_PWR_SWITCH_EN: bit 15

Changes since v1:
Modified comments on io_pad related changes.
Split some read+modify+write commands to multiple lines

Krishna Konda (1):
  mmc: sdhci-msm: support voltage pad switching

Vijay Viswanath (1):
  mmc: sdhci-msm: Add support to store supported vdd-io voltages

 drivers/mmc/host/sdhci-msm.c | 72 
 1 file changed, 72 insertions(+)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 2/2] mmc: sdhci-msm: support voltage pad switching

2018-02-11 Thread Vijay Viswanath
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 | 34 ++
 1 file changed, 34 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 5c23e92..96c81df 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -78,6 +78,8 @@
 #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)
@@ -1109,6 +,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
u32 irq_status, irq_ack = 0;
int retry = 10;
int pwr_state = 0, io_level = 0;
+   u32 config = 0;
 
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
@@ -1166,6 +1169,30 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host 
*host, int irq)
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
 
+   /* Ensure order between core_mem and hc_mem */
+   mb();
+   /*
+* 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.
+*/
+   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;
+   else if ((io_level & REQ_IO_LOW) ||
+   (msm_host->caps_0 & CORE_1_8V_SUPPORT))
+   config |= CORE_IO_PAD_PWR_SWITCH;
+
+   writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+   /* Ensure IO pad update before any further register read/writes */
+   mb();
+
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
@@ -1518,6 +1545,13 @@ static int sdhci_msm_probe(struct platform_device *pdev)
}
 
/*
+* Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH bit can
+* be used as required later on.
+*/
+   config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+   config |= CORE_IO_PAD_PWR_SWITCH_EN;
+   writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+   /*
 * Power on reset state may trigger power irq if previous status of
 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
 * interrupt in GIC, any pending power irq interrupt should be
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V2 1/2] mmc: sdhci-msm: Add support to store supported vdd-io voltages

2018-02-11 Thread Vijay Viswanath
During probe check whether the vdd-io regulator of sdhc platform device
can support 1.8V and 3V and store this information as a capability of
platform device.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index c283291..5c23e92 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -23,6 +23,7 @@
 #include 
 
 #include "sdhci-pltfm.h"
+#include 
 
 #define CORE_MCI_VERSION   0x50
 #define CORE_VERSION_MAJOR_SHIFT   28
@@ -81,6 +82,9 @@
 #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_CSR_CDC_CTLR_CFG0 0x130
 #define CORE_SW_TRIG_FULL_CALIBBIT(16)
 #define CORE_HW_AUTOCAL_ENABIT(17)
@@ -148,6 +152,7 @@ struct sdhci_msm_host {
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
+   u32 caps_0;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -1313,6 +1318,35 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 
val, int reg)
sdhci_msm_check_power_status(host, req_type);
 }
 
+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;
+   int i, count;
+   u32 caps = 0, vdd_uV;
+
+   if (!IS_ERR(mmc->supply.vqmmc)) {
+   count = regulator_count_voltages(supply);
+   if (count < 0)
+   return count;
+   for (i = 0; i < count; i++) {
+   vdd_uV = regulator_list_voltage(supply, i);
+   if (vdd_uV <= 0)
+   continue;
+   if (vdd_uV > 270)
+   caps |= CORE_3_0V_SUPPORT;
+   if (vdd_uV < 195)
+   caps |= CORE_1_8V_SUPPORT;
+   }
+   }
+   msm_host->caps_0 |= caps;
+   pr_debug("%s: %s: supported caps: 0x%08x\n", mmc_hostname(mmc),
+   __func__, caps);
+
+   return 0;
+}
+
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1530,6 +1564,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
goto pm_runtime_disable;
+   ret = sdhci_msm_set_regulator_caps(msm_host);
+   if (ret)
+   dev_err(&pdev->dev, "%s: Failed to set regulator caps: %d\n",
+   __func__, ret);
 
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH v1 0/5] mmc: sdhci-msm: Corrections to implementation of power irq

2017-09-12 Thread Vijay Viswanath

Hi Adrian, Ulf,

I have addressed the comments on previous patch series. Can you please 
tell how I should proceed from here?


Thanks,
Vijay

On 8/30/2017 6:21 PM, Vijay Viswanath wrote:

Register writes which change voltage of IO lines or turn the IO bus on/off
require sdhc controller to be ready before progressing further. Once a
register write which affects IO lines is done, the driver should wait for
power irq from controller. Once the irq comes, the driver should acknowledge
the irq by writing to power control register. If the acknowledgement is not
given to controller, the controller may not complete the corresponding
register write action and this can mess up the controller if drivers proceeds
without power irq completing.

Changes since RFC:
wait_for_completion_timeout replaced with wait_event_timeout when
waiting for power irq.
Removed the spinlock within power irq handler and API which waits
for power irq.
Added comments to sdhci msm register write functions, warning that they
can sleep.
Sdhci msm register write functions will do a memory barrier before
writing to the register if the particular register can trigger
power irq.
Instead of enabling SDHCI IO ACCESSORS config in arm64/defconfig, it
will be selected in mmc/host/Kconfig if the platform is MMC_SDHCI_MSM.


Sahitya Tummala (2):
   mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset
   mmc: sdhci-msm: Add support to wait for power irq

Subhash Jadavani (1):
   mmc: sdhci-msm: fix issue with power irq

Vijay Viswanath (2):
   mmc: sdhci-msm: Add ops to do sdhc register write
   mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

  drivers/mmc/host/Kconfig |   1 +
  drivers/mmc/host/sdhci-msm.c | 253 ++-
  2 files changed, 249 insertions(+), 5 deletions(-)



[PATCH v1 2/5] mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset

2017-08-30 Thread Vijay Viswanath
From: Sahitya Tummala 

There is a rare scenario in HW, where the first clear pulse could
be lost when the actual reset and clear/read of status register
are happening at the same time. Fix this by retrying upto 10 times
to ensure the status register gets cleared. Otherwise, this will
lead to a spurious power IRQ which results in system instability.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 46 
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d636251..42a65ab 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -995,17 +995,52 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 
0x%08x\n",
+   mmc_hostname(host->mmc),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
 {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
+   int retry = 10;
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK;
 
writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
 
+   /*
+* There is a rare HW scenario where the first clear pulse could be
+* lost when actual reset and clear/read of status register is
+* happening at a time. Hence, retry for at least 10 times to make
+* sure status register is cleared. Otherwise, this will result in
+* a spurious power IRQ resulting in system instability.
+*/
+   while (irq_status & readl_relaxed(msm_host->core_mem +
+   CORE_PWRCTL_STATUS)) {
+   if (retry == 0) {
+   pr_err("%s: Timedout clearing (0x%x) pwrctl status 
register\n",
+   mmc_hostname(host->mmc), irq_status);
+   sdhci_msm_dump_pwr_ctrl_regs(host);
+   WARN_ON(1);
+   break;
+   }
+   writel_relaxed(irq_status,
+   msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   retry--;
+   udelay(10);
+   }
+
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
@@ -1017,13 +1052,17 @@ static void sdhci_msm_voltage_switch(struct sdhci_host 
*host)
 * switches are handled by the sdhci core, so just report success.
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+
+   pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
+   mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
+   irq_ack);
 }
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
struct sdhci_host *host = (struct sdhci_host *)data;
 
-   sdhci_msm_voltage_switch(host);
+   sdhci_msm_handle_pwr_irq(host, irq);
 
return IRQ_HANDLED;
 }
@@ -1106,7 +1145,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-   .voltage_switch = sdhci_msm_voltage_switch,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
@@ -1257,7 +1295,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
 * acknowledged. Otherwise power irq interrupt handler would be
 * fired prematurely.
 */
-   sdhci_msm_voltage_switch(host);
+   sdhci_msm_handle_pwr_irq(host, 0);
 
/*
 * Ensure that above writes are propogated before interrupt enablement
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 5/5] mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

2017-08-30 Thread Vijay Viswanath
Enable CONFIG_MMC_SDHCI_IO_ACCESSORS so that SDHC controller specific
register read and write APIs, if registered, can be used.
---
 drivers/mmc/host/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2db84dd..64a9298 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -420,6 +420,7 @@ config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on MMC_SDHCI_PLTFM
+   select CONFIG_MMC_SDHCI_IO_ACCESSORS
help
  This selects the Secure Digital Host Controller Interface (SDHCI)
  support present in Qualcomm SOCs. The controller supports
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 4/5] mmc: sdhci-msm: Add ops to do sdhc register write

2017-08-30 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus
on/off require controller to be ready before progressing further. When
the controller is ready, it will generate a power irq which needs to be
handled. The thread which initiated the register write should wait for
power irq to complete. This will be done through the new sdhc msm write
APIs which will check whether the particular write can trigger a power
irq and wait for it with a timeout if it is expected.
The SDHC core power control IRQ gets triggered when -
* There is a state change in power control bit (bit 0)
  of SDHCI_POWER_CONTROL register.
* There is a state change in 1.8V enable bit (bit 3) of
  SDHCI_HOST_CONTROL2 register.
* Bit 1 of SDHCI_SOFTWARE_RESET is set.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 69 +++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index e3e385e..a4a78b5 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1070,7 +1070,6 @@ static void sdhci_msm_check_power_status(struct 
sdhci_host *host, u32 req_type)
__WARN_printf("%s: pwr_irq for req: (%d) timed out\n",
mmc_hostname(host->mmc), req_type);
}
-   msm_host->pwr_irq_flag = 0;
pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
__func__, req_type);
 }
@@ -1250,6 +1249,70 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
__sdhci_msm_set_clock(host, clock);
 }
 
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+/*
+ * Platform specific register write functions. This is so that, if any
+ * register write needs to be followed up by platform specific actions,
+ * they can be added here. These functions can go to sleep when writes
+ * to certain registers are done.
+ * These functions are relying on sdhci_set_ios not using spinlock.
+ */
+static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   u32 req_type = 0;
+
+   switch (reg) {
+   case SDHCI_HOST_CONTROL2:
+   req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
+   REQ_IO_HIGH;
+   break;
+   case SDHCI_SOFTWARE_RESET:
+   if (host->pwr && (val & SDHCI_RESET_ALL))
+   req_type = REQ_BUS_OFF;
+   break;
+   case SDHCI_POWER_CONTROL:
+   req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
+   break;
+   }
+
+   if (req_type) {
+   msm_host->pwr_irq_flag = 0;
+   /*
+* Since this register write may trigger a power irq, ensure
+* all previous register writes are complete by this point.
+*/
+   mb();
+   }
+   return req_type;
+}
+
+/* This function may sleep*/
+static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
+{
+   u32 req_type = 0;
+
+   req_type = __sdhci_msm_check_write(host, val, reg);
+   writew_relaxed(val, host->ioaddr + reg);
+
+   if (req_type)
+   sdhci_msm_check_power_status(host, req_type);
+}
+
+/* This function may sleep*/
+static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+   u32 req_type = 0;
+
+   req_type = __sdhci_msm_check_write(host, val, reg);
+
+   writeb_relaxed(val, host->ioaddr + reg);
+
+   if (req_type)
+   sdhci_msm_check_power_status(host, req_type);
+}
+#endif
 static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1264,6 +1327,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   .write_w = sdhci_msm_writew,
+   .write_b = sdhci_msm_writeb,
+#endif
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 3/5] mmc: sdhci-msm: Add support to wait for power irq

2017-08-30 Thread Vijay Viswanath
From: Sahitya Tummala 

Add support API which will check if power irq is expected to be
generated and wait for the power irq to come and complete if the irq is
expected.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 124 ++-
 1 file changed, 122 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 42a65ab..e3e385e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -123,6 +123,10 @@
 #define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
 
 #define MSM_MMC_AUTOSUSPEND_DELAY_MS   50
+
+/* Timeout value to avoid infinite waiting for pwr_irq */
+#define MSM_PWR_IRQ_TIMEOUT_MS 5000
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -138,6 +142,12 @@ struct sdhci_msm_host {
bool calibration_done;
u8 saved_tuning_phase;
bool use_cdclp533;
+   u32 curr_pwr_state;
+   u32 curr_io_level;
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   wait_queue_head_t pwr_irq_wait;
+   bool pwr_irq_flag;
+#endif
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -995,6 +1005,87 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
+{
+   init_waitqueue_head(&msm_host->pwr_irq_wait);
+}
+
+static inline void sdhci_msm_complete_pwr_irq_wait(
+   struct sdhci_msm_host *msm_host)
+{
+   wake_up(&msm_host->pwr_irq_wait);
+}
+
+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   bool done = false;
+
+   pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+   mmc_hostname(host->mmc), __func__, req_type,
+   msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+   /*
+* The IRQ for request type IO High/LOW will be generated when -
+* there is a state change in 1.8V enable bit (bit 3) of
+* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+* which indicates 3.3V IO voltage. So, when MMC core layer tries
+* to set it to 3.3V before card detection happens, the
+* IRQ doesn't get triggered as there is no state change in this bit.
+* The driver already handles this case by changing the IO voltage
+* level to high as part of controller power up sequence. Hence, check
+* for host->pwr to handle a case where IO voltage high request is
+* issued even before controller power up.
+*/
+   if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+   pr_debug("%s: do not wait for power IRQ that never comes, 
req_type: %d\n",
+   mmc_hostname(host->mmc), req_type);
+   return;
+   }
+   if ((req_type & msm_host->curr_pwr_state) ||
+   (req_type & msm_host->curr_io_level))
+   done = true;
+   /*
+* This is needed here to hanlde a case where IRQ gets
+* triggered even before this function is called so that
+* x->done counter of completion gets reset. Otherwise,
+* next call to wait_for_completion returns immediately
+* without actually waiting for the IRQ to be handled.
+*/
+   if (!done) {
+   if (!wait_event_timeout(msm_host->pwr_irq_wait,
+   msm_host->pwr_irq_flag,
+   msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+   __WARN_printf("%s: pwr_irq for req: (%d) timed out\n",
+   mmc_hostname(host->mmc), req_type);
+   }
+   msm_host->pwr_irq_flag = 0;
+   pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
+   __func__, req_type);
+}
+#else
+static inline void sdhci_msm_init_pwr_irq_completion(
+   struct sdhci_msm_host *msm_host)
+{
+}

[PATCH v1 0/5] mmc: sdhci-msm: Corrections to implementation of power irq

2017-08-30 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus on/off
require sdhc controller to be ready before progressing further. Once a
register write which affects IO lines is done, the driver should wait for
power irq from controller. Once the irq comes, the driver should acknowledge
the irq by writing to power control register. If the acknowledgement is not
given to controller, the controller may not complete the corresponding
register write action and this can mess up the controller if drivers proceeds
without power irq completing.

Changes since RFC:
wait_for_completion_timeout replaced with wait_event_timeout when
waiting for power irq.
Removed the spinlock within power irq handler and API which waits
for power irq.
Added comments to sdhci msm register write functions, warning that they
can sleep.
Sdhci msm register write functions will do a memory barrier before
writing to the register if the particular register can trigger
power irq.
Instead of enabling SDHCI IO ACCESSORS config in arm64/defconfig, it
will be selected in mmc/host/Kconfig if the platform is MMC_SDHCI_MSM.


Sahitya Tummala (2):
  mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset
  mmc: sdhci-msm: Add support to wait for power irq

Subhash Jadavani (1):
  mmc: sdhci-msm: fix issue with power irq

Vijay Viswanath (2):
  mmc: sdhci-msm: Add ops to do sdhc register write
  mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

 drivers/mmc/host/Kconfig |   1 +
 drivers/mmc/host/sdhci-msm.c | 253 ++-
 2 files changed, 249 insertions(+), 5 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 1/5] mmc: sdhci-msm: fix issue with power irq

2017-08-30 Thread Vijay Viswanath
From: Subhash Jadavani 

SDCC controller reset (SW_RST) during probe may trigger power irq if
previous status of PWRCTL was either BUS_ON or IO_HIGH_V. So before we
enable the power irq interrupt in GIC (by registering the interrupt
handler), we need to ensure that any pending power irq interrupt status
is acknowledged otherwise power irq interrupt handler would be fired
prematurely.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9d601dc..d636251 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1250,6 +1250,21 @@ static int sdhci_msm_probe(struct platform_device *pdev)
   CORE_VENDOR_SPEC_CAPABILITIES0);
}
 
+   /*
+* Power on reset state may trigger power irq if previous status of
+* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
+* interrupt in GIC, any pending power irq interrupt should be
+* acknowledged. Otherwise power irq interrupt handler would be
+* fired prematurely.
+*/
+   sdhci_msm_voltage_switch(host);
+
+   /*
+* Ensure that above writes are propogated before interrupt enablement
+* in GIC.
+*/
+   mb();
+
/* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -1259,6 +1274,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto clk_disable;
}
 
+   /* Enable pwr irq interrupts */
+   writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
+
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH 1/5] mmc: sdhci-msm: fix issue with power irq

2017-08-28 Thread Vijay Viswanath



On 8/24/2017 1:10 PM, Adrian Hunter wrote:

On 18/08/17 08:19, Vijay Viswanath wrote:

From: Subhash Jadavani 

SDCC controller reset (SW_RST) during probe may trigger power irq if
previous status of PWRCTL was either BUS_ON or IO_HIGH_V. So before we
enable the power irq interrupt in GIC (by registering the interrupt
handler), we need to ensure that any pending power irq interrupt status
is acknowledged otherwise power irq interrupt handler would be fired
prematurely.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 26 ++
  1 file changed, 26 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9d601dc..0957199 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1128,6 +1128,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
u16 host_version, core_minor;
u32 core_version, config;
u8 core_major;
+   u32 irq_status, irq_ctl;
  
  	host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));

if (IS_ERR(host))
@@ -1250,6 +1251,28 @@ static int sdhci_msm_probe(struct platform_device *pdev)
   CORE_VENDOR_SPEC_CAPABILITIES0);
}
  
+	/*

+* Power on reset state may trigger power irq if previous status of
+* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
+* interrupt in GIC, any pending power irq interrupt should be
+* acknowledged. Otherwise power irq interrupt handler would be
+* fired prematurely.
+*/
+
+   irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+   writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL);
+   if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+   irq_ctl |= CORE_PWRCTL_BUS_SUCCESS;
+   if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW))
+   irq_ctl |= CORE_PWRCTL_IO_SUCCESS;
+   writel_relaxed(irq_ctl, msm_host->core_mem + CORE_PWRCTL_CTL);


This looks a lot like sdhci_msm_voltage_switch().  Can clearing the
interrupt be a common function?


This is better. Will change the patches to do it this way.

+   /*
+* Ensure that above writes are propogated before interrupt enablement
+* in GIC.
+*/
+   mb();
+
/* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -1259,6 +1282,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto clk_disable;
}
  
+	/* Enable pwr irq interrupts */

+   writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
+
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);





Re: [PATCH 2/5] mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset

2017-08-28 Thread Vijay Viswanath



On 8/24/2017 1:12 PM, Adrian Hunter wrote:

On 18/08/17 08:19, Vijay Viswanath wrote:

From: Sahitya Tummala 

There is a rare scenario in HW, where the first clear pulse could
be lost when the actual reset and clear/read of status register
are happening at the same time. Fix this by retrying upto 10 times
to ensure the status register gets cleared. Otherwise, this will
lead to a spurious power IRQ which results in system instability.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 43 ---
  1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 0957199..f3e0489 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -995,17 +995,51 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
  }
  
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)

+static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 
0x%08x\n",
+   mmc_hostname(host->mmc),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
  {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
+   int retry = 10;
  
  	irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);

irq_status &= INT_MASK;
  
  	writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
  
+	/*

+* There is a rare HW scenario where the first clear pulse could be
+* lost when actual reset and clear/read of status register is
+* happening at a time. Hence, retry for at least 10 times to make
+* sure status register is cleared. Otherwise, this will result in
+* a spurious power IRQ resulting in system instability.
+*/
+   while (irq_status & readl_relaxed(msm_host->core_mem +
+   CORE_PWRCTL_STATUS)) {
+   if (retry == 0) {
+   pr_err("%s: Timedout clearing (0x%x) pwrctl status 
register\n",
+   mmc_hostname(host->mmc), irq_status);
+   sdhci_msm_dump_pwr_ctrl_regs(host);
+   WARN_ON(1);


Is it your intention to loop forever here?


A bad mistake from my side. Will add break here.

+   }
+   writel_relaxed(irq_status,
+   msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   retry--;
+   udelay(10);
+   }
+
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
@@ -1017,13 +1051,17 @@ static void sdhci_msm_voltage_switch(struct sdhci_host 
*host)
 * switches are handled by the sdhci core, so just report success.
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+
+   pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
+   mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
+   irq_ack);
  }
  
  static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)

  {
struct sdhci_host *host = (struct sdhci_host *)data;
  
-	sdhci_msm_voltage_switch(host);

+   sdhci_msm_handle_pwr_irq(host, irq);
  
  	return IRQ_HANDLED;

  }
@@ -1106,7 +1144,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-   .voltage_switch = sdhci_msm_voltage_switch,
  };
  
  static const struct sdhci_pltfm_data sdhci_msm_pdata = {




--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Re: [PATCH 3/5] mmc: sdhci-msm: Add support to wait for power irq

2017-08-28 Thread Vijay Viswanath



On 8/24/2017 3:35 PM, Adrian Hunter wrote:

On 18/08/17 08:19, Vijay Viswanath wrote:

From: Sahitya Tummala 

Add support API which will check if power irq is expected to be
generated and wait for the power irq to come and complete if the irq is
expected.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 125 ++-
  1 file changed, 123 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index f3e0489..6d3b1fd 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -123,6 +123,10 @@
  #define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT)
  
  #define MSM_MMC_AUTOSUSPEND_DELAY_MS	50

+
+/* Timeout value to avoid infinite waiting for pwr_irq */
+#define MSM_PWR_IRQ_TIMEOUT_MS 5000
+
  struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -138,6 +142,11 @@ struct sdhci_msm_host {
bool calibration_done;
u8 saved_tuning_phase;
bool use_cdclp533;
+   u32 curr_pwr_state;
+   u32 curr_io_level;
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   struct completion pwr_irq_completion;
+#endif
  };
  
  static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,

@@ -995,6 +1004,90 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
  }
  
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS

+static inline void sdhci_msm_init_pwr_irq_completion(
+   struct sdhci_msm_host *msm_host)
+{
+   init_completion(&msm_host->pwr_irq_completion);
+}
+
+static inline void sdhci_msm_complete_pwr_irq_completion(
+   struct sdhci_msm_host *msm_host)
+{
+   complete(&msm_host->pwr_irq_completion);
+}
+
+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   unsigned long flags;
+   bool done = false;
+
+   spin_lock_irqsave(&host->lock, flags);
+   pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+   mmc_hostname(host->mmc), __func__, req_type,
+   msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+   /*
+* The IRQ for request type IO High/LOW will be generated when -
+* there is a state change in 1.8V enable bit (bit 3) of
+* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+* which indicates 3.3V IO voltage. So, when MMC core layer tries
+* to set it to 3.3V before card detection happens, the
+* IRQ doesn't get triggered as there is no state change in this bit.
+* The driver already handles this case by changing the IO voltage
+* level to high as part of controller power up sequence. Hence, check
+* for host->pwr to handle a case where IO voltage high request is
+* issued even before controller power up.
+*/
+   if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+   pr_debug("%s: do not wait for power IRQ that never comes\n",
+   mmc_hostname(host->mmc));
+   spin_unlock_irqrestore(&host->lock, flags);
+   return;
+   }
+   if ((req_type & msm_host->curr_pwr_state) ||
+   (req_type & msm_host->curr_io_level))
+   done = true;
+   spin_unlock_irqrestore(&host->lock, flags);
+   /*
+* This is needed here to hanlde a case where IRQ gets
+* triggered even before this function is called so that
+* x->done counter of completion gets reset. Otherwise,
+* next call to wait_for_completion returns immediately
+* without actually waiting for the IRQ to be handled.
+*/
+   if (done)
+   init_completion(&msm_host->pwr_irq_completion);
+   else if (!wait_for_completion_timeout(&msm_host->pwr_irq_completion,
+   msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))


This all looks a bit more complicated and fragile than it needs to be.  You
are waiting for an event so you really want to be using
wait_event_ti

Re: [PATCH 4/5] mmc: sdhci-msm: Add ops to do sdhc register write

2017-08-28 Thread Vijay Viswanath



On 8/24/2017 3:41 PM, Adrian Hunter wrote:

On 18/08/17 08:19, Vijay Viswanath wrote:

Register writes which change voltage of IO lines or turn the IO bus
on/off require controller to be ready before progressing further. When
the controller is ready, it will generate a power irq which needs to be
handled. The thread which initiated the register write should wait for
power irq to complete. This will be done through the new sdhc msm write
APIs which will check whether the particular write can trigger a power
irq and wait for it with a timeout if it is expected.
The SDHC core power control IRQ gets triggered when -
* There is a state change in power control bit (bit 0)
   of SDHCI_POWER_CONTROL register.
* There is a state change in 1.8V enable bit (bit 3) of
   SDHCI_HOST_CONTROL2 register.
* Bit 1 of SDHCI_SOFTWARE_RESET is set.

Signed-off-by: Vijay Viswanath 
---
  drivers/mmc/host/sdhci-msm.c | 39 +++
  1 file changed, 39 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 6d3b1fd..6571880 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1250,6 +1250,41 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
__sdhci_msm_set_clock(host, clock);
  }
  
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS

+static void __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
+{
+   u32 req_type = 0;
+
+   switch (reg) {
+   case SDHCI_HOST_CONTROL2:
+   req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
+   REQ_IO_HIGH;
+   break;
+   case SDHCI_SOFTWARE_RESET:
+   if (host->pwr && (val & SDHCI_RESET_ALL))
+   req_type = REQ_BUS_OFF;
+   break;
+   case SDHCI_POWER_CONTROL:
+   req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
+   break;
+   }
+
+   if (req_type)


So you are really relying on these register writes not being done in an
atomic context.  Since the spin lock was removed from sdhci_set_ios() that
seems to be true, but it would be good to add a comment here acknowledging
that you are depending on that.



Will add the comments mentioning that this function can sleep and that 
it should not be called from atomic contexts.



+   sdhci_msm_check_power_status(host, req_type);
+}
+
+static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
+{
+   writew_relaxed(val, host->ioaddr + reg);
+   __sdhci_msm_check_write(host, val, reg);
+}
+
+static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+   writeb_relaxed(val, host->ioaddr + reg);
+   __sdhci_msm_check_write(host, val, reg);
+}
+#endif
  static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@@ -1264,6 +1299,10 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+   .write_w = sdhci_msm_writew,
+   .write_b = sdhci_msm_writeb,
+#endif
  };
  
  static const struct sdhci_pltfm_data sdhci_msm_pdata = {




--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Re: [PATCH 5/5] defconfig: msm: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

2017-08-28 Thread Vijay Viswanath



On 8/22/2017 3:08 PM, Ulf Hansson wrote:

On 18 August 2017 at 07:19, Vijay Viswanath  wrote:

Enable CONFIG_MMC_SDHCI_IO_ACCESSORS so that SDHC controller specific
register read and write APIs, if registered, can be used.

Signed-off-by: Vijay Viswanath 
---
  arch/arm64/configs/defconfig | 1 +
  1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 65cdd87..a3c93ed 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -398,6 +398,7 @@ CONFIG_MMC_SDHCI_CADENCE=y
  CONFIG_MMC_SDHCI_TEGRA=y
  CONFIG_MMC_MESON_GX=y
  CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
  CONFIG_MMC_SPI=y
  CONFIG_MMC_SDHI=y
  CONFIG_MMC_DW=y


CONFIG_MMC_SDHCI_IO_ACCESSORS is intended to be selected by those
SDHCI variants that needs it.

May therefore suggest you add a "select line" for MMC_SDHCI_MSM in
drivers/mmc/host/Kconfig:
select CONFIG_MMC_SDHCI_IO_ACCESSORS if ARM64



Will do this way. Thanks!


Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Re: [PATCH v1 5/5] mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

2017-09-18 Thread Vijay Viswanath



On 9/14/2017 12:04 PM, Adrian Hunter wrote:

On 30/08/17 15:51, Vijay Viswanath wrote:

Enable CONFIG_MMC_SDHCI_IO_ACCESSORS so that SDHC controller specific
register read and write APIs, if registered, can be used.


Missing signed-off

Why don't you put this patch earlier in the patch set and then you don't
need all the ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS ?



This will involve merging the current patches 3 & 4 into one (Some 
functions defined under ifdef in patch 3 are used only in patch 4). Will 
that be fine ?



---
  drivers/mmc/host/Kconfig | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2db84dd..64a9298 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -420,6 +420,7 @@ config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on MMC_SDHCI_PLTFM
+   select CONFIG_MMC_SDHCI_IO_ACCESSORS


CONFIG_MMC_SDHCI_IO_ACCESSORS -> MMC_SDHCI_IO_ACCESSORS


help
  This selects the Secure Digital Host Controller Interface (SDHCI)
  support present in Qualcomm SOCs. The controller supports





[PATCH v2 0/4] mmc: sdhci-msm: Corrections to implementation of power irq

2017-09-26 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus on/off
require sdhc controller to be ready before progressing further. Once a
register write which affects IO lines is done, the driver should wait for
power irq from controller. Once the irq comes, the driver should acknowledge
the irq by writing to power control register. If the acknowledgement is not
given to controller, the controller may not complete the corresponding
register write action and this can mess up the controller if drivers proceeds
without power irq completing.

Changes since v1:
Patch enabling MMC_IO_ACCESSORS in Kconfig moved up the patch list.
Also corrected a mistake in the patch.
Removed all ifdef CONFIG_MMC_IO_ACCESSORS since the patches using it
will come after MMC_IO_ACCESSORS are enabled.
Merged the patches 3 & 4 of earlier series into 1 patch (patch 4 in
current series).
Corrected a mistake in a comment text in patch 3 of previous series. 

Changes since RFC:
wait_for_completion_timeout replaced with wait_event_timeout when
waiting for power irq.
Removed the spinlock within power irq handler and API which waits
for power irq.
Added comments to sdhci msm register write functions, warning that they
can sleep.
Sdhci msm register write functions will do a memory barrier before
writing to the register if the particular register can trigger
power irq.
Instead of enabling SDHCI IO ACCESSORS config in arm64/defconfig, it
will be selected in mmc/host/Kconfig if the platform is MMC_SDHCI_MSM.

Sahitya Tummala (1):
  mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset

Subhash Jadavani (1):
  mmc: sdhci-msm: fix issue with power irq

Vijay Viswanath (2):
  mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS
  mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr
irq

 drivers/mmc/host/Kconfig |   1 +
 drivers/mmc/host/sdhci-msm.c | 235 ++-
 2 files changed, 231 insertions(+), 5 deletions(-)

-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v2 4/4] mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr irq

2017-09-26 Thread Vijay Viswanath
Register writes which change voltage of IO lines or turn the IO bus
on/off require controller to be ready before progressing further. When
the controller is ready, it will generate a power irq which needs to be
handled. The thread which initiated the register write should wait for
power irq to complete. This will be done through the new sdhc msm write
APIs which will check whether the particular write can trigger a power
irq and wait for it with a timeout if it is expected.
The SDHC core power control IRQ gets triggered when -
* There is a state change in power control bit (bit 0)
  of SDHCI_POWER_CONTROL register.
* There is a state change in 1.8V enable bit (bit 3) of
  SDHCI_HOST_CONTROL2 register.
* Bit 1 of SDHCI_SOFTWARE_RESET is set.

Also add support APIs which are used by sdhc msm write APIs to check
if power irq is expected to be generated and wait for the power irq
to come and complete if the irq is expected.

This patch requires CONFIG_MMC_SDHCI_IO_ACCESSORS to be enabled.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 173 ++-
 1 file changed, 171 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 42a65ab..b72a487 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -123,6 +123,10 @@
 #define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
 
 #define MSM_MMC_AUTOSUSPEND_DELAY_MS   50
+
+/* Timeout value to avoid infinite waiting for pwr_irq */
+#define MSM_PWR_IRQ_TIMEOUT_MS 5000
+
 struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -138,6 +142,10 @@ struct sdhci_msm_host {
bool calibration_done;
u8 saved_tuning_phase;
bool use_cdclp533;
+   u32 curr_pwr_state;
+   u32 curr_io_level;
+   wait_queue_head_t pwr_irq_wait;
+   bool pwr_irq_flag;
 };
 
 static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
@@ -995,6 +1003,73 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
+static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
+{
+   init_waitqueue_head(&msm_host->pwr_irq_wait);
+}
+
+static inline void sdhci_msm_complete_pwr_irq_wait(
+   struct sdhci_msm_host *msm_host)
+{
+   wake_up(&msm_host->pwr_irq_wait);
+}
+
+/*
+ * sdhci_msm_check_power_status API should be called when registers writes
+ * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
+ * To what state the register writes will change the IO lines should be passed
+ * as the argument req_type. This API will check whether the IO line's state
+ * is already the expected state and will wait for power irq only if
+ * power irq is expected to be trigerred based on the current IO line state
+ * and expected IO line state.
+ */
+static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+   bool done = false;
+
+   pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
+   mmc_hostname(host->mmc), __func__, req_type,
+   msm_host->curr_pwr_state, msm_host->curr_io_level);
+
+   /*
+* The IRQ for request type IO High/LOW will be generated when -
+* there is a state change in 1.8V enable bit (bit 3) of
+* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
+* which indicates 3.3V IO voltage. So, when MMC core layer tries
+* to set it to 3.3V before card detection happens, the
+* IRQ doesn't get triggered as there is no state change in this bit.
+* The driver already handles this case by changing the IO voltage
+* level to high as part of controller power up sequence. Hence, check
+* for host->pwr to handle a case where IO voltage high request is
+* issued even before controller power up.
+*/
+   if ((req_type & REQ_IO_HIGH) && !host->pwr) {
+   pr_debug("%s: do not wait for power IRQ that never comes, 
req_type: %d\n",
+   mmc_hostname(host->mmc), req_type);
+   return;
+   }
+   if ((req_type & msm_host->curr_pwr_state) ||
+   (req_type & msm_host->curr_io_level))
+   done = true;
+   /*
+* This is needed here to handle cases where register writes will
+* not change the current bus state or io level of the controller.
+* In this case, no power irq will be triggerred and we should
+* not wait.
+*/
+   if (!done) {
+  

[PATCH v2 3/4] mmc: Kconfig: Enable CONFIG_MMC_SDHCI_IO_ACCESSORS

2017-09-26 Thread Vijay Viswanath
Enable CONFIG_MMC_SDHCI_IO_ACCESSORS so that SDHC controller specific
register read and write APIs, if registered, can be used.

Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2db84dd..11bfb82 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -420,6 +420,7 @@ config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on MMC_SDHCI_PLTFM
+   select MMC_SDHCI_IO_ACCESSORS
help
  This selects the Secure Digital Host Controller Interface (SDHCI)
  support present in Qualcomm SOCs. The controller supports
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v2 1/4] mmc: sdhci-msm: fix issue with power irq

2017-09-26 Thread Vijay Viswanath
From: Subhash Jadavani 

SDCC controller reset (SW_RST) during probe may trigger power irq if
previous status of PWRCTL was either BUS_ON or IO_HIGH_V. So before we
enable the power irq interrupt in GIC (by registering the interrupt
handler), we need to ensure that any pending power irq interrupt status
is acknowledged otherwise power irq interrupt handler would be fired
prematurely.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9d601dc..d636251 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1250,6 +1250,21 @@ static int sdhci_msm_probe(struct platform_device *pdev)
   CORE_VENDOR_SPEC_CAPABILITIES0);
}
 
+   /*
+* Power on reset state may trigger power irq if previous status of
+* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
+* interrupt in GIC, any pending power irq interrupt should be
+* acknowledged. Otherwise power irq interrupt handler would be
+* fired prematurely.
+*/
+   sdhci_msm_voltage_switch(host);
+
+   /*
+* Ensure that above writes are propogated before interrupt enablement
+* in GIC.
+*/
+   mb();
+
/* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -1259,6 +1274,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto clk_disable;
}
 
+   /* Enable pwr irq interrupts */
+   writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
+
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v2 2/4] mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset

2017-09-26 Thread Vijay Viswanath
From: Sahitya Tummala 

There is a rare scenario in HW, where the first clear pulse could
be lost when the actual reset and clear/read of status register
are happening at the same time. Fix this by retrying upto 10 times
to ensure the status register gets cleared. Otherwise, this will
lead to a spurious power IRQ which results in system instability.

Signed-off-by: Sahitya Tummala 
Signed-off-by: Vijay Viswanath 
---
 drivers/mmc/host/sdhci-msm.c | 46 
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d636251..42a65ab 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -995,17 +995,52 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host 
*host,
sdhci_msm_hs400(host, &mmc->ios);
 }
 
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
+{
+   struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+   struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+
+   pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 
0x%08x\n",
+   mmc_hostname(host->mmc),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
+   readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
 {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
+   int retry = 10;
 
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK;
 
writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
 
+   /*
+* There is a rare HW scenario where the first clear pulse could be
+* lost when actual reset and clear/read of status register is
+* happening at a time. Hence, retry for at least 10 times to make
+* sure status register is cleared. Otherwise, this will result in
+* a spurious power IRQ resulting in system instability.
+*/
+   while (irq_status & readl_relaxed(msm_host->core_mem +
+   CORE_PWRCTL_STATUS)) {
+   if (retry == 0) {
+   pr_err("%s: Timedout clearing (0x%x) pwrctl status 
register\n",
+   mmc_hostname(host->mmc), irq_status);
+   sdhci_msm_dump_pwr_ctrl_regs(host);
+   WARN_ON(1);
+   break;
+   }
+   writel_relaxed(irq_status,
+   msm_host->core_mem + CORE_PWRCTL_CLEAR);
+   retry--;
+   udelay(10);
+   }
+
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
@@ -1017,13 +1052,17 @@ static void sdhci_msm_voltage_switch(struct sdhci_host 
*host)
 * switches are handled by the sdhci core, so just report success.
 */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+
+   pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
+   mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
+   irq_ack);
 }
 
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
struct sdhci_host *host = (struct sdhci_host *)data;
 
-   sdhci_msm_voltage_switch(host);
+   sdhci_msm_handle_pwr_irq(host, irq);
 
return IRQ_HANDLED;
 }
@@ -1106,7 +1145,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, 
unsigned int clock)
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
-   .voltage_switch = sdhci_msm_voltage_switch,
 };
 
 static const struct sdhci_pltfm_data sdhci_msm_pdata = {
@@ -1257,7 +1295,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
 * acknowledged. Otherwise power irq interrupt handler would be
 * fired prematurely.
 */
-   sdhci_msm_voltage_switch(host);
+   sdhci_msm_handle_pwr_irq(host, 0);
 
/*
 * Ensure that above writes are propogated before interrupt enablement
-- 
 Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



Re: [PATCH v2 4/4] mmc: sdhci-msm: Add sdhci msm register write APIs which wait for pwr irq

2017-10-20 Thread Vijay Viswanath

On 10/14/2017 1:01 PM, Bjorn Andersson wrote:

On Tue 26 Sep 22:34 PDT 2017, Vijay Viswanath wrote:


diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c

[..]

+   if (!done) {
+   if (!wait_event_timeout(msm_host->pwr_irq_wait,
+   msm_host->pwr_irq_flag,
+   msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
+   __WARN_printf("%s: pwr_irq for req: (%d) timed out\n",
+   mmc_hostname(host->mmc), req_type);


Bumped my MSM8974AB device to latest linux-next and found this patch; I
see this print every five seconds during boot and the eMMC never comes
up.

Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



Hi Bjorn,

I couldn't get one 8974 device. I tested the latest linux-next on db410c 
and its not showing any issue. 8974 is an older msm and has some 
differences in the controller like your "mmc: sdhci-msm: Enable delay 
circuit calibration clocks" patch.


I am currently going through the programming guide to see what could be 
the reason. Can you please share the full logs from the device with me 
so that I can focus my search?


Thanks,
Vijay