xref: /rk3399_rockchip-uboot/drivers/mmc/omap_hsmmc.c (revision a9d6a7e23a67a7eb53f0c138868e2a3af8e37d25)
1de941241SSukumar Ghorai /*
2de941241SSukumar Ghorai  * (C) Copyright 2008
3de941241SSukumar Ghorai  * Texas Instruments, <www.ti.com>
4de941241SSukumar Ghorai  * Sukumar Ghorai <s-ghorai@ti.com>
5de941241SSukumar Ghorai  *
6de941241SSukumar Ghorai  * See file CREDITS for list of people who contributed to this
7de941241SSukumar Ghorai  * project.
8de941241SSukumar Ghorai  *
9de941241SSukumar Ghorai  * This program is free software; you can redistribute it and/or
10de941241SSukumar Ghorai  * modify it under the terms of the GNU General Public License as
11de941241SSukumar Ghorai  * published by the Free Software Foundation's version 2 of
12de941241SSukumar Ghorai  * the License.
13de941241SSukumar Ghorai  *
14de941241SSukumar Ghorai  * This program is distributed in the hope that it will be useful,
15de941241SSukumar Ghorai  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16de941241SSukumar Ghorai  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17de941241SSukumar Ghorai  * GNU General Public License for more details.
18de941241SSukumar Ghorai  *
19de941241SSukumar Ghorai  * You should have received a copy of the GNU General Public License
20de941241SSukumar Ghorai  * along with this program; if not, write to the Free Software
21de941241SSukumar Ghorai  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22de941241SSukumar Ghorai  * MA 02111-1307 USA
23de941241SSukumar Ghorai  */
24de941241SSukumar Ghorai 
25de941241SSukumar Ghorai #include <config.h>
26de941241SSukumar Ghorai #include <common.h>
2793bfd616SPantelis Antoniou #include <malloc.h>
28de941241SSukumar Ghorai #include <mmc.h>
29de941241SSukumar Ghorai #include <part.h>
30de941241SSukumar Ghorai #include <i2c.h>
31de941241SSukumar Ghorai #include <twl4030.h>
3214fa2dd0SBalaji T K #include <twl6030.h>
33cb199102SNishanth Menon #include <palmas.h>
34de941241SSukumar Ghorai #include <asm/io.h>
35de941241SSukumar Ghorai #include <asm/arch/mmc_host_def.h>
363b68939fSRoger Quadros #if !defined(CONFIG_SOC_KEYSTONE)
373b68939fSRoger Quadros #include <asm/gpio.h>
3896e0e7b3SDirk Behme #include <asm/arch/sys_proto.h>
393b68939fSRoger Quadros #endif
40*a9d6a7e2SMugunthan V N #include <dm.h>
41*a9d6a7e2SMugunthan V N 
42*a9d6a7e2SMugunthan V N DECLARE_GLOBAL_DATA_PTR;
43de941241SSukumar Ghorai 
44ab769f22SPantelis Antoniou /* simplify defines to OMAP_HSMMC_USE_GPIO */
45ab769f22SPantelis Antoniou #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
46ab769f22SPantelis Antoniou 	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
47ab769f22SPantelis Antoniou #define OMAP_HSMMC_USE_GPIO
48ab769f22SPantelis Antoniou #else
49ab769f22SPantelis Antoniou #undef OMAP_HSMMC_USE_GPIO
50ab769f22SPantelis Antoniou #endif
51ab769f22SPantelis Antoniou 
5225c719e2SGrazvydas Ignotas /* common definitions for all OMAPs */
5325c719e2SGrazvydas Ignotas #define SYSCTL_SRC	(1 << 25)
5425c719e2SGrazvydas Ignotas #define SYSCTL_SRD	(1 << 26)
5525c719e2SGrazvydas Ignotas 
56cc22b0c0SNikita Kiryanov struct omap_hsmmc_data {
57cc22b0c0SNikita Kiryanov 	struct hsmmc *base_addr;
5893bfd616SPantelis Antoniou 	struct mmc_config cfg;
59ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
60*a9d6a7e2SMugunthan V N #ifdef CONFIG_DM_MMC
61*a9d6a7e2SMugunthan V N 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
62*a9d6a7e2SMugunthan V N 	struct gpio_desc wp_gpio;	/* Write Protect GPIO */
63*a9d6a7e2SMugunthan V N 	bool cd_inverted;
64*a9d6a7e2SMugunthan V N #else
65e874d5b0SNikita Kiryanov 	int cd_gpio;
66e3913f56SNikita Kiryanov 	int wp_gpio;
67ab769f22SPantelis Antoniou #endif
68*a9d6a7e2SMugunthan V N #endif
69cc22b0c0SNikita Kiryanov };
70cc22b0c0SNikita Kiryanov 
71eb9a28f6SNishanth Menon /* If we fail after 1 second wait, something is really bad */
72eb9a28f6SNishanth Menon #define MAX_RETRY_MS	1000
73eb9a28f6SNishanth Menon 
74933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
75933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
76933efe64SSricharan 			unsigned int siz);
7714fa2dd0SBalaji T K 
78*a9d6a7e2SMugunthan V N #if defined(OMAP_HSMMC_USE_GPIO) && !defined(CONFIG_DM_MMC)
79e874d5b0SNikita Kiryanov static int omap_mmc_setup_gpio_in(int gpio, const char *label)
80e874d5b0SNikita Kiryanov {
815915a2adSSimon Glass 	int ret;
825915a2adSSimon Glass 
835915a2adSSimon Glass #ifndef CONFIG_DM_GPIO
84e874d5b0SNikita Kiryanov 	if (!gpio_is_valid(gpio))
85e874d5b0SNikita Kiryanov 		return -1;
865915a2adSSimon Glass #endif
875915a2adSSimon Glass 	ret = gpio_request(gpio, label);
885915a2adSSimon Glass 	if (ret)
895915a2adSSimon Glass 		return ret;
90e874d5b0SNikita Kiryanov 
915915a2adSSimon Glass 	ret = gpio_direction_input(gpio);
925915a2adSSimon Glass 	if (ret)
935915a2adSSimon Glass 		return ret;
94e874d5b0SNikita Kiryanov 
95e874d5b0SNikita Kiryanov 	return gpio;
96e874d5b0SNikita Kiryanov }
97e874d5b0SNikita Kiryanov #endif
98e874d5b0SNikita Kiryanov 
9914fa2dd0SBalaji T K #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
10014fa2dd0SBalaji T K static void omap4_vmmc_pbias_config(struct mmc *mmc)
10114fa2dd0SBalaji T K {
10214fa2dd0SBalaji T K 	u32 value = 0;
10314fa2dd0SBalaji T K 
104c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbiaslite);
10514fa2dd0SBalaji T K 	value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
106c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbiaslite);
10714fa2dd0SBalaji T K 	/* set VMMC to 3V */
10814fa2dd0SBalaji T K 	twl6030_power_mmc_init();
109c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbiaslite);
11014fa2dd0SBalaji T K 	value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
111c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbiaslite);
11214fa2dd0SBalaji T K }
11314fa2dd0SBalaji T K #endif
11414fa2dd0SBalaji T K 
115cb199102SNishanth Menon #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
116dd23e59dSBalaji T K static void omap5_pbias_config(struct mmc *mmc)
117dd23e59dSBalaji T K {
118dd23e59dSBalaji T K 	u32 value = 0;
119dd23e59dSBalaji T K 
120c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbias);
121a5d439c2SBalaji T K 	value &= ~SDCARD_PWRDNZ;
122a5d439c2SBalaji T K 	writel(value, (*ctrl)->control_pbias);
123a5d439c2SBalaji T K 	udelay(10); /* wait 10 us */
124a5d439c2SBalaji T K 	value &= ~SDCARD_BIAS_PWRDNZ;
125c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
126dd23e59dSBalaji T K 
127384bcae0SNishanth Menon 	palmas_mmc1_poweron_ldo();
128dd23e59dSBalaji T K 
129c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbias);
130a5d439c2SBalaji T K 	value |= SDCARD_BIAS_PWRDNZ;
131c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
132a5d439c2SBalaji T K 	udelay(150); /* wait 150 us */
133a5d439c2SBalaji T K 	value |= SDCARD_PWRDNZ;
134c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
135a5d439c2SBalaji T K 	udelay(150); /* wait 150 us */
136dd23e59dSBalaji T K }
137dd23e59dSBalaji T K #endif
138dd23e59dSBalaji T K 
139750121c3SJeroen Hofstee static unsigned char mmc_board_init(struct mmc *mmc)
140de941241SSukumar Ghorai {
141de941241SSukumar Ghorai #if defined(CONFIG_OMAP34XX)
142de941241SSukumar Ghorai 	t2_t *t2_base = (t2_t *)T2_BASE;
143de941241SSukumar Ghorai 	struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
144b1e725f2SGrazvydas Ignotas 	u32 pbias_lite;
145de941241SSukumar Ghorai 
146b1e725f2SGrazvydas Ignotas 	pbias_lite = readl(&t2_base->pbias_lite);
147b1e725f2SGrazvydas Ignotas 	pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
1485bfdd1fcSAlbert ARIBAUD \(3ADEV\) #ifdef CONFIG_TARGET_OMAP3_CAIRO
1495bfdd1fcSAlbert ARIBAUD \(3ADEV\) 	/* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
1505bfdd1fcSAlbert ARIBAUD \(3ADEV\) 	pbias_lite &= ~PBIASLITEVMODE0;
1515bfdd1fcSAlbert ARIBAUD \(3ADEV\) #endif
152b1e725f2SGrazvydas Ignotas 	writel(pbias_lite, &t2_base->pbias_lite);
153aac5450eSPaul Kocialkowski 
154b1e725f2SGrazvydas Ignotas 	writel(pbias_lite | PBIASLITEPWRDNZ1 |
155de941241SSukumar Ghorai 		PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
156de941241SSukumar Ghorai 		&t2_base->pbias_lite);
157de941241SSukumar Ghorai 
158de941241SSukumar Ghorai 	writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
159de941241SSukumar Ghorai 		&t2_base->devconf0);
160de941241SSukumar Ghorai 
161de941241SSukumar Ghorai 	writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
162de941241SSukumar Ghorai 		&t2_base->devconf1);
163de941241SSukumar Ghorai 
164bbbc1ae9SJonathan Solnit 	/* Change from default of 52MHz to 26MHz if necessary */
16593bfd616SPantelis Antoniou 	if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz))
166bbbc1ae9SJonathan Solnit 		writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
167bbbc1ae9SJonathan Solnit 			&t2_base->ctl_prog_io1);
168bbbc1ae9SJonathan Solnit 
169de941241SSukumar Ghorai 	writel(readl(&prcm_base->fclken1_core) |
170de941241SSukumar Ghorai 		EN_MMC1 | EN_MMC2 | EN_MMC3,
171de941241SSukumar Ghorai 		&prcm_base->fclken1_core);
172de941241SSukumar Ghorai 
173de941241SSukumar Ghorai 	writel(readl(&prcm_base->iclken1_core) |
174de941241SSukumar Ghorai 		EN_MMC1 | EN_MMC2 | EN_MMC3,
175de941241SSukumar Ghorai 		&prcm_base->iclken1_core);
176de941241SSukumar Ghorai #endif
177de941241SSukumar Ghorai 
17814fa2dd0SBalaji T K #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
17914fa2dd0SBalaji T K 	/* PBIAS config needed for MMC1 only */
18014fa2dd0SBalaji T K 	if (mmc->block_dev.dev == 0)
18114fa2dd0SBalaji T K 		omap4_vmmc_pbias_config(mmc);
18214fa2dd0SBalaji T K #endif
183cb199102SNishanth Menon #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
184dd23e59dSBalaji T K 	if (mmc->block_dev.dev == 0)
185dd23e59dSBalaji T K 		omap5_pbias_config(mmc);
186dd23e59dSBalaji T K #endif
187de941241SSukumar Ghorai 
188de941241SSukumar Ghorai 	return 0;
189de941241SSukumar Ghorai }
190de941241SSukumar Ghorai 
191933efe64SSricharan void mmc_init_stream(struct hsmmc *mmc_base)
192de941241SSukumar Ghorai {
193eb9a28f6SNishanth Menon 	ulong start;
194de941241SSukumar Ghorai 
195de941241SSukumar Ghorai 	writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
196de941241SSukumar Ghorai 
197de941241SSukumar Ghorai 	writel(MMC_CMD0, &mmc_base->cmd);
198eb9a28f6SNishanth Menon 	start = get_timer(0);
199eb9a28f6SNishanth Menon 	while (!(readl(&mmc_base->stat) & CC_MASK)) {
200eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
201eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc!\n", __func__);
202eb9a28f6SNishanth Menon 			return;
203eb9a28f6SNishanth Menon 		}
204eb9a28f6SNishanth Menon 	}
205de941241SSukumar Ghorai 	writel(CC_MASK, &mmc_base->stat)
206de941241SSukumar Ghorai 		;
207de941241SSukumar Ghorai 	writel(MMC_CMD0, &mmc_base->cmd)
208de941241SSukumar Ghorai 		;
209eb9a28f6SNishanth Menon 	start = get_timer(0);
210eb9a28f6SNishanth Menon 	while (!(readl(&mmc_base->stat) & CC_MASK)) {
211eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
212eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc2!\n", __func__);
213eb9a28f6SNishanth Menon 			return;
214eb9a28f6SNishanth Menon 		}
215eb9a28f6SNishanth Menon 	}
216de941241SSukumar Ghorai 	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
217de941241SSukumar Ghorai }
218de941241SSukumar Ghorai 
219de941241SSukumar Ghorai 
220ab769f22SPantelis Antoniou static int omap_hsmmc_init_setup(struct mmc *mmc)
221de941241SSukumar Ghorai {
222cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
223de941241SSukumar Ghorai 	unsigned int reg_val;
224de941241SSukumar Ghorai 	unsigned int dsor;
225eb9a28f6SNishanth Menon 	ulong start;
226de941241SSukumar Ghorai 
227cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
22814fa2dd0SBalaji T K 	mmc_board_init(mmc);
229de941241SSukumar Ghorai 
230de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
231de941241SSukumar Ghorai 		&mmc_base->sysconfig);
232eb9a28f6SNishanth Menon 	start = get_timer(0);
233eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
234eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
235eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc2!\n", __func__);
236eb9a28f6SNishanth Menon 			return TIMEOUT;
237eb9a28f6SNishanth Menon 		}
238eb9a28f6SNishanth Menon 	}
239de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
240eb9a28f6SNishanth Menon 	start = get_timer(0);
241eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
242eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
243eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for softresetall!\n",
244eb9a28f6SNishanth Menon 				__func__);
245eb9a28f6SNishanth Menon 			return TIMEOUT;
246eb9a28f6SNishanth Menon 		}
247eb9a28f6SNishanth Menon 	}
248de941241SSukumar Ghorai 	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
249de941241SSukumar Ghorai 	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
250de941241SSukumar Ghorai 		&mmc_base->capa);
251de941241SSukumar Ghorai 
252de941241SSukumar Ghorai 	reg_val = readl(&mmc_base->con) & RESERVED_MASK;
253de941241SSukumar Ghorai 
254de941241SSukumar Ghorai 	writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
255de941241SSukumar Ghorai 		MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
256de941241SSukumar Ghorai 		HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
257de941241SSukumar Ghorai 
258de941241SSukumar Ghorai 	dsor = 240;
259de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
260de941241SSukumar Ghorai 		(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
261de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
262de941241SSukumar Ghorai 		(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
263eb9a28f6SNishanth Menon 	start = get_timer(0);
264eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
265eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
266eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for ics!\n", __func__);
267eb9a28f6SNishanth Menon 			return TIMEOUT;
268eb9a28f6SNishanth Menon 		}
269eb9a28f6SNishanth Menon 	}
270de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
271de941241SSukumar Ghorai 
272de941241SSukumar Ghorai 	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
273de941241SSukumar Ghorai 
274de941241SSukumar Ghorai 	writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
275de941241SSukumar Ghorai 		IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
276de941241SSukumar Ghorai 		&mmc_base->ie);
277de941241SSukumar Ghorai 
278de941241SSukumar Ghorai 	mmc_init_stream(mmc_base);
279de941241SSukumar Ghorai 
280de941241SSukumar Ghorai 	return 0;
281de941241SSukumar Ghorai }
282de941241SSukumar Ghorai 
28325c719e2SGrazvydas Ignotas /*
28425c719e2SGrazvydas Ignotas  * MMC controller internal finite state machine reset
28525c719e2SGrazvydas Ignotas  *
28625c719e2SGrazvydas Ignotas  * Used to reset command or data internal state machines, using respectively
28725c719e2SGrazvydas Ignotas  * SRC or SRD bit of SYSCTL register
28825c719e2SGrazvydas Ignotas  */
28925c719e2SGrazvydas Ignotas static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
29025c719e2SGrazvydas Ignotas {
29125c719e2SGrazvydas Ignotas 	ulong start;
29225c719e2SGrazvydas Ignotas 
29325c719e2SGrazvydas Ignotas 	mmc_reg_out(&mmc_base->sysctl, bit, bit);
29425c719e2SGrazvydas Ignotas 
29561a6cc27SOleksandr Tyshchenko 	/*
29661a6cc27SOleksandr Tyshchenko 	 * CMD(DAT) lines reset procedures are slightly different
29761a6cc27SOleksandr Tyshchenko 	 * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
29861a6cc27SOleksandr Tyshchenko 	 * According to OMAP3 TRM:
29961a6cc27SOleksandr Tyshchenko 	 * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
30061a6cc27SOleksandr Tyshchenko 	 * returns to 0x0.
30161a6cc27SOleksandr Tyshchenko 	 * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
30261a6cc27SOleksandr Tyshchenko 	 * procedure steps must be as follows:
30361a6cc27SOleksandr Tyshchenko 	 * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
30461a6cc27SOleksandr Tyshchenko 	 *    MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
30561a6cc27SOleksandr Tyshchenko 	 * 2. Poll the SRC(SRD) bit until it is set to 0x1.
30661a6cc27SOleksandr Tyshchenko 	 * 3. Wait until the SRC (SRD) bit returns to 0x0
30761a6cc27SOleksandr Tyshchenko 	 *    (reset procedure is completed).
30861a6cc27SOleksandr Tyshchenko 	 */
30961a6cc27SOleksandr Tyshchenko #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
310dce55b93SNikita Kiryanov 	defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
31161a6cc27SOleksandr Tyshchenko 	if (!(readl(&mmc_base->sysctl) & bit)) {
31261a6cc27SOleksandr Tyshchenko 		start = get_timer(0);
31361a6cc27SOleksandr Tyshchenko 		while (!(readl(&mmc_base->sysctl) & bit)) {
31461a6cc27SOleksandr Tyshchenko 			if (get_timer(0) - start > MAX_RETRY_MS)
31561a6cc27SOleksandr Tyshchenko 				return;
31661a6cc27SOleksandr Tyshchenko 		}
31761a6cc27SOleksandr Tyshchenko 	}
31861a6cc27SOleksandr Tyshchenko #endif
31925c719e2SGrazvydas Ignotas 	start = get_timer(0);
32025c719e2SGrazvydas Ignotas 	while ((readl(&mmc_base->sysctl) & bit) != 0) {
32125c719e2SGrazvydas Ignotas 		if (get_timer(0) - start > MAX_RETRY_MS) {
32225c719e2SGrazvydas Ignotas 			printf("%s: timedout waiting for sysctl %x to clear\n",
32325c719e2SGrazvydas Ignotas 				__func__, bit);
32425c719e2SGrazvydas Ignotas 			return;
32525c719e2SGrazvydas Ignotas 		}
32625c719e2SGrazvydas Ignotas 	}
32725c719e2SGrazvydas Ignotas }
328de941241SSukumar Ghorai 
329ab769f22SPantelis Antoniou static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
330de941241SSukumar Ghorai 			struct mmc_data *data)
331de941241SSukumar Ghorai {
332cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
333de941241SSukumar Ghorai 	unsigned int flags, mmc_stat;
334eb9a28f6SNishanth Menon 	ulong start;
335de941241SSukumar Ghorai 
336cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
337eb9a28f6SNishanth Menon 	start = get_timer(0);
338a7778f8fSTom Rini 	while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
339eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
340a7778f8fSTom Rini 			printf("%s: timedout waiting on cmd inhibit to clear\n",
341a7778f8fSTom Rini 					__func__);
342eb9a28f6SNishanth Menon 			return TIMEOUT;
343eb9a28f6SNishanth Menon 		}
344eb9a28f6SNishanth Menon 	}
345de941241SSukumar Ghorai 	writel(0xFFFFFFFF, &mmc_base->stat);
346eb9a28f6SNishanth Menon 	start = get_timer(0);
347eb9a28f6SNishanth Menon 	while (readl(&mmc_base->stat)) {
348eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
34915ceb1deSGrazvydas Ignotas 			printf("%s: timedout waiting for STAT (%x) to clear\n",
35015ceb1deSGrazvydas Ignotas 				__func__, readl(&mmc_base->stat));
351eb9a28f6SNishanth Menon 			return TIMEOUT;
352eb9a28f6SNishanth Menon 		}
353eb9a28f6SNishanth Menon 	}
354de941241SSukumar Ghorai 	/*
355de941241SSukumar Ghorai 	 * CMDREG
356de941241SSukumar Ghorai 	 * CMDIDX[13:8]	: Command index
357de941241SSukumar Ghorai 	 * DATAPRNT[5]	: Data Present Select
358de941241SSukumar Ghorai 	 * ENCMDIDX[4]	: Command Index Check Enable
359de941241SSukumar Ghorai 	 * ENCMDCRC[3]	: Command CRC Check Enable
360de941241SSukumar Ghorai 	 * RSPTYP[1:0]
361de941241SSukumar Ghorai 	 *	00 = No Response
362de941241SSukumar Ghorai 	 *	01 = Length 136
363de941241SSukumar Ghorai 	 *	10 = Length 48
364de941241SSukumar Ghorai 	 *	11 = Length 48 Check busy after response
365de941241SSukumar Ghorai 	 */
366de941241SSukumar Ghorai 	/* Delay added before checking the status of frq change
367de941241SSukumar Ghorai 	 * retry not supported by mmc.c(core file)
368de941241SSukumar Ghorai 	 */
369de941241SSukumar Ghorai 	if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
370de941241SSukumar Ghorai 		udelay(50000); /* wait 50 ms */
371de941241SSukumar Ghorai 
372de941241SSukumar Ghorai 	if (!(cmd->resp_type & MMC_RSP_PRESENT))
373de941241SSukumar Ghorai 		flags = 0;
374de941241SSukumar Ghorai 	else if (cmd->resp_type & MMC_RSP_136)
375de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
376de941241SSukumar Ghorai 	else if (cmd->resp_type & MMC_RSP_BUSY)
377de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT48B;
378de941241SSukumar Ghorai 	else
379de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT48;
380de941241SSukumar Ghorai 
381de941241SSukumar Ghorai 	/* enable default flags */
382de941241SSukumar Ghorai 	flags =	flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
383de941241SSukumar Ghorai 			MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
384de941241SSukumar Ghorai 
385de941241SSukumar Ghorai 	if (cmd->resp_type & MMC_RSP_CRC)
386de941241SSukumar Ghorai 		flags |= CCCE_CHECK;
387de941241SSukumar Ghorai 	if (cmd->resp_type & MMC_RSP_OPCODE)
388de941241SSukumar Ghorai 		flags |= CICE_CHECK;
389de941241SSukumar Ghorai 
390de941241SSukumar Ghorai 	if (data) {
391de941241SSukumar Ghorai 		if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
392de941241SSukumar Ghorai 			 (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
393de941241SSukumar Ghorai 			flags |= (MSBS_MULTIBLK | BCE_ENABLE);
394de941241SSukumar Ghorai 			data->blocksize = 512;
395de941241SSukumar Ghorai 			writel(data->blocksize | (data->blocks << 16),
396de941241SSukumar Ghorai 							&mmc_base->blk);
397de941241SSukumar Ghorai 		} else
398de941241SSukumar Ghorai 			writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
399de941241SSukumar Ghorai 
400de941241SSukumar Ghorai 		if (data->flags & MMC_DATA_READ)
401de941241SSukumar Ghorai 			flags |= (DP_DATA | DDIR_READ);
402de941241SSukumar Ghorai 		else
403de941241SSukumar Ghorai 			flags |= (DP_DATA | DDIR_WRITE);
404de941241SSukumar Ghorai 	}
405de941241SSukumar Ghorai 
406de941241SSukumar Ghorai 	writel(cmd->cmdarg, &mmc_base->arg);
407152ba363SLubomir Popov 	udelay(20);		/* To fix "No status update" error on eMMC */
408de941241SSukumar Ghorai 	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
409de941241SSukumar Ghorai 
410eb9a28f6SNishanth Menon 	start = get_timer(0);
411de941241SSukumar Ghorai 	do {
412de941241SSukumar Ghorai 		mmc_stat = readl(&mmc_base->stat);
413eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
414de941241SSukumar Ghorai 			printf("%s : timeout: No status update\n", __func__);
415de941241SSukumar Ghorai 			return TIMEOUT;
416de941241SSukumar Ghorai 		}
417eb9a28f6SNishanth Menon 	} while (!mmc_stat);
418de941241SSukumar Ghorai 
41925c719e2SGrazvydas Ignotas 	if ((mmc_stat & IE_CTO) != 0) {
42025c719e2SGrazvydas Ignotas 		mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
421de941241SSukumar Ghorai 		return TIMEOUT;
42225c719e2SGrazvydas Ignotas 	} else if ((mmc_stat & ERRI_MASK) != 0)
423de941241SSukumar Ghorai 		return -1;
424de941241SSukumar Ghorai 
425de941241SSukumar Ghorai 	if (mmc_stat & CC_MASK) {
426de941241SSukumar Ghorai 		writel(CC_MASK, &mmc_base->stat);
427de941241SSukumar Ghorai 		if (cmd->resp_type & MMC_RSP_PRESENT) {
428de941241SSukumar Ghorai 			if (cmd->resp_type & MMC_RSP_136) {
429de941241SSukumar Ghorai 				/* response type 2 */
430de941241SSukumar Ghorai 				cmd->response[3] = readl(&mmc_base->rsp10);
431de941241SSukumar Ghorai 				cmd->response[2] = readl(&mmc_base->rsp32);
432de941241SSukumar Ghorai 				cmd->response[1] = readl(&mmc_base->rsp54);
433de941241SSukumar Ghorai 				cmd->response[0] = readl(&mmc_base->rsp76);
434de941241SSukumar Ghorai 			} else
435de941241SSukumar Ghorai 				/* response types 1, 1b, 3, 4, 5, 6 */
436de941241SSukumar Ghorai 				cmd->response[0] = readl(&mmc_base->rsp10);
437de941241SSukumar Ghorai 		}
438de941241SSukumar Ghorai 	}
439de941241SSukumar Ghorai 
440de941241SSukumar Ghorai 	if (data && (data->flags & MMC_DATA_READ)) {
441de941241SSukumar Ghorai 		mmc_read_data(mmc_base,	data->dest,
442de941241SSukumar Ghorai 				data->blocksize * data->blocks);
443de941241SSukumar Ghorai 	} else if (data && (data->flags & MMC_DATA_WRITE)) {
444de941241SSukumar Ghorai 		mmc_write_data(mmc_base, data->src,
445de941241SSukumar Ghorai 				data->blocksize * data->blocks);
446de941241SSukumar Ghorai 	}
447de941241SSukumar Ghorai 	return 0;
448de941241SSukumar Ghorai }
449de941241SSukumar Ghorai 
450933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
451de941241SSukumar Ghorai {
452de941241SSukumar Ghorai 	unsigned int *output_buf = (unsigned int *)buf;
453de941241SSukumar Ghorai 	unsigned int mmc_stat;
454de941241SSukumar Ghorai 	unsigned int count;
455de941241SSukumar Ghorai 
456de941241SSukumar Ghorai 	/*
457de941241SSukumar Ghorai 	 * Start Polled Read
458de941241SSukumar Ghorai 	 */
459de941241SSukumar Ghorai 	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
460de941241SSukumar Ghorai 	count /= 4;
461de941241SSukumar Ghorai 
462de941241SSukumar Ghorai 	while (size) {
463eb9a28f6SNishanth Menon 		ulong start = get_timer(0);
464de941241SSukumar Ghorai 		do {
465de941241SSukumar Ghorai 			mmc_stat = readl(&mmc_base->stat);
466eb9a28f6SNishanth Menon 			if (get_timer(0) - start > MAX_RETRY_MS) {
467eb9a28f6SNishanth Menon 				printf("%s: timedout waiting for status!\n",
468eb9a28f6SNishanth Menon 						__func__);
469eb9a28f6SNishanth Menon 				return TIMEOUT;
470eb9a28f6SNishanth Menon 			}
471de941241SSukumar Ghorai 		} while (mmc_stat == 0);
472de941241SSukumar Ghorai 
47325c719e2SGrazvydas Ignotas 		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
47425c719e2SGrazvydas Ignotas 			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
47525c719e2SGrazvydas Ignotas 
476de941241SSukumar Ghorai 		if ((mmc_stat & ERRI_MASK) != 0)
477de941241SSukumar Ghorai 			return 1;
478de941241SSukumar Ghorai 
479de941241SSukumar Ghorai 		if (mmc_stat & BRR_MASK) {
480de941241SSukumar Ghorai 			unsigned int k;
481de941241SSukumar Ghorai 
482de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BRR_MASK,
483de941241SSukumar Ghorai 				&mmc_base->stat);
484de941241SSukumar Ghorai 			for (k = 0; k < count; k++) {
485de941241SSukumar Ghorai 				*output_buf = readl(&mmc_base->data);
486de941241SSukumar Ghorai 				output_buf++;
487de941241SSukumar Ghorai 			}
488de941241SSukumar Ghorai 			size -= (count*4);
489de941241SSukumar Ghorai 		}
490de941241SSukumar Ghorai 
491de941241SSukumar Ghorai 		if (mmc_stat & BWR_MASK)
492de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BWR_MASK,
493de941241SSukumar Ghorai 				&mmc_base->stat);
494de941241SSukumar Ghorai 
495de941241SSukumar Ghorai 		if (mmc_stat & TC_MASK) {
496de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | TC_MASK,
497de941241SSukumar Ghorai 				&mmc_base->stat);
498de941241SSukumar Ghorai 			break;
499de941241SSukumar Ghorai 		}
500de941241SSukumar Ghorai 	}
501de941241SSukumar Ghorai 	return 0;
502de941241SSukumar Ghorai }
503de941241SSukumar Ghorai 
504933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
505933efe64SSricharan 				unsigned int size)
506de941241SSukumar Ghorai {
507de941241SSukumar Ghorai 	unsigned int *input_buf = (unsigned int *)buf;
508de941241SSukumar Ghorai 	unsigned int mmc_stat;
509de941241SSukumar Ghorai 	unsigned int count;
510de941241SSukumar Ghorai 
511de941241SSukumar Ghorai 	/*
512152ba363SLubomir Popov 	 * Start Polled Write
513de941241SSukumar Ghorai 	 */
514de941241SSukumar Ghorai 	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
515de941241SSukumar Ghorai 	count /= 4;
516de941241SSukumar Ghorai 
517de941241SSukumar Ghorai 	while (size) {
518eb9a28f6SNishanth Menon 		ulong start = get_timer(0);
519de941241SSukumar Ghorai 		do {
520de941241SSukumar Ghorai 			mmc_stat = readl(&mmc_base->stat);
521eb9a28f6SNishanth Menon 			if (get_timer(0) - start > MAX_RETRY_MS) {
522eb9a28f6SNishanth Menon 				printf("%s: timedout waiting for status!\n",
523eb9a28f6SNishanth Menon 						__func__);
524eb9a28f6SNishanth Menon 				return TIMEOUT;
525eb9a28f6SNishanth Menon 			}
526de941241SSukumar Ghorai 		} while (mmc_stat == 0);
527de941241SSukumar Ghorai 
52825c719e2SGrazvydas Ignotas 		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
52925c719e2SGrazvydas Ignotas 			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
53025c719e2SGrazvydas Ignotas 
531de941241SSukumar Ghorai 		if ((mmc_stat & ERRI_MASK) != 0)
532de941241SSukumar Ghorai 			return 1;
533de941241SSukumar Ghorai 
534de941241SSukumar Ghorai 		if (mmc_stat & BWR_MASK) {
535de941241SSukumar Ghorai 			unsigned int k;
536de941241SSukumar Ghorai 
537de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BWR_MASK,
538de941241SSukumar Ghorai 					&mmc_base->stat);
539de941241SSukumar Ghorai 			for (k = 0; k < count; k++) {
540de941241SSukumar Ghorai 				writel(*input_buf, &mmc_base->data);
541de941241SSukumar Ghorai 				input_buf++;
542de941241SSukumar Ghorai 			}
543de941241SSukumar Ghorai 			size -= (count*4);
544de941241SSukumar Ghorai 		}
545de941241SSukumar Ghorai 
546de941241SSukumar Ghorai 		if (mmc_stat & BRR_MASK)
547de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BRR_MASK,
548de941241SSukumar Ghorai 				&mmc_base->stat);
549de941241SSukumar Ghorai 
550de941241SSukumar Ghorai 		if (mmc_stat & TC_MASK) {
551de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | TC_MASK,
552de941241SSukumar Ghorai 				&mmc_base->stat);
553de941241SSukumar Ghorai 			break;
554de941241SSukumar Ghorai 		}
555de941241SSukumar Ghorai 	}
556de941241SSukumar Ghorai 	return 0;
557de941241SSukumar Ghorai }
558de941241SSukumar Ghorai 
559ab769f22SPantelis Antoniou static void omap_hsmmc_set_ios(struct mmc *mmc)
560de941241SSukumar Ghorai {
561cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
562de941241SSukumar Ghorai 	unsigned int dsor = 0;
563eb9a28f6SNishanth Menon 	ulong start;
564de941241SSukumar Ghorai 
565cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
566de941241SSukumar Ghorai 	/* configue bus width */
567de941241SSukumar Ghorai 	switch (mmc->bus_width) {
568de941241SSukumar Ghorai 	case 8:
569de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) | DTW_8_BITMODE,
570de941241SSukumar Ghorai 			&mmc_base->con);
571de941241SSukumar Ghorai 		break;
572de941241SSukumar Ghorai 
573de941241SSukumar Ghorai 	case 4:
574de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
575de941241SSukumar Ghorai 			&mmc_base->con);
576de941241SSukumar Ghorai 		writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
577de941241SSukumar Ghorai 			&mmc_base->hctl);
578de941241SSukumar Ghorai 		break;
579de941241SSukumar Ghorai 
580de941241SSukumar Ghorai 	case 1:
581de941241SSukumar Ghorai 	default:
582de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
583de941241SSukumar Ghorai 			&mmc_base->con);
584de941241SSukumar Ghorai 		writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
585de941241SSukumar Ghorai 			&mmc_base->hctl);
586de941241SSukumar Ghorai 		break;
587de941241SSukumar Ghorai 	}
588de941241SSukumar Ghorai 
589de941241SSukumar Ghorai 	/* configure clock with 96Mhz system clock.
590de941241SSukumar Ghorai 	 */
591de941241SSukumar Ghorai 	if (mmc->clock != 0) {
592de941241SSukumar Ghorai 		dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock);
593de941241SSukumar Ghorai 		if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock)
594de941241SSukumar Ghorai 			dsor++;
595de941241SSukumar Ghorai 	}
596de941241SSukumar Ghorai 
597de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
598de941241SSukumar Ghorai 				(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
599de941241SSukumar Ghorai 
600de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
601de941241SSukumar Ghorai 				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
602de941241SSukumar Ghorai 
603eb9a28f6SNishanth Menon 	start = get_timer(0);
604eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
605eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
606eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for ics!\n", __func__);
607eb9a28f6SNishanth Menon 			return;
608eb9a28f6SNishanth Menon 		}
609eb9a28f6SNishanth Menon 	}
610de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
611de941241SSukumar Ghorai }
612de941241SSukumar Ghorai 
613ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
614*a9d6a7e2SMugunthan V N #ifdef CONFIG_DM_MMC
615*a9d6a7e2SMugunthan V N static int omap_hsmmc_getcd(struct mmc *mmc)
616*a9d6a7e2SMugunthan V N {
617*a9d6a7e2SMugunthan V N 	struct omap_hsmmc_data *priv = mmc->priv;
618*a9d6a7e2SMugunthan V N 	int value;
619*a9d6a7e2SMugunthan V N 
620*a9d6a7e2SMugunthan V N 	value = dm_gpio_get_value(&priv->cd_gpio);
621*a9d6a7e2SMugunthan V N 	/* if no CD return as 1 */
622*a9d6a7e2SMugunthan V N 	if (value < 0)
623*a9d6a7e2SMugunthan V N 		return 1;
624*a9d6a7e2SMugunthan V N 
625*a9d6a7e2SMugunthan V N 	if (priv->cd_inverted)
626*a9d6a7e2SMugunthan V N 		return !value;
627*a9d6a7e2SMugunthan V N 	return value;
628*a9d6a7e2SMugunthan V N }
629*a9d6a7e2SMugunthan V N 
630*a9d6a7e2SMugunthan V N static int omap_hsmmc_getwp(struct mmc *mmc)
631*a9d6a7e2SMugunthan V N {
632*a9d6a7e2SMugunthan V N 	struct omap_hsmmc_data *priv = mmc->priv;
633*a9d6a7e2SMugunthan V N 	int value;
634*a9d6a7e2SMugunthan V N 
635*a9d6a7e2SMugunthan V N 	value = dm_gpio_get_value(&priv->wp_gpio);
636*a9d6a7e2SMugunthan V N 	/* if no WP return as 0 */
637*a9d6a7e2SMugunthan V N 	if (value < 0)
638*a9d6a7e2SMugunthan V N 		return 0;
639*a9d6a7e2SMugunthan V N 	return value;
640*a9d6a7e2SMugunthan V N }
641*a9d6a7e2SMugunthan V N #else
642ab769f22SPantelis Antoniou static int omap_hsmmc_getcd(struct mmc *mmc)
643ab769f22SPantelis Antoniou {
644ab769f22SPantelis Antoniou 	struct omap_hsmmc_data *priv_data = mmc->priv;
645ab769f22SPantelis Antoniou 	int cd_gpio;
646ab769f22SPantelis Antoniou 
647ab769f22SPantelis Antoniou 	/* if no CD return as 1 */
648ab769f22SPantelis Antoniou 	cd_gpio = priv_data->cd_gpio;
649ab769f22SPantelis Antoniou 	if (cd_gpio < 0)
650ab769f22SPantelis Antoniou 		return 1;
651ab769f22SPantelis Antoniou 
6520b03a931SIgor Grinberg 	/* NOTE: assumes card detect signal is active-low */
6530b03a931SIgor Grinberg 	return !gpio_get_value(cd_gpio);
654ab769f22SPantelis Antoniou }
655ab769f22SPantelis Antoniou 
656ab769f22SPantelis Antoniou static int omap_hsmmc_getwp(struct mmc *mmc)
657ab769f22SPantelis Antoniou {
658ab769f22SPantelis Antoniou 	struct omap_hsmmc_data *priv_data = mmc->priv;
659ab769f22SPantelis Antoniou 	int wp_gpio;
660ab769f22SPantelis Antoniou 
661ab769f22SPantelis Antoniou 	/* if no WP return as 0 */
662ab769f22SPantelis Antoniou 	wp_gpio = priv_data->wp_gpio;
663ab769f22SPantelis Antoniou 	if (wp_gpio < 0)
664ab769f22SPantelis Antoniou 		return 0;
665ab769f22SPantelis Antoniou 
6660b03a931SIgor Grinberg 	/* NOTE: assumes write protect signal is active-high */
667ab769f22SPantelis Antoniou 	return gpio_get_value(wp_gpio);
668ab769f22SPantelis Antoniou }
669ab769f22SPantelis Antoniou #endif
670*a9d6a7e2SMugunthan V N #endif
671ab769f22SPantelis Antoniou 
672ab769f22SPantelis Antoniou static const struct mmc_ops omap_hsmmc_ops = {
673ab769f22SPantelis Antoniou 	.send_cmd	= omap_hsmmc_send_cmd,
674ab769f22SPantelis Antoniou 	.set_ios	= omap_hsmmc_set_ios,
675ab769f22SPantelis Antoniou 	.init		= omap_hsmmc_init_setup,
676ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
677ab769f22SPantelis Antoniou 	.getcd		= omap_hsmmc_getcd,
678ab769f22SPantelis Antoniou 	.getwp		= omap_hsmmc_getwp,
679ab769f22SPantelis Antoniou #endif
680ab769f22SPantelis Antoniou };
681ab769f22SPantelis Antoniou 
682*a9d6a7e2SMugunthan V N #ifndef CONFIG_DM_MMC
683e3913f56SNikita Kiryanov int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
684e3913f56SNikita Kiryanov 		int wp_gpio)
685de941241SSukumar Ghorai {
68693bfd616SPantelis Antoniou 	struct mmc *mmc;
68793bfd616SPantelis Antoniou 	struct omap_hsmmc_data *priv_data;
68893bfd616SPantelis Antoniou 	struct mmc_config *cfg;
68993bfd616SPantelis Antoniou 	uint host_caps_val;
690de941241SSukumar Ghorai 
69193bfd616SPantelis Antoniou 	priv_data = malloc(sizeof(*priv_data));
69293bfd616SPantelis Antoniou 	if (priv_data == NULL)
69393bfd616SPantelis Antoniou 		return -1;
69493bfd616SPantelis Antoniou 
6955a20397bSRob Herring 	host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
696de941241SSukumar Ghorai 
697de941241SSukumar Ghorai 	switch (dev_index) {
698de941241SSukumar Ghorai 	case 0:
699cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
700de941241SSukumar Ghorai 		break;
7011037d585STom Rini #ifdef OMAP_HSMMC2_BASE
702de941241SSukumar Ghorai 	case 1:
703cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
704152ba363SLubomir Popov #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
7059fbdca60SNikita Kiryanov 	defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX) || \
7063b68939fSRoger Quadros 	defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \
7073b68939fSRoger Quadros 		defined(CONFIG_HSMMC2_8BIT)
708152ba363SLubomir Popov 		/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
709152ba363SLubomir Popov 		host_caps_val |= MMC_MODE_8BIT;
710152ba363SLubomir Popov #endif
711de941241SSukumar Ghorai 		break;
7121037d585STom Rini #endif
7131037d585STom Rini #ifdef OMAP_HSMMC3_BASE
714de941241SSukumar Ghorai 	case 2:
715cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
716d11ac4b5SFelipe Balbi #if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT)
717152ba363SLubomir Popov 		/* Enable 8-bit interface for eMMC on DRA7XX */
718152ba363SLubomir Popov 		host_caps_val |= MMC_MODE_8BIT;
719152ba363SLubomir Popov #endif
720de941241SSukumar Ghorai 		break;
7211037d585STom Rini #endif
722de941241SSukumar Ghorai 	default:
723cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
724de941241SSukumar Ghorai 		return 1;
725de941241SSukumar Ghorai 	}
726ab769f22SPantelis Antoniou #ifdef OMAP_HSMMC_USE_GPIO
727ab769f22SPantelis Antoniou 	/* on error gpio values are set to -1, which is what we want */
728e874d5b0SNikita Kiryanov 	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
729e3913f56SNikita Kiryanov 	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
730ab769f22SPantelis Antoniou #endif
731173ddc5bSPeter Korsgaard 
73293bfd616SPantelis Antoniou 	cfg = &priv_data->cfg;
733de941241SSukumar Ghorai 
73493bfd616SPantelis Antoniou 	cfg->name = "OMAP SD/MMC";
73593bfd616SPantelis Antoniou 	cfg->ops = &omap_hsmmc_ops;
73693bfd616SPantelis Antoniou 
73793bfd616SPantelis Antoniou 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
73893bfd616SPantelis Antoniou 	cfg->host_caps = host_caps_val & ~host_caps_mask;
73993bfd616SPantelis Antoniou 
74093bfd616SPantelis Antoniou 	cfg->f_min = 400000;
741bbbc1ae9SJonathan Solnit 
742bbbc1ae9SJonathan Solnit 	if (f_max != 0)
74393bfd616SPantelis Antoniou 		cfg->f_max = f_max;
744bbbc1ae9SJonathan Solnit 	else {
74593bfd616SPantelis Antoniou 		if (cfg->host_caps & MMC_MODE_HS) {
74693bfd616SPantelis Antoniou 			if (cfg->host_caps & MMC_MODE_HS_52MHz)
74793bfd616SPantelis Antoniou 				cfg->f_max = 52000000;
748bbbc1ae9SJonathan Solnit 			else
74993bfd616SPantelis Antoniou 				cfg->f_max = 26000000;
750bbbc1ae9SJonathan Solnit 		} else
75193bfd616SPantelis Antoniou 			cfg->f_max = 20000000;
752bbbc1ae9SJonathan Solnit 	}
753de941241SSukumar Ghorai 
75493bfd616SPantelis Antoniou 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
7558feafcc4SJohn Rigby 
7564ca9244dSJohn Rigby #if defined(CONFIG_OMAP34XX)
7574ca9244dSJohn Rigby 	/*
7584ca9244dSJohn Rigby 	 * Silicon revs 2.1 and older do not support multiblock transfers.
7594ca9244dSJohn Rigby 	 */
7604ca9244dSJohn Rigby 	if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
76193bfd616SPantelis Antoniou 		cfg->b_max = 1;
7624ca9244dSJohn Rigby #endif
76393bfd616SPantelis Antoniou 	mmc = mmc_create(cfg, priv_data);
76493bfd616SPantelis Antoniou 	if (mmc == NULL)
76593bfd616SPantelis Antoniou 		return -1;
766de941241SSukumar Ghorai 
767de941241SSukumar Ghorai 	return 0;
768de941241SSukumar Ghorai }
769*a9d6a7e2SMugunthan V N #else
770*a9d6a7e2SMugunthan V N static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
771*a9d6a7e2SMugunthan V N {
772*a9d6a7e2SMugunthan V N 	struct omap_hsmmc_data *priv = dev_get_priv(dev);
773*a9d6a7e2SMugunthan V N 	const void *fdt = gd->fdt_blob;
774*a9d6a7e2SMugunthan V N 	int node = dev->of_offset;
775*a9d6a7e2SMugunthan V N 	struct mmc_config *cfg;
776*a9d6a7e2SMugunthan V N 	int val;
777*a9d6a7e2SMugunthan V N 
778*a9d6a7e2SMugunthan V N 	priv->base_addr = (struct hsmmc *)dev_get_addr(dev);
779*a9d6a7e2SMugunthan V N 	cfg = &priv->cfg;
780*a9d6a7e2SMugunthan V N 
781*a9d6a7e2SMugunthan V N 	cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
782*a9d6a7e2SMugunthan V N 	val = fdtdec_get_int(fdt, node, "bus-width", -1);
783*a9d6a7e2SMugunthan V N 	if (val < 0) {
784*a9d6a7e2SMugunthan V N 		printf("error: bus-width property missing\n");
785*a9d6a7e2SMugunthan V N 		return -ENOENT;
786*a9d6a7e2SMugunthan V N 	}
787*a9d6a7e2SMugunthan V N 
788*a9d6a7e2SMugunthan V N 	switch (val) {
789*a9d6a7e2SMugunthan V N 	case 0x8:
790*a9d6a7e2SMugunthan V N 		cfg->host_caps |= MMC_MODE_8BIT;
791*a9d6a7e2SMugunthan V N 	case 0x4:
792*a9d6a7e2SMugunthan V N 		cfg->host_caps |= MMC_MODE_4BIT;
793*a9d6a7e2SMugunthan V N 		break;
794*a9d6a7e2SMugunthan V N 	default:
795*a9d6a7e2SMugunthan V N 		printf("error: invalid bus-width property\n");
796*a9d6a7e2SMugunthan V N 		return -ENOENT;
797*a9d6a7e2SMugunthan V N 	}
798*a9d6a7e2SMugunthan V N 
799*a9d6a7e2SMugunthan V N 	cfg->f_min = 400000;
800*a9d6a7e2SMugunthan V N 	cfg->f_max = fdtdec_get_int(fdt, node, "max-frequency", 52000000);
801*a9d6a7e2SMugunthan V N 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
802*a9d6a7e2SMugunthan V N 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
803*a9d6a7e2SMugunthan V N 
804*a9d6a7e2SMugunthan V N 	priv->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
805*a9d6a7e2SMugunthan V N 
806*a9d6a7e2SMugunthan V N 	return 0;
807*a9d6a7e2SMugunthan V N }
808*a9d6a7e2SMugunthan V N 
809*a9d6a7e2SMugunthan V N static int omap_hsmmc_probe(struct udevice *dev)
810*a9d6a7e2SMugunthan V N {
811*a9d6a7e2SMugunthan V N 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
812*a9d6a7e2SMugunthan V N 	struct omap_hsmmc_data *priv = dev_get_priv(dev);
813*a9d6a7e2SMugunthan V N 	struct mmc_config *cfg;
814*a9d6a7e2SMugunthan V N 	struct mmc *mmc;
815*a9d6a7e2SMugunthan V N 
816*a9d6a7e2SMugunthan V N 	cfg = &priv->cfg;
817*a9d6a7e2SMugunthan V N 	cfg->name = "OMAP SD/MMC";
818*a9d6a7e2SMugunthan V N 	cfg->ops = &omap_hsmmc_ops;
819*a9d6a7e2SMugunthan V N 
820*a9d6a7e2SMugunthan V N 	mmc = mmc_create(cfg, priv);
821*a9d6a7e2SMugunthan V N 	if (mmc == NULL)
822*a9d6a7e2SMugunthan V N 		return -1;
823*a9d6a7e2SMugunthan V N 
824*a9d6a7e2SMugunthan V N 	upriv->mmc = mmc;
825*a9d6a7e2SMugunthan V N 
826*a9d6a7e2SMugunthan V N 	return 0;
827*a9d6a7e2SMugunthan V N }
828*a9d6a7e2SMugunthan V N 
829*a9d6a7e2SMugunthan V N static const struct udevice_id omap_hsmmc_ids[] = {
830*a9d6a7e2SMugunthan V N 	{ .compatible = "ti,omap3-hsmmc" },
831*a9d6a7e2SMugunthan V N 	{ .compatible = "ti,omap4-hsmmc" },
832*a9d6a7e2SMugunthan V N 	{ .compatible = "ti,am33xx-hsmmc" },
833*a9d6a7e2SMugunthan V N 	{ }
834*a9d6a7e2SMugunthan V N };
835*a9d6a7e2SMugunthan V N 
836*a9d6a7e2SMugunthan V N U_BOOT_DRIVER(omap_hsmmc) = {
837*a9d6a7e2SMugunthan V N 	.name	= "omap_hsmmc",
838*a9d6a7e2SMugunthan V N 	.id	= UCLASS_MMC,
839*a9d6a7e2SMugunthan V N 	.of_match = omap_hsmmc_ids,
840*a9d6a7e2SMugunthan V N 	.ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata,
841*a9d6a7e2SMugunthan V N 	.probe	= omap_hsmmc_probe,
842*a9d6a7e2SMugunthan V N 	.priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
843*a9d6a7e2SMugunthan V N };
844*a9d6a7e2SMugunthan V N #endif
845