Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2012, Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/mmc/host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/mmc/mmc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/of_gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include "dw_mmc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include "dw_mmc-pltfm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include "dw_mmc-exynos.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) /* Variations in Exynos specific dw-mshc controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) enum dw_mci_exynos_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	DW_MCI_TYPE_EXYNOS4210,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	DW_MCI_TYPE_EXYNOS4412,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	DW_MCI_TYPE_EXYNOS5250,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	DW_MCI_TYPE_EXYNOS5420,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	DW_MCI_TYPE_EXYNOS5420_SMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	DW_MCI_TYPE_EXYNOS7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	DW_MCI_TYPE_EXYNOS7_SMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) /* Exynos implementation specific driver private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) struct dw_mci_exynos_priv_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	enum dw_mci_exynos_type		ctrl_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	u8				ciu_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	u32				sdr_timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	u32				ddr_timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	u32				hs400_timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	u32				tuned_sample;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	u32				cur_speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	u32				dqs_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	u32				saved_dqs_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	u32				saved_strobe_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static struct dw_mci_exynos_compatible {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	char				*compatible;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	enum dw_mci_exynos_type		ctrl_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) } exynos_compat[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		.compatible	= "samsung,exynos4210-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS4210,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 		.compatible	= "samsung,exynos4412-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS4412,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		.compatible	= "samsung,exynos5250-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		.compatible	= "samsung,exynos5420-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS5420,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		.compatible	= "samsung,exynos5420-dw-mshc-smu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS5420_SMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		.compatible	= "samsung,exynos7-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		.compatible	= "samsung,exynos7-dw-mshc-smu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		.ctrl_type	= DW_MCI_TYPE_EXYNOS7_SMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		return EXYNOS4412_FIXED_CIU_CLK_DIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		return EXYNOS4210_FIXED_CIU_CLK_DIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) static void dw_mci_exynos_config_smu(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	 * If Exynos is provided the Security management,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	 * set for non-ecryption mode at this time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		mci_writel(host, MPSBEGIN0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 			   SDMMC_MPSCTRL_NON_SECURE_READ_BIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			   SDMMC_MPSCTRL_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 			   SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int dw_mci_exynos_priv_init(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	dw_mci_exynos_config_smu(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		if (!priv->dqs_delay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 			priv->dqs_delay =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 				DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	host->bus_hz /= (priv->ciu_div + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	u32 clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		clksel = mci_readl(host, CLKSEL64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		clksel = mci_readl(host, CLKSEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		mci_writel(host, CLKSEL64, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		mci_writel(host, CLKSEL, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	 * Exynos4412 and Exynos5250 extends the use of CMD register with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	 * use of bit 29 (which is reserved on standard MSHC controllers) for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	 * optionally bypassing the HOLD register for command and data. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	 * HOLD register should be bypassed in case there is no phase shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	 * applied on CMD/DATA that is sent to the card.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int dw_mci_exynos_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	struct dw_mci *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	ret = dw_mci_runtime_resume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	dw_mci_exynos_config_smu(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #endif /* CONFIG_PM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)  * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)  * @dev: Device to suspend (this device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)  * This ensures that device will be in runtime active state in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)  * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int dw_mci_exynos_suspend_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	pm_runtime_get_noresume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	return pm_runtime_force_suspend(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)  * dw_mci_exynos_resume_noirq - Exynos-specific resume code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)  * @dev: Device to resume (this device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)  * On exynos5420 there is a silicon errata that will sometimes leave the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)  * WAKEUP_INT bit in the CLKSEL register asserted.  This bit is 1 to indicate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)  * that it fired and we can clear it by writing a 1 back.  Clear it to prevent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)  * interrupts from going off constantly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)  * We run this code on all exynos variants because it doesn't hurt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int dw_mci_exynos_resume_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	struct dw_mci *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	u32 clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	ret = pm_runtime_force_resume(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		clksel = mci_readl(host, CLKSEL64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		clksel = mci_readl(host, CLKSEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 			mci_writel(host, CLKSEL64, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 			mci_writel(host, CLKSEL, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	pm_runtime_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	u32 dqs, strobe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	 * Not supported to configure register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	 * related to HS400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		if (timing == MMC_TIMING_MMC_HS400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 			dev_warn(host->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 				 "cannot configure HS400, unsupported chipset\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	dqs = priv->saved_dqs_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	strobe = priv->saved_strobe_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	if (timing == MMC_TIMING_MMC_HS400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		dqs |= DATA_STROBE_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	} else if (timing == MMC_TIMING_UHS_SDR104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		dqs &= 0xffffff00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		dqs &= ~DATA_STROBE_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	mci_writel(host, HS400_DQS_EN, dqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	mci_writel(host, HS400_DLINE_CTRL, strobe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	unsigned long actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	u8 div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	 * Don't care if wanted clock is zero or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	 * ciu clock is unavailable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	if (!wanted || IS_ERR(host->ciu_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	/* Guaranteed minimum frequency for cclkin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	if (wanted < EXYNOS_CCLKIN_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		wanted = EXYNOS_CCLKIN_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	if (wanted == priv->cur_speed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	div = dw_mci_exynos_get_ciu_div(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	ret = clk_set_rate(host->ciu_clk, wanted * div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		dev_warn(host->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 			"failed to set clk-rate %u error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			wanted * div, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	actual = clk_get_rate(host->ciu_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	host->bus_hz = actual / div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	priv->cur_speed = wanted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	host->current_speed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	unsigned int wanted = ios->clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	u32 timing = ios->timing, clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	switch (timing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	case MMC_TIMING_MMC_HS400:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		/* Update tuned sample timing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 		clksel = SDMMC_CLKSEL_UP_SAMPLE(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 				priv->hs400_timing, priv->tuned_sample);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 		wanted <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	case MMC_TIMING_MMC_DDR52:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		clksel = priv->ddr_timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		/* Should be double rate for DDR mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 		if (ios->bus_width == MMC_BUS_WIDTH_8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 			wanted <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	case MMC_TIMING_UHS_SDR104:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	case MMC_TIMING_UHS_SDR50:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		clksel = (priv->sdr_timing & 0xfff8ffff) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 			(priv->ciu_div << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	case MMC_TIMING_UHS_DDR50:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		clksel = (priv->ddr_timing & 0xfff8ffff) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			(priv->ciu_div << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		clksel = priv->sdr_timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	/* Set clock timing for the requested speed mode*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	dw_mci_exynos_set_clksel_timing(host, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	/* Configure setting for HS400 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	dw_mci_exynos_config_hs400(host, timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	/* Configure clock rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	dw_mci_exynos_adjust_clock(host, wanted);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static int dw_mci_exynos_parse_dt(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	struct dw_mci_exynos_priv_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	struct device_node *np = host->dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	u32 timing[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	u32 div = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		if (of_device_is_compatible(np, exynos_compat[idx].compatible))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 			priv->ctrl_type = exynos_compat[idx].ctrl_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		priv->ciu_div = div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	ret = of_property_read_u32_array(np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 			"samsung,dw-mshc-sdr-timing", timing, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	ret = of_property_read_u32_array(np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			"samsung,dw-mshc-ddr-timing", timing, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	ret = of_property_read_u32_array(np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 			"samsung,dw-mshc-hs400-timing", timing, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	if (!ret && of_property_read_u32(np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 				"samsung,read-strobe-delay", &priv->dqs_delay))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		dev_dbg(host->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			"read-strobe-delay is not found, assuming usage of default value\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 						HS400_FIXED_CIU_CLK_DIV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	host->priv = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 		return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	u32 clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		clksel = mci_readl(host, CLKSEL64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		clksel = mci_readl(host, CLKSEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		mci_writel(host, CLKSEL64, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 		mci_writel(host, CLKSEL, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	u32 clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	u8 sample;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		clksel = mci_readl(host, CLKSEL64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		clksel = mci_readl(host, CLKSEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	sample = (clksel + 1) & 0x7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 		mci_writel(host, CLKSEL64, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 		mci_writel(host, CLKSEL, clksel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	return sample;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	const u8 iter = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	u8 __c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	s8 i, loc = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	for (i = 0; i < iter; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 		__c = ror8(candiates, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		if ((__c & 0xc7) == 0xc7) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 			loc = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	for (i = 0; i < iter; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 		__c = ror8(candiates, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		if ((__c & 0x83) == 0x83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 			loc = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	 * If there is no cadiates value, then it needs to return -EIO.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	 * If there are candiates values and don't find bset clk sample value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	 * then use a first candiates clock sample value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	for (i = 0; i < iter; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		__c = ror8(candiates, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		if ((__c & 0x1) == 0x1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			loc = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	return loc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	struct dw_mci *host = slot->host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	struct mmc_host *mmc = slot->mmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	u8 start_smpl, smpl, candiates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	s8 found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	start_smpl = dw_mci_exynos_get_clksmpl(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 		mci_writel(host, TMOUT, ~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		smpl = dw_mci_exynos_move_next_clksmpl(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 		if (!mmc_send_tuning(mmc, opcode, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 			candiates |= (1 << smpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	} while (start_smpl != smpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	found = dw_mci_exynos_get_best_clksmpl(candiates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	if (found >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 		dw_mci_exynos_set_clksmpl(host, found);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 		priv->tuned_sample = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 		ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 		dev_warn(&mmc->class_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 			"There is no candiates value about clksmpl!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 					struct mmc_ios *ios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	struct dw_mci_exynos_priv_data *priv = host->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) /* Common capabilities of Exynos4/Exynos5 SoC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) static unsigned long exynos_dwmmc_caps[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	MMC_CAP_CMD23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	MMC_CAP_CMD23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	MMC_CAP_CMD23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static const struct dw_mci_drv_data exynos_drv_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	.caps			= exynos_dwmmc_caps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	.num_caps		= ARRAY_SIZE(exynos_dwmmc_caps),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	.init			= dw_mci_exynos_priv_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	.set_ios		= dw_mci_exynos_set_ios,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	.parse_dt		= dw_mci_exynos_parse_dt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	.execute_tuning		= dw_mci_exynos_execute_tuning,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	.prepare_hs400_tuning	= dw_mci_exynos_prepare_hs400_tuning,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static const struct of_device_id dw_mci_exynos_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	{ .compatible = "samsung,exynos4412-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	{ .compatible = "samsung,exynos5250-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	{ .compatible = "samsung,exynos5420-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	{ .compatible = "samsung,exynos5420-dw-mshc-smu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	{ .compatible = "samsung,exynos7-dw-mshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	{ .compatible = "samsung,exynos7-dw-mshc-smu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 			.data = &exynos_drv_data, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	{},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static int dw_mci_exynos_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 	const struct dw_mci_drv_data *drv_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 	match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	drv_data = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	pm_runtime_get_noresume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	pm_runtime_set_active(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 	pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	ret = dw_mci_pltfm_register(pdev, drv_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 		pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 		pm_runtime_set_suspended(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 		pm_runtime_put_noidle(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static int dw_mci_exynos_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 	pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	pm_runtime_set_suspended(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 	pm_runtime_put_noidle(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	return dw_mci_pltfm_remove(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static const struct dev_pm_ops dw_mci_exynos_pmops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 				      dw_mci_exynos_resume_noirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 			   dw_mci_exynos_runtime_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 			   NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static struct platform_driver dw_mci_exynos_pltfm_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 	.probe		= dw_mci_exynos_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	.remove		= dw_mci_exynos_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	.driver		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 		.name		= "dwmmc_exynos",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 		.of_match_table	= dw_mci_exynos_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 		.pm		= &dw_mci_exynos_pmops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) module_platform_driver(dw_mci_exynos_pltfm_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) MODULE_ALIAS("platform:dwmmc_exynos");