Merge "platform: msm_shared: Add more debug information"
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index a14b3b5..a243e84 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -33,6 +33,14 @@
#include <bits.h>
#include <kernel/event.h>
+//#define DEBUG_SDHCI
+
+#ifdef DEBUG_SDHCI
+#define DBG(...) dprintf(ALWAYS, __VA_ARGS__)
+#else
+#define DBG(...)
+#endif
+
/*
* Capabilities for the host controller
* These values are read from the capabilities
@@ -123,7 +131,7 @@
/*
* Helper macros for writing byte, word & long registers
*/
-#define REG_READ8(host, a) readb(host->base + a);
+#define REG_READ8(host, a) readb(host->base + a)
#define REG_WRITE8(host, v, a) writeb(v, (host->base + a))
#define REG_READ32(host, a) readl(host->base + a)
@@ -155,9 +163,11 @@
#define SDHCI_ERR_INT_STS_EN_REG (0x036)
#define SDHCI_NRML_INT_SIG_EN_REG (0x038)
#define SDHCI_ERR_INT_SIG_EN_REG (0x03A)
+#define SDHCI_AUTO_CMD_ERR (0x03C)
#define SDHCI_HOST_CTRL2_REG (0x03E)
#define SDHCI_CAPS_REG1 (0x040)
#define SDHCI_CAPS_REG2 (0x044)
+#define SDHCI_ADM_ERR_REG (0x054)
#define SDHCI_ADM_ADDR_REG (0x058)
/*
diff --git a/platform/msm_shared/include/sdhci_msm.h b/platform/msm_shared/include/sdhci_msm.h
index a075460..180f23a 100644
--- a/platform/msm_shared/include/sdhci_msm.h
+++ b/platform/msm_shared/include/sdhci_msm.h
@@ -76,7 +76,8 @@
#define CDC_SWITCH_BYPASS_OFF BIT(0)
#define CDC_SWITCH_RC_EN BIT(1)
#define START_CDC_TRAFFIC BIT(6)
-#define FW_CLK_SW_RST_DIS BIT(13)
+#define FF_CLK_SW_RST_DIS_START 0xD
+#define FF_CLK_SW_RST_DIS_WIDTH 0x1
#define CDC_SW_TRIGGER_FULL_CALIB BIT(16)
#define CDC_HW_AUTO_CAL_EN BIT(17)
#define CDC_TIMER_EN BIT(16)
@@ -102,6 +103,9 @@
#define CORE_VERSION_MAJOR_MASK 0xF0000000
#define CORE_VERSION_MAJOR_SHIFT 0x1C
+#define SDHCI_DLL_TIMEOUT 50
+#define CDC_STATUS_TIMEOUT 50
+
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 f7a82f3..0d0b361 100644
--- a/platform/msm_shared/mmc_sdhci.c
+++ b/platform/msm_shared/mmc_sdhci.c
@@ -822,6 +822,8 @@
{
uint32_t mmc_ret = 0;
+ DBG("\n Enabling HS200 Mode Start\n");
+
/* Set 4/8 bit SDR bus width */
mmc_ret = mmc_set_bus_width(host, card, width);
if (mmc_ret) {
@@ -864,6 +866,8 @@
if ((mmc_ret = sdhci_msm_execute_tuning(host, width)))
dprintf(CRITICAL, "Tuning for hs200 failed\n");
+ DBG("\n Enabling HS200 Mode Done\n");
+
return mmc_ret;
}
@@ -877,6 +881,8 @@
{
uint8_t mmc_ret = 0;
+ DBG("\n Enabling DDR Mode Start\n");
+
/* Set width for 8 bit DDR mode by default */
mmc_ret = mmc_set_bus_width(host, card, DATA_DDR_BUS_WIDTH_8BIT);
@@ -892,6 +898,8 @@
/* Set the DDR mode in controller */
sdhci_set_uhs_mode(host, SDHCI_DDR50_MODE);
+ DBG("\n Enabling DDR Mode Done\n");
+
return 0;
}
@@ -947,6 +955,7 @@
* 4. Enable HS400 mode & execute tuning
*/
+ DBG("\n Enabling HS400 Mode Start\n");
/* HS400 mode is supported only in DDR 8-bit */
if (width != DATA_BUS_WIDTH_8BIT)
{
@@ -1008,6 +1017,8 @@
if ((mmc_ret = sdhci_msm_execute_tuning(host, width)))
dprintf(CRITICAL, "Tuning for hs400 failed\n");
+ DBG("\n Enabling HS400 Mode Done\n");
+
return mmc_ret;
}
@@ -1052,6 +1063,12 @@
clock_config_mmc(cfg->slot, cfg->max_clk_rate);
+ /* Configure the CDC clocks needed for emmc storage
+ * we use slot '1' for emmc
+ */
+ if (cfg->slot == 1)
+ clock_config_cdc(cfg->slot);
+
/*
* MSM specific sdhc init
*/
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 9c4e8ed..cbcabff 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -39,6 +39,57 @@
#include <sdhci.h>
#include <sdhci_msm.h>
+static void sdhci_dumpregs(struct sdhci_host *host)
+{
+ DBG("****************** SDHC REG DUMP START ********************\n");
+
+ DBG("Version: 0x%08x\n", REG_READ32(host, SDHCI_ARG2_REG));
+ DBG("Arg2: 0x%08x\t Blk Cnt: 0x%08x\n",
+ REG_READ32(host, SDHCI_ARG2_REG),
+ REG_READ16(host, SDHCI_BLK_CNT_REG));
+ DBG("Arg1: 0x%08x\t Blk Sz : 0x%08x\n",
+ REG_READ32(host, SDHCI_ARGUMENT_REG),
+ REG_READ16(host, SDHCI_BLKSZ_REG));
+ DBG("Command: 0x%08x\t Trans mode: 0x%08x\n",
+ REG_READ16(host, SDHCI_CMD_REG),
+ REG_READ16(host, SDHCI_TRANS_MODE_REG));
+ DBG("Resp0: 0x%08x\t Resp1: 0x%08x\n",
+ REG_READ32(host, SDHCI_RESP_REG),
+ REG_READ32(host, SDHCI_RESP_REG + 0x4));
+ DBG("Resp2: 0x%08x\t Resp3: 0x%08x\n",
+ REG_READ32(host, SDHCI_RESP_REG + 0x8),
+ REG_READ32(host, SDHCI_RESP_REG + 0xC));
+ DBG("Prsnt State: 0x%08x\t Host Ctrl1: 0x%08x\n",
+ REG_READ32(host, SDHCI_PRESENT_STATE_REG),
+ REG_READ8(host, SDHCI_HOST_CTRL1_REG));
+ DBG("Timeout ctrl: 0x%08x\t Power Ctrl: 0x%08x\n",
+ REG_READ8(host, SDHCI_TIMEOUT_REG),
+ REG_READ8(host, SDHCI_PWR_CTRL_REG));
+ DBG("Error stat: 0x%08x\t Int Status: 0x%08x\n",
+ REG_READ32(host, SDHCI_ERR_INT_STS_REG),
+ REG_READ32(host, SDHCI_NRML_INT_STS_REG));
+ DBG("Host Ctrl2: 0x%08x\t Clock ctrl: 0x%08x\n",
+ REG_READ32(host, SDHCI_HOST_CTRL2_REG),
+ REG_READ32(host, SDHCI_CLK_CTRL_REG));
+ DBG("Caps1: 0x%08x\t Caps2: 0x%08x\n",
+ REG_READ32(host, SDHCI_CAPS_REG1),
+ REG_READ32(host, SDHCI_CAPS_REG1));
+ DBG("Adma Err: 0x%08x\t Auto Cmd err: 0x%08x\n",
+ REG_READ8(host, SDHCI_ADM_ERR_REG),
+ REG_READ16(host, SDHCI_AUTO_CMD_ERR));
+ DBG("Adma addr1: 0x%08x\t Adma addr2: 0x%08x\n",
+ REG_READ32(host, SDHCI_ADM_ADDR_REG),
+ REG_READ32(host, SDHCI_ADM_ADDR_REG + 0x4));
+
+ DBG("****************** SDHC REG DUMP END ********************\n");
+
+ DBG("************* SDHC VENDOR REG DUMPS START ***************\n");
+ DBG("SDCC_DLL_CONFIG_REG: 0x%08x\n", REG_READ32(host, SDCC_DLL_CONFIG_REG));
+ DBG("SDCC_VENDOR_SPECIFIC_FUNC: 0x%08x\n", REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC));
+ DBG("SDCC_REG_DLL_STATUS: 0x%08x\n", REG_READ32(host, SDCC_REG_DLL_STATUS));
+ DBG("************* SDHC VENDOR REG DUMPS END ***************\n");
+}
+
/*
* Function: sdhci reset
* Arg : Host structure & mask to write to reset register
@@ -138,6 +189,8 @@
host->cur_clk_rate = clk;
+ DBG("\n %s: clock_rate: %d clock_div:0x%08x\n", __func__, clk, div);
+
return 0;
}
@@ -203,6 +256,8 @@
voltage |= SDHCI_BUS_PWR_EN;
+ DBG("\n %s: voltage: 0x%02x\n", __func__, voltage);
+
REG_WRITE8(host, voltage, SDHCI_PWR_CTRL_REG);
}
@@ -307,6 +362,8 @@
return 1;
}
+ DBG("\n %s: bus width:0x%04x\n", __func__, width);
+
REG_WRITE8(host, (reg | width), SDHCI_HOST_CTRL1_REG);
return 0;
@@ -385,6 +442,19 @@
if (int_status == SDHCI_INT_STS_CMD_COMPLETE)
break;
+ /*
+ * If Tuning is in progress ignore cmd crc & cmd end bit errors
+ */
+ if (host->tuning_in_progress)
+ {
+ err_status = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
+ if ((err_status & SDHCI_CMD_CRC_MASK) || (err_status & SDHCI_DAT_END_BIT_MASK))
+ {
+ sdhci_reset(host, (SOFT_RESET_CMD | SOFT_RESET_DATA));
+ return 0;
+ }
+ }
+
retry++;
udelay(500);
if (retry == SDHCI_MAX_CMD_RETRY) {
@@ -486,8 +556,9 @@
}
else if (sdhci_cmd_err_status(host))
{
- dprintf(CRITICAL, "Error: Command completed with errors\n");
ret = 1;
+ /* Dump sdhc registers on error */
+ sdhci_dumpregs(host);
}
/* Reset Command & Dat lines on error */
need_reset = 1;
@@ -528,7 +599,8 @@
sg_list[0].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
| SDHCI_ADMA_TRANS_END;
- arch_clean_invalidate_cache_range((addr_t)sg_list, sizeof(struct desc_entry));
+ sg_len = 1;
+ table_len = sizeof(struct desc_entry);
} else {
/* Calculate the number of entries in desc table */
sg_len = len / SDHCI_ADMA_DESC_LINE_SZ;
@@ -581,6 +653,12 @@
arch_clean_invalidate_cache_range((addr_t)sg_list, table_len);
+ for (i = 0; i < sg_len; i++)
+ {
+ DBG("\n %s: sg_list: addr: 0x%08x len: 0x%04x attr: 0x%04x\n", __func__, sg_list[i].addr,
+ (sg_list[i].len ? sg_list[i].len : SDHCI_ADMA_DESC_LINE_SZ), sg_list[i].tran_att);
+ }
+
return sg_list;
}
@@ -655,6 +733,9 @@
uint32_t flags;
struct desc_entry *sg_list = NULL;
+ DBG("\n %s: START: cmd:0x%04d, arg:0x%08x, resp_type:0x%04x, data_present:%d\n",
+ __func__, cmd->cmd_index, cmd->argument, cmd->resp_type, cmd->data_present);
+
if (cmd->data_present)
ASSERT(cmd->data.data_ptr);
@@ -724,6 +805,23 @@
flags |= (cmd->data_present << SDHCI_CMD_DATA_PRESENT_BIT);
flags |= (cmd->cmd_type << SDHCI_CMD_CMD_TYPE_BIT);
+ /* Enable Command CRC & Index check for commands with response
+ * R1, R6, R7 & R1B. Also only CRC check for R2 response
+ */
+ switch(cmd->resp_type) {
+ case SDHCI_CMD_RESP_R1:
+ case SDHCI_CMD_RESP_R6:
+ case SDHCI_CMD_RESP_R7:
+ case SDHCI_CMD_RESP_R1B:
+ flags |= (1 << SDHCI_CMD_CRC_CHECK_BIT) | (1 << SDHCI_CMD_IDX_CHECK_BIT);
+ break;
+ case SDHCI_CMD_RESP_R2:
+ flags |= (1 << SDHCI_CMD_CRC_CHECK_BIT);
+ break;
+ default:
+ break;
+ };
+
/* Set the timeout value */
REG_WRITE8(host, SDHCI_CMD_TIMEOUT, SDHCI_TIMEOUT_REG);
@@ -774,6 +872,9 @@
if (sg_list)
free(sg_list);
+ DBG("\n %s: END: cmd:%04d, arg:0x%08x, resp:0x%08x 0x%08x 0x%08x 0x%08x\n",
+ __func__, cmd->cmd_index, cmd->argument, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
return 0;
}
@@ -798,6 +899,9 @@
caps[0] = REG_READ32(host, SDHCI_CAPS_REG1);
caps[1] = REG_READ32(host, SDHCI_CAPS_REG2);
+
+ DBG("\n %s: Host capability: cap1:0x%08x, cap2: 0x%08x\n", __func__, caps[0], caps[1]);
+
host->caps.base_clk_rate = (caps[0] & SDHCI_CLK_RATE_MASK) >> SDHCI_CLK_RATE_BIT;
host->caps.base_clk_rate *= 1000000;
diff --git a/platform/msm_shared/sdhci_msm.c b/platform/msm_shared/sdhci_msm.c
index 8677dbe..25b47e4 100644
--- a/platform/msm_shared/sdhci_msm.c
+++ b/platform/msm_shared/sdhci_msm.c
@@ -151,6 +151,9 @@
/* Enable sdhc mode */
writel(SDHCI_HC_MODE_EN, (config->pwrctl_base + SDCC_MCI_HC_MODE));
+ /* Set the FF_CLK_SW_RST_DIS to 1 */
+ RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1);
+
/*
* Reset the controller
*/
@@ -247,13 +250,16 @@
else if (host->cur_clk_rate <= 200000000)
reg_val = 0x7;
+ DBG("\n %s: DLL freq: 0x%08x\n", __func__, reg_val);
+
REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START, SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
}
/* Initialize DLL (Programmable Delay Line) */
-static void sdhci_msm_init_dll(struct sdhci_host *host)
+static uint32_t sdhci_msm_init_dll(struct sdhci_host *host)
{
uint32_t pwr_save = 0;
+ uint32_t timeout = SDHCI_DLL_TIMEOUT;
pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
@@ -276,17 +282,31 @@
REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN), SDCC_DLL_CONFIG_REG);
/* Write 1 to CLK_OUT_EN */
REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
- /* Wait for DLL_LOCK in DLL_STATUS register */
+ /* Wait for DLL_LOCK in DLL_STATUS register, wait time 50us */
while(!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT));
+ {
+ udelay(1);
+ timeout--;
+ if (!timeout)
+ {
+ dprintf(CRITICAL, "%s: Failed to get DLL lock: 0x%08x\n", __func__, REG_READ32(host, SDCC_REG_DLL_STATUS));
+ return 1;
+ }
+ }
+
/* Set the powersave back on */
if (pwr_save)
REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
+
+ return 0;
}
/* Configure DLL with delay value based on 'phase' */
-static void sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
+static uint32_t sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
{
uint32_t core_cfg = 0;
+ uint32_t timeout = SDHCI_DLL_TIMEOUT;
+
/* Gray code values from SWI */
uint32_t gray_code [] = { 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8 };
@@ -304,8 +324,17 @@
REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
- /* Wait until CLK_OUT_EN is 1 */
- while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN));
+ /* Wait until CLK_OUT_EN is 1, wait time 50us */
+ while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN))
+ {
+ timeout--;
+ udelay(1);
+ if (!timeout)
+ {
+ dprintf(CRITICAL, "%s: clk_out_en timed out: %08x\n", __func__, REG_READ32(host, SDCC_DLL_CONFIG_REG));
+ return 1;
+ }
+ }
core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
@@ -314,7 +343,7 @@
REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
- return;
+ return 0;
}
/*
@@ -427,17 +456,15 @@
uint32_t timeout;
uint32_t cdc_err;
+ DBG("\n CDCLP533 Calibration Start\n");
+
/* Reset & Initialize the DLL block */
- sdhci_msm_init_dll(host);
+ if (sdhci_msm_init_dll(host))
+ return 1;
/* Write the save phase */
- sdhci_msm_config_dll(host, host->msm_host->saved_phase);
-
- /* Configure the clocks needed for CDC */
- clock_config_cdc(host->msm_host->slot);
-
- /* Set the FF_CLK_SW_RST_DIS to 1 */
- REG_WRITE32(host, (REG_READ32(host, SDCC_MCI_HC_MODE) | FW_CLK_SW_RST_DIS), SDCC_MCI_HC_MODE);
+ if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
+ return 1;
/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
@@ -492,7 +519,7 @@
REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN), SDCC_CSR_CDC_CAL_TIMER_CFG0);
/* Wait for CALIBRATION_DONE in CDC_STATUS */
- timeout = 50;
+ timeout = CDC_STATUS_TIMEOUT;
while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0)))
{
timeout--;
@@ -513,6 +540,8 @@
/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
+ DBG("\n CDCLP533 Calibration Done\n");
+
return 0;
}
@@ -531,6 +560,7 @@
uint32_t phase = 0;
uint32_t tuned_phase_cnt = 0;
int ret = 0;
+ int i;
struct sdhci_msm_data *msm_host;
msm_host = host->msm_host;
@@ -563,14 +593,22 @@
ASSERT(tuning_data);
/* Reset & Initialize the DLL block */
- sdhci_msm_init_dll(host);
+ if (sdhci_msm_init_dll(host))
+ {
+ ret = 1;
+ goto free;
+ }
while (phase < MAX_PHASES)
{
struct mmc_command cmd = {0};
/* configure dll to set phase delay */
- sdhci_msm_config_dll(host, phase);
+ if (sdhci_msm_config_dll(host, phase))
+ {
+ ret = 1;
+ goto free;
+ }
cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
cmd.argument = 0x0;
@@ -592,6 +630,12 @@
/* Find the appropriate tuned phase */
if (tuned_phase_cnt)
{
+ DBG("\n Tuned phase\n");
+ for (i = 0 ; i < tuned_phase_cnt ; i++)
+ {
+ DBG("%d\t", tuned_phases[i]);
+ }
+
ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
if (ret < 0)
@@ -604,7 +648,10 @@
phase = (uint32_t) ret;
ret = 0;
- sdhci_msm_config_dll(host, phase);
+ DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
+
+ if (sdhci_msm_config_dll(host, phase))
+ goto free;
/* Save the tuned phase */
host->msm_host->saved_phase = phase;