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
|