[RFC PATCH 10/11] mmc: host: tegra: config settings for timing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Use config settings framework to initialize Tegra SDHCI
timing registers

Signed-off-by: Krishna Yarlagadda <kyarlagadda@xxxxxxxxxx>
Signed-off-by: Prathamesh Shete <pshete@xxxxxxxxxx>
---
 drivers/mmc/host/sdhci-tegra.c | 84 ++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 1ad0a6b3a2eb..87fe85991617 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -28,6 +28,7 @@
 #include <linux/reset.h>
 
 #include <soc/tegra/common.h>
+#include <soc/tegra/tegra-cfg.h>
 
 #include "sdhci-cqhci.h"
 #include "sdhci-pltfm.h"
@@ -64,6 +65,7 @@
 #define SDHCI_TEGRA_DLLCAL_STA_ACTIVE			BIT(31)
 
 #define SDHCI_VNDR_TUN_CTRL0_0				0x1c0
+#define SDHCI_VNDR_TUN_CTRL0_CMD_CRC_ERR_EN		BIT(28)
 #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP			0x20000
 #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK		0x03fc0000
 #define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT	18
@@ -74,6 +76,7 @@
 #define TRIES_128					2
 #define TRIES_256					4
 #define SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK		0x7
+#define SDHCI_VNDR_TUN_CTRL0_DIV_N_MASK			GENMASK(5, 3)
 
 #define SDHCI_TEGRA_VNDR_TUN_CTRL1_0			0x1c4
 #define SDHCI_TEGRA_VNDR_TUN_STATUS0			0x1C8
@@ -134,6 +137,20 @@
 					 SDHCI_TRNS_BLK_CNT_EN | \
 					 SDHCI_TRNS_DMA)
 
+static const char * const cfg_device_states[] = {
+	"default",		/* MMC_TIMING_LEGACY */
+	"sd-mmc-highspeed",	/* MMC_TIMING_MMC_HS */
+	"sd-mmc-highspeed",	/* MMC_TIMING_SD_HS */
+	"uhs-sdr12",		/* MMC_TIMING_UHS_SDR12 */
+	"uhs-sdr25",		/* MMC_TIMING_UHS_SDR25 */
+	"uhs-sdr50",		/* MMC_TIMING_UHS_SDR50 */
+	"uhs-sdr104",		/* MMC_TIMING_UHS_SDR104 */
+	"uhs-ddr52",		/* MMC_TIMING_UHS_DDR50 */
+	"uhs-ddr52",		/* MMC_TIMING_MMC_DDR52 */
+	"mmc-hs200",		/* MMC_TIMING_MMC_HS200 */
+	"mmc-hs400",		/* MMC_TIMING_MMC_HS400 */
+};
+
 struct sdhci_tegra_soc_data {
 	const struct sdhci_pltfm_data *pdata;
 	u64 dma_mask;
@@ -158,6 +175,18 @@ struct sdhci_tegra_autocal_offsets {
 	u32 pull_down_hs400;
 };
 
+static const struct tegra_cfg_field_desc sdhci_cfg_fields[] = {
+	TEGRA_CFG_FIELD("nvidia,num-tuning-iter",
+			SDHCI_VNDR_TUN_CTRL0_0,
+			SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK),
+};
+
+static struct tegra_cfg_desc sdhci_cfg_desc = {
+	.num_regs = 0,
+	.num_fields = ARRAY_SIZE(sdhci_cfg_fields),
+	.fields = sdhci_cfg_fields,
+};
+
 struct sdhci_tegra {
 	const struct sdhci_tegra_soc_data *soc_data;
 	struct gpio_desc *power_gpio;
@@ -183,6 +212,7 @@ struct sdhci_tegra {
 	unsigned long curr_clk_rate;
 	u8 tuned_tap_delay;
 	u32 stream_id;
+	struct tegra_cfg_list *list;
 };
 
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -362,6 +392,30 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
 	}
 }
 
+static void tegra_sdhci_write_cfg_settings(struct sdhci_host *host,
+					   const char *name)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+	struct tegra_cfg_reg *regs;
+	struct tegra_cfg *cfg;
+	unsigned int i;
+	u32 val;
+
+	cfg = tegra_cfg_get_by_name(mmc_dev(host->mmc),
+				    tegra_host->list, name);
+	if (!cfg)
+		return;
+
+	regs = cfg->regs;
+	for (i = 0; i < cfg->num_regs; ++i) {
+		val = sdhci_readl(host, regs[i].offset);
+		val &= ~regs[i].mask;
+		val |= regs[i].value;
+		sdhci_writel(host, val, regs[i].offset);
+	}
+}
+
 static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -374,6 +428,8 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 	if (!(mask & SDHCI_RESET_ALL))
 		return;
 
+	tegra_sdhci_write_cfg_settings(host, "common");
+
 	tegra_sdhci_set_tap(host, tegra_host->default_tap);
 
 	misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
@@ -1011,6 +1067,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
 	bool set_default_tap = false;
 	bool set_dqs_trim = false;
 	bool do_hs400_dll_cal = false;
+	bool set_config = false;
 	u8 iter = TRIES_256;
 	u32 val;
 
@@ -1027,6 +1084,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
 		set_dqs_trim = true;
 		do_hs400_dll_cal = true;
 		iter = TRIES_128;
+		set_config = true;
 		break;
 	case MMC_TIMING_MMC_DDR52:
 	case MMC_TIMING_UHS_DDR50:
@@ -1059,6 +1117,9 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
 	else
 		tegra_sdhci_set_tap(host, tegra_host->default_tap);
 
+	if (set_config)
+		tegra_sdhci_write_cfg_settings(host,
+					       cfg_device_states[timing]);
 	if (set_dqs_trim)
 		tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim);
 
@@ -1129,6 +1190,29 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
 static int tegra_sdhci_init_pinctrl_info(struct device *dev,
 					 struct sdhci_tegra *tegra_host)
 {
+	unsigned int i, j, count;
+	const struct tegra_cfg_field_desc *fields;
+
+	count = 0;
+	fields = sdhci_cfg_fields;
+
+	for (i = 0; i < sdhci_cfg_desc.num_fields; i++) {
+		for (j = 0; j < i; j++)
+			if (fields[i].offset == fields[j].offset)
+				break;
+
+		if (i == j)
+			count++;
+	}
+
+	sdhci_cfg_desc.num_regs = count;
+	tegra_host->list = tegra_cfg_get(dev, NULL, &sdhci_cfg_desc);
+	if (IS_ERR(tegra_host->list)) {
+		dev_dbg(dev, "Config setting not available, err: %ld\n",
+			PTR_ERR(tegra_host->list));
+		tegra_host->list = NULL;
+	}
+
 	tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev);
 	if (IS_ERR(tegra_host->pinctrl_sdmmc)) {
 		dev_dbg(dev, "No pinctrl info, err: %ld\n",
-- 
2.43.2





[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux