platform: msm_shared: Check SDCC version before enabling hs400 mode
SDHC open spec does not support hs400 mode, so the existing driver
was using SDR104 capability from host to enable hs400 mode. SDR104
mode only corresponds to hs200 mode, instead we should read SDCC
version register to find out if host supports hs400 mode.
SDCC5 supports hs400 mode, so enable hs400 mode only if the host
controller version is SDCC5 or greater.
CRs-Fixed: 609007
Change-Id: I41a5e388de8254c55425f4514bb00e2bdabecac7
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index b7061dd..a14b3b5 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -48,6 +48,7 @@
uint8_t ddr_support; /* Dual Data rate */
uint8_t sdr50_support; /* UHS mode, with 100 MHZ clock */
uint8_t sdr104_support; /* UHS mode, with 200 MHZ clock */
+ uint8_t hs400_support; /* Hs400 mode, with 400 MHZ clock */
};
/*
diff --git a/platform/msm_shared/include/sdhci_msm.h b/platform/msm_shared/include/sdhci_msm.h
index bc36348..293cd13 100644
--- a/platform/msm_shared/include/sdhci_msm.h
+++ b/platform/msm_shared/include/sdhci_msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -97,6 +97,11 @@
#define MAX_PHASES 16
+/* SDCC version macros */
+#define MCI_VERSION 0x50
+#define CORE_VERSION_MAJOR_MASK 0xF0000000
+#define CORE_VERSION_MAJOR_SHIFT 0x1C
+
struct sdhci_msm_data
{
uint32_t pwrctl_base;
diff --git a/platform/msm_shared/mmc_sdhci.c b/platform/msm_shared/mmc_sdhci.c
index c8caf66..01121fe 100644
--- a/platform/msm_shared/mmc_sdhci.c
+++ b/platform/msm_shared/mmc_sdhci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -842,7 +842,7 @@
sdhci_set_uhs_mode(host, SDHCI_SDR104_MODE);
/* Run the clock @ 400 Mhz */
- if (mmc_card_supports_hs400_mode(card))
+ if (host->caps.hs400_support && mmc_card_supports_hs400_mode(card))
{
clock_config_mmc(host->msm_host->slot, SDHCI_CLK_400MHZ);
/* Save the timing value, before changing the clock */
@@ -1525,7 +1525,7 @@
* 2. DDR mode host, if supported by host & card
* 3. Use normal speed mode with supported bus width
*/
- if (mmc_card_supports_hs400_mode(card) && host->caps.sdr104_support)
+ if (host->caps.hs400_support && mmc_card_supports_hs400_mode(card))
{
mmc_return = mmc_set_hs400_mode(host, card, bus_width);
if (mmc_return)
@@ -1535,7 +1535,7 @@
return mmc_return;
}
}
- else if (mmc_card_supports_hs200_mode(card) && host->caps.sdr104_support)
+ else if (host->caps.sdr104_support && mmc_card_supports_hs200_mode(card))
{
mmc_return = mmc_set_hs200_mode(host, card, bus_width);
@@ -1544,7 +1544,7 @@
card->rca);
return mmc_return;
}
- } else if (mmc_card_supports_ddr_mode(card) && host->caps.ddr_support) {
+ } else if (host->caps.ddr_support && mmc_card_supports_ddr_mode(card)) {
mmc_return = mmc_set_ddr_mode(host, card);
if (mmc_return) {
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 6fba466..547f4ec 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -37,7 +37,7 @@
#include <bits.h>
#include <debug.h>
#include <sdhci.h>
-
+#include <sdhci_msm.h>
/*
* Function: sdhci reset
@@ -799,7 +799,7 @@
void sdhci_init(struct sdhci_host *host)
{
uint32_t caps[2];
-
+ uint8_t sdcc_version = 0;
/* Read the capabilities register & store the info */
caps[0] = REG_READ32(host, SDHCI_CAPS_REG1);
@@ -836,6 +836,14 @@
/* SDR104 mode support */
host->caps.sdr104_support = (caps[1] & SDHCI_SDR104_MODE_MASK) ? 1 : 0;
+ /* HS400 mode support:
+ * The last four bits of MCI_VERSION indicate the SDCC major version
+ * Version 0 --> SDCC4 core
+ * Version >= 1 --> SDCC5 or above core
+ */
+ sdcc_version = ((readl(host->msm_host->pwrctl_base + MCI_VERSION)) & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
+ host->caps.hs400_support = (sdcc_version >= 1) ? 1 : 0;
+
/* Set bus power on */
sdhci_set_bus_power_on(host);