mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Diff
		
	
	
| --- linux-4.9.37/drivers/mmc/host/sdhci-gk7202v300.c	1970-01-01 03:00:00.000000000 +0300
 | |
| +++ linux-4.9.y/drivers/mmc/host/sdhci-gk7202v300.c	2021-06-07 13:01:33.000000000 +0300
 | |
| @@ -0,0 +1,495 @@
 | |
| +/*
 | |
| + * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
 | |
| + */
 | |
| +
 | |
| +#include <linux/delay.h>
 | |
| +#include <linux/device.h>
 | |
| +#include <linux/of.h>
 | |
| +#include <linux/module.h>
 | |
| +#include <linux/regmap.h>
 | |
| +#include <linux/mfd/syscon.h>
 | |
| +#include <linux/reset.h>
 | |
| +#include <linux/mmc/host.h>
 | |
| +#include <linux/pm_runtime.h>
 | |
| +#include "sdhci-pltfm.h"
 | |
| +#include "sdhci-proc.h"
 | |
| +
 | |
| +#ifdef CONFIG_MMC_SDHCI_GOKE
 | |
| +#define PHASE_SCALE	32
 | |
| +#define EDGE_TUNING_PHASE_STEP	4
 | |
| +#define NOT_FOUND	(-1)
 | |
| +#define MAX_TUNING_NUM	1
 | |
| +#define MAX_FREQ	200000000
 | |
| +
 | |
| +#define GOKE_MMC_AUTOSUSPEND_DELAY_MS 50
 | |
| +
 | |
| +#define REG_EMMC_DRV_DLL_CTRL		0x1fc
 | |
| +#define REG_SDIO0_DRV_DLL_CTRL		0x1fc
 | |
| +#define REG_SDIO1_DRV_DLL_CTRL		0x220
 | |
| +#define REG_SDIO2_DRV_DLL_CTRL          /* no sdio2 */
 | |
| +#define SDIO_DRV_PHASE_SEL_MASK		(0x1f << 24)
 | |
| +#define sdio_drv_sel(phase)		((phase) << 24)
 | |
| +
 | |
| +#define REG_EMMC_DRV_DLL_STATUS		0x210
 | |
| +#define REG_SDIO0_DRV_DLL_STATUS	0x210
 | |
| +#define REG_SDIO1_DRV_DLL_STATUS	0x228
 | |
| +#define REG_SDIO2_DRV_DLL_STATUS        /* no sdio2 */
 | |
| +#define SDIO_DRV_DLL_LOCK		BIT(15)
 | |
| +#define SDIO_DRV_DLL_READY		BIT(14)
 | |
| +
 | |
| +#define REG_EMMC_SAMPL_DLL_STATUS	0x208
 | |
| +#define REG_SDIO0_SAMPL_DLL_STATUS	0x208
 | |
| +#define REG_SDIO1_SAMPL_DLL_STATUS	0x224
 | |
| +#define REG_SDIO2_SAMPL_DLL_STATUS      /* no sdio2 */
 | |
| +#define SDIO_SAMPL_DLL_SLAVE_READY	BIT(0)
 | |
| +
 | |
| +#define REG_EMMC_SAMPL_DLL_CTRL		0x1f4
 | |
| +#define REG_SDIO0_SAMPL_DLL_CTRL	0x1f4
 | |
| +#define REG_SDIO1_SAMPL_DLL_CTRL	0x22c
 | |
| +#define REG_SDIO2_SAMPL_DLL_CTRL        /* no sdio2 */
 | |
| +#define SDIO_SAMPL_DLL_SLAVE_EN		BIT(16)
 | |
| +
 | |
| +#define REG_EMMC_SAMPLB_DLL_CTRL	0x1f8
 | |
| +#define REG_SDIO0_SAMPLB_DLL_CTRL	0x1f8
 | |
| +#define REG_SDIO1_SAMPLB_DLL_CTRL	0x21c
 | |
| +#define REG_SDIO2_SAMPLB_DLL_CTRL       /* no sdio2 */
 | |
| +#define SDIO_SAMPLB_DLL_CLK_MASK	(0x1f << 0)
 | |
| +#define sdio_samplb_sel(phase)		((phase) << 0)
 | |
| +
 | |
| +#define REG_EMMC_DS_DLL_CTRL		0x200
 | |
| +#define EMMC_DS_DLL_MODE_SSEL		BIT(13)
 | |
| +#define EMMC_DS_DLL_SSEL_MASK		0x7f
 | |
| +
 | |
| +#define REG_EMMC_DS180_DLL_CTRL		0x204
 | |
| +#define EMMC_DS180_DLL_BYPASS		BIT(15)
 | |
| +#define REG_EMMC_DS180_DLL_STATUS	0x218
 | |
| +#define EMMC_DS180_DLL_READY		BIT(0)
 | |
| +
 | |
| +#define REG_EMMC_DS_DLL_STATUS		0x214
 | |
| +#define EMMC_DS_DLL_READY		BIT(0)
 | |
| +
 | |
| +#define REG_EMMC_CLK_CTRL		0x1f4
 | |
| +#define REG_SDIO0_CLK_CTRL		0x1f4
 | |
| +#define REG_SDIO1_CLK_CTRL		0x22c
 | |
| +#define REG_SDIO2_CLK_CTRL              /* no sdio2 */
 | |
| +#define SDIO_CLK_DRV_DLL_RST		BIT(29)
 | |
| +#define SDIO_CLK_CRG_RST		BIT(27)
 | |
| +
 | |
| +#define IO_CFG_SR			BIT(10)
 | |
| +#define IO_CFG_PULL_DOWN		BIT(9)
 | |
| +#define IO_CFG_PULL_UP			BIT(8)
 | |
| +#define IO_CFG_DRV_STR_MASK		(0xf << 4)
 | |
| +#define io_cfg_drv_str_sel(str)		((str) << 4)
 | |
| +#define IO_CFG_PIN_MUX_MASK		(0xf << 0)
 | |
| +#define io_cfg_pin_mux_sel(type)	((type) << 0)
 | |
| +#define IO_CFG_PIN_MUX_TYPE_CLK_EMMC	0x0
 | |
| +#define IO_CFG_PIN_MUX_TYPE_CLK_SD	0x1
 | |
| +
 | |
| +#define IO_CFG_EMMC_DATA_LINE_COUNT	4
 | |
| +#define REG_CTRL_EMMC_CLK		0x0014
 | |
| +#define REG_CTRL_EMMC_CMD		0x0018
 | |
| +#define REG_CTRL_EMMC_DATA0		0x001c
 | |
| +#define REG_CTRL_EMMC_DATA1		0x0028
 | |
| +#define REG_CTRL_EMMC_DATA2		0x0024
 | |
| +#define REG_CTRL_EMMC_DATA3		0x0020
 | |
| +
 | |
| +#define REG_CTRL_EMMC_DS		0x0058
 | |
| +#define REG_CTRL_EMMC_RST		0x005c
 | |
| +static unsigned int io_emmc_data_reg[IO_CFG_EMMC_DATA_LINE_COUNT] = {
 | |
| +	REG_CTRL_EMMC_DATA0, REG_CTRL_EMMC_DATA1,
 | |
| +	REG_CTRL_EMMC_DATA2, REG_CTRL_EMMC_DATA3
 | |
| +};
 | |
| +
 | |
| +#define IO_CFG_SDIO0_DATA_LINE_COUNT	4
 | |
| +#define REG_CTRL_SDIO0_CLK		0x0040
 | |
| +#define REG_CTRL_SDIO0_CMD		0x0044
 | |
| +#define REG_CTRL_SDIO0_DATA0		0x0048
 | |
| +#define REG_CTRL_SDIO0_DATA1		0x004C
 | |
| +#define REG_CTRL_SDIO0_DATA2		0x0050
 | |
| +#define REG_CTRL_SDIO0_DATA3		0x0054
 | |
| +static unsigned int io_sdio0_data_reg[IO_CFG_SDIO0_DATA_LINE_COUNT] = {
 | |
| +	REG_CTRL_SDIO0_DATA0, REG_CTRL_SDIO0_DATA1,
 | |
| +	REG_CTRL_SDIO0_DATA2, REG_CTRL_SDIO0_DATA3
 | |
| +};
 | |
| +
 | |
| +#define IO_CFG_SDIO1_DATA_LINE_COUNT	4
 | |
| +#define REG_CTRL_SDIO1_CLK		0x0048
 | |
| +#define REG_CTRL_SDIO1_CMD		0x004C
 | |
| +#define REG_CTRL_SDIO1_DATA0		0x0064
 | |
| +#define REG_CTRL_SDIO1_DATA1		0x0060
 | |
| +#define REG_CTRL_SDIO1_DATA2		0x005C
 | |
| +#define REG_CTRL_SDIO1_DATA3		0x0058
 | |
| +static unsigned int io_sdio1_data_reg[IO_CFG_SDIO1_DATA_LINE_COUNT] = {
 | |
| +	REG_CTRL_SDIO1_DATA0, REG_CTRL_SDIO1_DATA1,
 | |
| +	REG_CTRL_SDIO1_DATA2, REG_CTRL_SDIO1_DATA3
 | |
| +};
 | |
| +
 | |
| +struct sdhci_bsp_priv {
 | |
| +	struct reset_control *crg_rst;
 | |
| +	struct reset_control *dll_rst;
 | |
| +	struct reset_control *sampl_rst; /* Not used */
 | |
| +	struct regmap *crg_regmap;
 | |
| +	struct regmap *iocfg_regmap;
 | |
| +	unsigned int f_max;
 | |
| +	unsigned int devid;
 | |
| +	unsigned int drv_phase;
 | |
| +	unsigned int sampl_phase;
 | |
| +	unsigned int tuning_phase;
 | |
| +};
 | |
| +
 | |
| +static void bsp_mmc_crg_init(struct sdhci_host *host);
 | |
| +static void sdhci_bsp_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios);
 | |
| +static int sdhci_bsp_parse_dt(struct sdhci_host *host);
 | |
| +
 | |
| +static inline void *sdhci_get_pltfm_priv(struct sdhci_host *host)
 | |
| +{
 | |
| +	return sdhci_pltfm_priv(sdhci_priv(host));
 | |
| +}
 | |
| +
 | |
| +static void sdhci_bsp_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios)
 | |
| +{
 | |
| +	u32 ctrl;
 | |
| +	struct sdhci_host *host = mmc_priv(mmc);
 | |
| +
 | |
| +	ctrl = sdhci_readl(host, SDHCI_EMMC_CTRL);
 | |
| +	if (ios->enhanced_strobe)
 | |
| +		ctrl |= SDHCI_ENH_STROBE_EN;
 | |
| +	else
 | |
| +		ctrl &= ~SDHCI_ENH_STROBE_EN;
 | |
| +
 | |
| +	sdhci_writel(host, ctrl, SDHCI_EMMC_CTRL);
 | |
| +}
 | |
| +
 | |
| +static int sdhci_bsp_pltfm_init(struct platform_device *pdev, struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_pltfm_priv(pltfm_host);
 | |
| +	struct device_node *np = pdev->dev.of_node;
 | |
| +	struct clk *clk = NULL;
 | |
| +	int ret;
 | |
| +
 | |
| +	bsp_priv->crg_rst = devm_reset_control_get(&pdev->dev, "crg_reset");
 | |
| +	if (IS_ERR_OR_NULL(bsp_priv->crg_rst)) {
 | |
| +		dev_err(&pdev->dev, "get crg_rst failed.\n");
 | |
| +		return PTR_ERR(bsp_priv->crg_rst);
 | |
| +	}
 | |
| +
 | |
| +	bsp_priv->dll_rst = devm_reset_control_get(&pdev->dev, "dll_reset");
 | |
| +	if (IS_ERR_OR_NULL(bsp_priv->dll_rst)) {
 | |
| +		dev_err(&pdev->dev, "get dll_rst failed.\n");
 | |
| +		return PTR_ERR(bsp_priv->dll_rst);
 | |
| +	}
 | |
| +
 | |
| +	bsp_priv->sampl_rst = NULL;
 | |
| +
 | |
| +	bsp_priv->crg_regmap = syscon_regmap_lookup_by_phandle(np, "crg_regmap");
 | |
| +	if (IS_ERR(bsp_priv->crg_regmap)) {
 | |
| +		dev_err(&pdev->dev, "get crg regmap failed.\n");
 | |
| +		return PTR_ERR(bsp_priv->crg_regmap);
 | |
| +	}
 | |
| +
 | |
| +	bsp_priv->iocfg_regmap = syscon_regmap_lookup_by_phandle(np, "iocfg_regmap");
 | |
| +	if (IS_ERR(bsp_priv->iocfg_regmap)) {
 | |
| +		dev_err(&pdev->dev, "get iocfg regmap failed.\n");
 | |
| +		return PTR_ERR(bsp_priv->iocfg_regmap);
 | |
| +	}
 | |
| +
 | |
| +	if (of_property_read_u32(np, "devid", &bsp_priv->devid))
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	clk = devm_clk_get(mmc_dev(host->mmc), "mmc_clk");
 | |
| +	if (IS_ERR_OR_NULL(clk)) {
 | |
| +		dev_err(mmc_dev(host->mmc), "get clk err\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	pltfm_host->clk = clk;
 | |
| +
 | |
| +	bsp_mmc_crg_init(host);
 | |
| +	ret = sdhci_bsp_parse_dt(host);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	/*
 | |
| +	 * Only eMMC has a hw reset, and now eMMC signaling
 | |
| +	 * is fixed to 180
 | |
| +	 */
 | |
| +	if (host->mmc->caps & MMC_CAP_HW_RESET) {
 | |
| +		host->flags &= ~SDHCI_SIGNALING_330;
 | |
| +		host->flags |= SDHCI_SIGNALING_180;
 | |
| +	}
 | |
| +
 | |
| +	/*
 | |
| +	 * We parse the support timings from dts, so we read the
 | |
| +	 * host capabilities early and clear the timing capabilities,
 | |
| +	 * SDHCI_QUIRK_MISSING_CAPS is set so that sdhci driver would
 | |
| +	 * not read it again
 | |
| +	 */
 | |
| +	host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
 | |
| +	host->caps &= ~(SDHCI_CAN_DO_HISPD | SDHCI_CAN_VDD_300);
 | |
| +	host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
 | |
| +	host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
 | |
| +				SDHCI_SUPPORT_DDR50 | SDHCI_CAN_DO_ADMA3);
 | |
| +	host->quirks |= SDHCI_QUIRK_MISSING_CAPS |
 | |
| +			SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 | |
| +			SDHCI_QUIRK_SINGLE_POWER_WRITE;
 | |
| +
 | |
| +	host->mmc_host_ops.hs400_enhanced_strobe =
 | |
| +			sdhci_bsp_hs400_enhanced_strobe;
 | |
| +
 | |
| +	mci_host[slot_index++] = host->mmc;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void bsp_wait_ds_dll_lock(struct sdhci_host *host)
 | |
| +{
 | |
| +	/* Do nothing */
 | |
| +}
 | |
| +
 | |
| +static void bsp_wait_ds_180_dll_ready(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	unsigned int reg;
 | |
| +	unsigned int timeout = 20;
 | |
| +
 | |
| +	do {
 | |
| +		reg = 0;
 | |
| +		regmap_read(bsp_priv->crg_regmap,
 | |
| +				REG_EMMC_DS180_DLL_STATUS, ®);
 | |
| +		if (reg & EMMC_DS180_DLL_READY)
 | |
| +			return;
 | |
| +
 | |
| +		mdelay(1);
 | |
| +		timeout--;
 | |
| +	} while (timeout > 0);
 | |
| +
 | |
| +	pr_err("%s: DS 180 DLL master not ready.\n", mmc_hostname(host->mmc));
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_ds_dll_delay(struct sdhci_host *host)
 | |
| +{
 | |
| +	/* Do nothing */
 | |
| +}
 | |
| +
 | |
| +static void bsp_host_extra_init(struct sdhci_host *host)
 | |
| +{
 | |
| +	unsigned short ctrl;
 | |
| +	unsigned int mbiiu_ctrl, val;
 | |
| +
 | |
| +	ctrl = sdhci_readw(host, SDHCI_MSHC_CTRL);
 | |
| +	ctrl &= ~SDHCI_CMD_CONFLIT_CHECK;
 | |
| +	sdhci_writew(host, ctrl, SDHCI_MSHC_CTRL);
 | |
| +
 | |
| +	mbiiu_ctrl = sdhci_readl(host, SDHCI_AXI_MBIIU_CTRL);
 | |
| +	mbiiu_ctrl &= ~(SDHCI_GM_WR_OSRC_LMT_MASK | SDHCI_GM_RD_OSRC_LMT_MASK |
 | |
| +			SDHCI_UNDEFL_INCR_EN);
 | |
| +	mbiiu_ctrl |= (SDHCI_GM_WR_OSRC_LMT_SEL(0x7) | /* set write outstanding 8 (lmt + 1) */
 | |
| +		       SDHCI_GM_RD_OSRC_LMT_SEL(0x7)); /* set read outstanding 8 (lmt + 1) */
 | |
| +	sdhci_writel(host, mbiiu_ctrl, SDHCI_AXI_MBIIU_CTRL);
 | |
| +
 | |
| +	val = sdhci_readl(host, SDHCI_MULTI_CYCLE);
 | |
| +	val &= ~SDHCI_CMD_DLY_EN;
 | |
| +	val |= SDHCI_EDGE_DETECT_EN | SDHCI_DATA_DLY_EN;
 | |
| +	val &= ~SDHCI_DOUT_EN_F_EDGE;
 | |
| +
 | |
| +	sdhci_writel(host, val, SDHCI_MULTI_CYCLE);
 | |
| +	host->error_count = 0;
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_drv_str(struct regmap *iocfg_regmap,
 | |
| +				unsigned int offset, unsigned int pull_up,
 | |
| +				unsigned int pull_down, unsigned int sr,
 | |
| +				unsigned int drv_str)
 | |
| +{
 | |
| +	unsigned int reg = 0;
 | |
| +
 | |
| +	regmap_read(iocfg_regmap, offset, ®);
 | |
| +
 | |
| +	reg &= ~(IO_CFG_PULL_UP | IO_CFG_PULL_DOWN |
 | |
| +		 IO_CFG_DRV_STR_MASK | IO_CFG_SR);
 | |
| +	reg |= (pull_up ? IO_CFG_PULL_UP : 0);
 | |
| +	reg |= (pull_down ? IO_CFG_PULL_DOWN : 0);
 | |
| +	reg |= (sr ? IO_CFG_SR : 0);
 | |
| +	reg |= io_cfg_drv_str_sel(drv_str);
 | |
| +
 | |
| +	regmap_write(iocfg_regmap, offset, reg);
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_emmc_ctrl(struct sdhci_host *host)
 | |
| +{
 | |
| +	unsigned int reg;
 | |
| +
 | |
| +	reg = sdhci_readl(host, SDHCI_EMMC_CTRL);
 | |
| +	reg |= SDHCI_CARD_IS_EMMC;
 | |
| +	sdhci_writel(host, reg, SDHCI_EMMC_CTRL);
 | |
| +}
 | |
| +
 | |
| +
 | |
| +static void bsp_set_mmc_drv(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	void *iocfg_regmap = bsp_priv->iocfg_regmap;
 | |
| +	int i;
 | |
| +
 | |
| +	switch (host->timing) {
 | |
| +	case MMC_TIMING_MMC_HS400:
 | |
| +		bsp_set_emmc_ctrl(host);
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CLK, 0, 1, 0, 0x3); /* set drv level 3 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CMD, 1, 0, 0, 0x5); /* set drv level 5 */
 | |
| +		for (i = 0; i < IO_CFG_EMMC_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_emmc_data_reg[i], 1, 0, 0, 0x5); /* set drv level 5 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_DS, 0, 1, 1, 0x3);  /* set drv level 3 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_RST, 1, 0, 1, 0x3); /* set drv level 3 */
 | |
| +		break;
 | |
| +	case MMC_TIMING_MMC_HS200:
 | |
| +		bsp_set_emmc_ctrl(host);
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CLK, 0, 1, 0, 0x2); /* set drv level 2 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CMD, 1, 0, 1, 0x4); /* set drv level 4 */
 | |
| +		for (i = 0; i < IO_CFG_EMMC_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_emmc_data_reg[i], 1, 0, 1, 0x4); /* set drv level 4 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_RST, 1, 0, 1, 0x3); /* set drv level 3 */
 | |
| +		break;
 | |
| +	case MMC_TIMING_MMC_HS:
 | |
| +		bsp_set_emmc_ctrl(host);
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CLK, 0, 1, 1, 0x4); /* set drv level 4 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CMD, 1, 0, 1, 0x6); /* set drv level 6 */
 | |
| +		for (i = 0; i < IO_CFG_EMMC_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_emmc_data_reg[i], 1, 0, 1, 0x6); /* set drv level 6 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_RST, 1, 0, 1, 0x3); /* set drv level 3 */
 | |
| +		break;
 | |
| +	case MMC_TIMING_LEGACY:
 | |
| +	case MMC_TIMING_MMC_DDR52:
 | |
| +	default:
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CLK, 0, 1, 1, 0x5); /* set drv level 5 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_CMD, 1, 0, 1, 0x6); /* set drv level 6 */
 | |
| +		for (i = 0; i < IO_CFG_EMMC_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_emmc_data_reg[i], 1, 0, 1, 0x6); /* set drv level 6 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_EMMC_RST, 1, 0, 1, 0x3); /* set drv level 3 */
 | |
| +		break;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_sd_drv(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	void *iocfg_regmap = bsp_priv->iocfg_regmap;
 | |
| +	int i;
 | |
| +
 | |
| +	switch (host->timing) {
 | |
| +	case MMC_TIMING_SD_HS:
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO0_CLK, 0, 1, 1, 0x5); /* set drv level 5 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO0_CMD, 1, 0, 1, 0x7); /* set drv level 7 */
 | |
| +		for (i = 0; i < IO_CFG_SDIO0_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_sdio0_data_reg[i], 1, 0, 1, 0x7); /* set drv level 7 */
 | |
| +		break;
 | |
| +	case MMC_TIMING_LEGACY:
 | |
| +	default:
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO0_CLK, 0, 1, 1, 0x5); /* set drv level 5 */
 | |
| +		bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO0_CMD, 1, 0, 1, 0x7); /* set drv level 7 */
 | |
| +		for (i = 0; i < IO_CFG_SDIO0_DATA_LINE_COUNT; i++)
 | |
| +			bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_sdio0_data_reg[i], 1, 0, 1, 0x7); /* set drv level 7 */
 | |
| +		break;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_sdio_drv(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	void *iocfg_regmap = bsp_priv->iocfg_regmap;
 | |
| +	int i;
 | |
| +
 | |
| +	bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO1_CLK, 0, 1, 0, 0x3); /* 0x3 set drv level 5 */
 | |
| +	bsp_set_drv_str(iocfg_regmap, REG_CTRL_SDIO1_CMD, 1, 0, 0, 0x2); /* 0x2 set drv level 2 */
 | |
| +	for (i = 0; i < IO_CFG_SDIO1_DATA_LINE_COUNT; i++)
 | |
| +		bsp_set_drv_str(iocfg_regmap,
 | |
| +				io_sdio1_data_reg[i], 1, 0, 0, 0x2); /* 0x2 set drv level 2 */
 | |
| +}
 | |
| +
 | |
| +static void bsp_set_io_config(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	unsigned int devid = bsp_priv->devid;
 | |
| +	void *iocfg_regmap = bsp_priv->iocfg_regmap;
 | |
| +	unsigned int reg = 0;
 | |
| +
 | |
| +	if (devid == 0) {
 | |
| +		/* For mmc0: eMMC and SD card */
 | |
| +		regmap_read(iocfg_regmap, REG_CTRL_EMMC_CLK, ®);
 | |
| +		if ((reg & IO_CFG_PIN_MUX_MASK) ==
 | |
| +			io_cfg_pin_mux_sel(IO_CFG_PIN_MUX_TYPE_CLK_EMMC))
 | |
| +			bsp_set_mmc_drv(host);
 | |
| +
 | |
| +		regmap_read(iocfg_regmap, REG_CTRL_SDIO0_CLK, ®);
 | |
| +		if ((reg & IO_CFG_PIN_MUX_MASK) ==
 | |
| +			io_cfg_pin_mux_sel(IO_CFG_PIN_MUX_TYPE_CLK_SD))
 | |
| +			bsp_set_sd_drv(host);
 | |
| +	} else {
 | |
| +		/* For mmc1: sdio wifi */
 | |
| +		bsp_set_sdio_drv(host);
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static void bsp_get_phase(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	unsigned int devid = bsp_priv->devid;
 | |
| +
 | |
| +	if (devid == 0) {
 | |
| +		/* For eMMC and SD card */
 | |
| +		if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
 | |
| +			bsp_priv->drv_phase = 9;   /* 9 for 101.25 degree */
 | |
| +			bsp_priv->sampl_phase = bsp_priv->tuning_phase;
 | |
| +		} else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200) {
 | |
| +			bsp_priv->drv_phase = 23;  /* 23 for 258.75 degree */
 | |
| +			bsp_priv->sampl_phase = bsp_priv->tuning_phase;
 | |
| +		} else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS) {
 | |
| +			bsp_priv->drv_phase = 16;  /* 16 for 180 degree */
 | |
| +			bsp_priv->sampl_phase = 4; /* 4 for 45 degree */
 | |
| +		} else if (host->mmc->ios.timing == MMC_TIMING_SD_HS) {
 | |
| +			bsp_priv->drv_phase = 20;  /* 20 for 225 degree */
 | |
| +			bsp_priv->sampl_phase = 4; /* 4 for 45 degree */
 | |
| +		} else if (host->mmc->ios.timing == MMC_TIMING_LEGACY) {
 | |
| +			bsp_priv->drv_phase = 16;  /* 16 for 180 degree */
 | |
| +			bsp_priv->sampl_phase = 0; /* 0 for 0 degree */
 | |
| +		} else if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) {
 | |
| +			bsp_priv->drv_phase = 8;   /* 8 for 90 degree */
 | |
| +			bsp_priv->sampl_phase = bsp_priv->tuning_phase;
 | |
| +		} else {
 | |
| +			bsp_priv->drv_phase = 16;  /* 16 for 180 degree */
 | |
| +			bsp_priv->sampl_phase = 0; /* 0 for 0 degree */
 | |
| +		}
 | |
| +	} else {
 | |
| +		/* For SDIO device */
 | |
| +		if ((host->mmc->ios.timing == MMC_TIMING_SD_HS) ||
 | |
| +			(host->mmc->ios.timing == MMC_TIMING_UHS_SDR25)) {
 | |
| +			bsp_priv->drv_phase = 16;  /* 16 for 180 degree */
 | |
| +			bsp_priv->sampl_phase = 4; /* 4 for 45 degree */
 | |
| +		} else {
 | |
| +			/* UHS_SDR12 */
 | |
| +			bsp_priv->drv_phase = 16;  /* 16 for 180 degree */
 | |
| +			bsp_priv->sampl_phase = 0; /* 0 for 0 degree */
 | |
| +		}
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int bsp_support_runtime_pm(struct sdhci_host *host)
 | |
| +{
 | |
| +	struct sdhci_bsp_priv *bsp_priv = sdhci_get_pltfm_priv(host);
 | |
| +	unsigned int devid = bsp_priv->devid;
 | |
| +
 | |
| +	/* Only enable for mmc0 eMMC and SD card */
 | |
| +	if (devid == 0)
 | |
| +		return 1;
 | |
| +	else
 | |
| +		return 0;
 | |
| +}
 | |
| +
 | |
| +#include "sdhci-goke.c"
 | |
| +#endif
 | |
| \ No newline at end of file
 |