xref: /rk3399_rockchip-uboot/drivers/mmc/omap_hsmmc.c (revision a5d439c2d3a55df2718eae19fb128e498f4bef87)
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>
27de941241SSukumar Ghorai #include <mmc.h>
28de941241SSukumar Ghorai #include <part.h>
29de941241SSukumar Ghorai #include <i2c.h>
30de941241SSukumar Ghorai #include <twl4030.h>
3114fa2dd0SBalaji T K #include <twl6030.h>
32cb199102SNishanth Menon #include <palmas.h>
33e874d5b0SNikita Kiryanov #include <asm/gpio.h>
34de941241SSukumar Ghorai #include <asm/io.h>
35de941241SSukumar Ghorai #include <asm/arch/mmc_host_def.h>
3696e0e7b3SDirk Behme #include <asm/arch/sys_proto.h>
37de941241SSukumar Ghorai 
3825c719e2SGrazvydas Ignotas /* common definitions for all OMAPs */
3925c719e2SGrazvydas Ignotas #define SYSCTL_SRC	(1 << 25)
4025c719e2SGrazvydas Ignotas #define SYSCTL_SRD	(1 << 26)
4125c719e2SGrazvydas Ignotas 
42cc22b0c0SNikita Kiryanov struct omap_hsmmc_data {
43cc22b0c0SNikita Kiryanov 	struct hsmmc *base_addr;
44e874d5b0SNikita Kiryanov 	int cd_gpio;
45e3913f56SNikita Kiryanov 	int wp_gpio;
46cc22b0c0SNikita Kiryanov };
47cc22b0c0SNikita Kiryanov 
48eb9a28f6SNishanth Menon /* If we fail after 1 second wait, something is really bad */
49eb9a28f6SNishanth Menon #define MAX_RETRY_MS	1000
50eb9a28f6SNishanth Menon 
51933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
52933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
53933efe64SSricharan 			unsigned int siz);
545964daddSNikita Kiryanov static struct mmc hsmmc_dev[3];
55cc22b0c0SNikita Kiryanov static struct omap_hsmmc_data hsmmc_dev_data[3];
5614fa2dd0SBalaji T K 
57e874d5b0SNikita Kiryanov #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
58e874d5b0SNikita Kiryanov 	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
59e874d5b0SNikita Kiryanov static int omap_mmc_setup_gpio_in(int gpio, const char *label)
60e874d5b0SNikita Kiryanov {
61e874d5b0SNikita Kiryanov 	if (!gpio_is_valid(gpio))
62e874d5b0SNikita Kiryanov 		return -1;
63e874d5b0SNikita Kiryanov 
64e874d5b0SNikita Kiryanov 	if (gpio_request(gpio, label) < 0)
65e874d5b0SNikita Kiryanov 		return -1;
66e874d5b0SNikita Kiryanov 
67e874d5b0SNikita Kiryanov 	if (gpio_direction_input(gpio) < 0)
68e874d5b0SNikita Kiryanov 		return -1;
69e874d5b0SNikita Kiryanov 
70e874d5b0SNikita Kiryanov 	return gpio;
71e874d5b0SNikita Kiryanov }
72e874d5b0SNikita Kiryanov 
73e874d5b0SNikita Kiryanov static int omap_mmc_getcd(struct mmc *mmc)
74e874d5b0SNikita Kiryanov {
75e874d5b0SNikita Kiryanov 	int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
76e874d5b0SNikita Kiryanov 	return gpio_get_value(cd_gpio);
77e874d5b0SNikita Kiryanov }
78e3913f56SNikita Kiryanov 
79e3913f56SNikita Kiryanov static int omap_mmc_getwp(struct mmc *mmc)
80e3913f56SNikita Kiryanov {
81e3913f56SNikita Kiryanov 	int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio;
82e3913f56SNikita Kiryanov 	return gpio_get_value(wp_gpio);
83e3913f56SNikita Kiryanov }
84e874d5b0SNikita Kiryanov #else
85e874d5b0SNikita Kiryanov static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
86e874d5b0SNikita Kiryanov {
87e874d5b0SNikita Kiryanov 	return -1;
88e874d5b0SNikita Kiryanov }
89e874d5b0SNikita Kiryanov 
90e874d5b0SNikita Kiryanov #define omap_mmc_getcd NULL
91e3913f56SNikita Kiryanov #define omap_mmc_getwp NULL
92e874d5b0SNikita Kiryanov #endif
93e874d5b0SNikita Kiryanov 
9414fa2dd0SBalaji T K #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
9514fa2dd0SBalaji T K static void omap4_vmmc_pbias_config(struct mmc *mmc)
9614fa2dd0SBalaji T K {
9714fa2dd0SBalaji T K 	u32 value = 0;
9814fa2dd0SBalaji T K 
99c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbiaslite);
10014fa2dd0SBalaji T K 	value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
101c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbiaslite);
10214fa2dd0SBalaji T K 	/* set VMMC to 3V */
10314fa2dd0SBalaji T K 	twl6030_power_mmc_init();
104c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbiaslite);
10514fa2dd0SBalaji T K 	value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
106c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbiaslite);
10714fa2dd0SBalaji T K }
10814fa2dd0SBalaji T K #endif
10914fa2dd0SBalaji T K 
110cb199102SNishanth Menon #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
111dd23e59dSBalaji T K static void omap5_pbias_config(struct mmc *mmc)
112dd23e59dSBalaji T K {
113dd23e59dSBalaji T K 	u32 value = 0;
114dd23e59dSBalaji T K 
115c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbias);
116*a5d439c2SBalaji T K 	value &= ~SDCARD_PWRDNZ;
117*a5d439c2SBalaji T K 	writel(value, (*ctrl)->control_pbias);
118*a5d439c2SBalaji T K 	udelay(10); /* wait 10 us */
119*a5d439c2SBalaji T K 	value &= ~SDCARD_BIAS_PWRDNZ;
120c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
121dd23e59dSBalaji T K 
122384bcae0SNishanth Menon 	palmas_mmc1_poweron_ldo();
123dd23e59dSBalaji T K 
124c43c8339SLokesh Vutla 	value = readl((*ctrl)->control_pbias);
125*a5d439c2SBalaji T K 	value |= SDCARD_BIAS_PWRDNZ;
126c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
127*a5d439c2SBalaji T K 	udelay(150); /* wait 150 us */
128*a5d439c2SBalaji T K 	value |= SDCARD_PWRDNZ;
129c43c8339SLokesh Vutla 	writel(value, (*ctrl)->control_pbias);
130*a5d439c2SBalaji T K 	udelay(150); /* wait 150 us */
131dd23e59dSBalaji T K }
132dd23e59dSBalaji T K #endif
133dd23e59dSBalaji T K 
13414fa2dd0SBalaji T K unsigned char mmc_board_init(struct mmc *mmc)
135de941241SSukumar Ghorai {
136de941241SSukumar Ghorai #if defined(CONFIG_OMAP34XX)
137de941241SSukumar Ghorai 	t2_t *t2_base = (t2_t *)T2_BASE;
138de941241SSukumar Ghorai 	struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
139b1e725f2SGrazvydas Ignotas 	u32 pbias_lite;
140de941241SSukumar Ghorai 
141b1e725f2SGrazvydas Ignotas 	pbias_lite = readl(&t2_base->pbias_lite);
142b1e725f2SGrazvydas Ignotas 	pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
143b1e725f2SGrazvydas Ignotas 	writel(pbias_lite, &t2_base->pbias_lite);
144b1e725f2SGrazvydas Ignotas #endif
145b1e725f2SGrazvydas Ignotas #if defined(CONFIG_TWL4030_POWER)
146b1e725f2SGrazvydas Ignotas 	twl4030_power_mmc_init();
147b1e725f2SGrazvydas Ignotas 	mdelay(100);	/* ramp-up delay from Linux code */
148b1e725f2SGrazvydas Ignotas #endif
149b1e725f2SGrazvydas Ignotas #if defined(CONFIG_OMAP34XX)
150b1e725f2SGrazvydas Ignotas 	writel(pbias_lite | PBIASLITEPWRDNZ1 |
151de941241SSukumar Ghorai 		PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
152de941241SSukumar Ghorai 		&t2_base->pbias_lite);
153de941241SSukumar Ghorai 
154de941241SSukumar Ghorai 	writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
155de941241SSukumar Ghorai 		&t2_base->devconf0);
156de941241SSukumar Ghorai 
157de941241SSukumar Ghorai 	writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
158de941241SSukumar Ghorai 		&t2_base->devconf1);
159de941241SSukumar Ghorai 
160bbbc1ae9SJonathan Solnit 	/* Change from default of 52MHz to 26MHz if necessary */
161bbbc1ae9SJonathan Solnit 	if (!(mmc->host_caps & MMC_MODE_HS_52MHz))
162bbbc1ae9SJonathan Solnit 		writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
163bbbc1ae9SJonathan Solnit 			&t2_base->ctl_prog_io1);
164bbbc1ae9SJonathan Solnit 
165de941241SSukumar Ghorai 	writel(readl(&prcm_base->fclken1_core) |
166de941241SSukumar Ghorai 		EN_MMC1 | EN_MMC2 | EN_MMC3,
167de941241SSukumar Ghorai 		&prcm_base->fclken1_core);
168de941241SSukumar Ghorai 
169de941241SSukumar Ghorai 	writel(readl(&prcm_base->iclken1_core) |
170de941241SSukumar Ghorai 		EN_MMC1 | EN_MMC2 | EN_MMC3,
171de941241SSukumar Ghorai 		&prcm_base->iclken1_core);
172de941241SSukumar Ghorai #endif
173de941241SSukumar Ghorai 
17414fa2dd0SBalaji T K #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
17514fa2dd0SBalaji T K 	/* PBIAS config needed for MMC1 only */
17614fa2dd0SBalaji T K 	if (mmc->block_dev.dev == 0)
17714fa2dd0SBalaji T K 		omap4_vmmc_pbias_config(mmc);
17814fa2dd0SBalaji T K #endif
179cb199102SNishanth Menon #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
180dd23e59dSBalaji T K 	if (mmc->block_dev.dev == 0)
181dd23e59dSBalaji T K 		omap5_pbias_config(mmc);
182dd23e59dSBalaji T K #endif
183de941241SSukumar Ghorai 
184de941241SSukumar Ghorai 	return 0;
185de941241SSukumar Ghorai }
186de941241SSukumar Ghorai 
187933efe64SSricharan void mmc_init_stream(struct hsmmc *mmc_base)
188de941241SSukumar Ghorai {
189eb9a28f6SNishanth Menon 	ulong start;
190de941241SSukumar Ghorai 
191de941241SSukumar Ghorai 	writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
192de941241SSukumar Ghorai 
193de941241SSukumar Ghorai 	writel(MMC_CMD0, &mmc_base->cmd);
194eb9a28f6SNishanth Menon 	start = get_timer(0);
195eb9a28f6SNishanth Menon 	while (!(readl(&mmc_base->stat) & CC_MASK)) {
196eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
197eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc!\n", __func__);
198eb9a28f6SNishanth Menon 			return;
199eb9a28f6SNishanth Menon 		}
200eb9a28f6SNishanth Menon 	}
201de941241SSukumar Ghorai 	writel(CC_MASK, &mmc_base->stat)
202de941241SSukumar Ghorai 		;
203de941241SSukumar Ghorai 	writel(MMC_CMD0, &mmc_base->cmd)
204de941241SSukumar Ghorai 		;
205eb9a28f6SNishanth Menon 	start = get_timer(0);
206eb9a28f6SNishanth Menon 	while (!(readl(&mmc_base->stat) & CC_MASK)) {
207eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
208eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc2!\n", __func__);
209eb9a28f6SNishanth Menon 			return;
210eb9a28f6SNishanth Menon 		}
211eb9a28f6SNishanth Menon 	}
212de941241SSukumar Ghorai 	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
213de941241SSukumar Ghorai }
214de941241SSukumar Ghorai 
215de941241SSukumar Ghorai 
216de941241SSukumar Ghorai static int mmc_init_setup(struct mmc *mmc)
217de941241SSukumar Ghorai {
218cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
219de941241SSukumar Ghorai 	unsigned int reg_val;
220de941241SSukumar Ghorai 	unsigned int dsor;
221eb9a28f6SNishanth Menon 	ulong start;
222de941241SSukumar Ghorai 
223cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
22414fa2dd0SBalaji T K 	mmc_board_init(mmc);
225de941241SSukumar Ghorai 
226de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
227de941241SSukumar Ghorai 		&mmc_base->sysconfig);
228eb9a28f6SNishanth Menon 	start = get_timer(0);
229eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
230eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
231eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for cc2!\n", __func__);
232eb9a28f6SNishanth Menon 			return TIMEOUT;
233eb9a28f6SNishanth Menon 		}
234eb9a28f6SNishanth Menon 	}
235de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
236eb9a28f6SNishanth Menon 	start = get_timer(0);
237eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
238eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
239eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for softresetall!\n",
240eb9a28f6SNishanth Menon 				__func__);
241eb9a28f6SNishanth Menon 			return TIMEOUT;
242eb9a28f6SNishanth Menon 		}
243eb9a28f6SNishanth Menon 	}
244de941241SSukumar Ghorai 	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
245de941241SSukumar Ghorai 	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
246de941241SSukumar Ghorai 		&mmc_base->capa);
247de941241SSukumar Ghorai 
248de941241SSukumar Ghorai 	reg_val = readl(&mmc_base->con) & RESERVED_MASK;
249de941241SSukumar Ghorai 
250de941241SSukumar Ghorai 	writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
251de941241SSukumar Ghorai 		MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
252de941241SSukumar Ghorai 		HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
253de941241SSukumar Ghorai 
254de941241SSukumar Ghorai 	dsor = 240;
255de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
256de941241SSukumar Ghorai 		(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
257de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
258de941241SSukumar Ghorai 		(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
259eb9a28f6SNishanth Menon 	start = get_timer(0);
260eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
261eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
262eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for ics!\n", __func__);
263eb9a28f6SNishanth Menon 			return TIMEOUT;
264eb9a28f6SNishanth Menon 		}
265eb9a28f6SNishanth Menon 	}
266de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
267de941241SSukumar Ghorai 
268de941241SSukumar Ghorai 	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
269de941241SSukumar Ghorai 
270de941241SSukumar Ghorai 	writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
271de941241SSukumar Ghorai 		IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
272de941241SSukumar Ghorai 		&mmc_base->ie);
273de941241SSukumar Ghorai 
274de941241SSukumar Ghorai 	mmc_init_stream(mmc_base);
275de941241SSukumar Ghorai 
276de941241SSukumar Ghorai 	return 0;
277de941241SSukumar Ghorai }
278de941241SSukumar Ghorai 
27925c719e2SGrazvydas Ignotas /*
28025c719e2SGrazvydas Ignotas  * MMC controller internal finite state machine reset
28125c719e2SGrazvydas Ignotas  *
28225c719e2SGrazvydas Ignotas  * Used to reset command or data internal state machines, using respectively
28325c719e2SGrazvydas Ignotas  * SRC or SRD bit of SYSCTL register
28425c719e2SGrazvydas Ignotas  */
28525c719e2SGrazvydas Ignotas static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
28625c719e2SGrazvydas Ignotas {
28725c719e2SGrazvydas Ignotas 	ulong start;
28825c719e2SGrazvydas Ignotas 
28925c719e2SGrazvydas Ignotas 	mmc_reg_out(&mmc_base->sysctl, bit, bit);
29025c719e2SGrazvydas Ignotas 
29125c719e2SGrazvydas Ignotas 	start = get_timer(0);
29225c719e2SGrazvydas Ignotas 	while ((readl(&mmc_base->sysctl) & bit) != 0) {
29325c719e2SGrazvydas Ignotas 		if (get_timer(0) - start > MAX_RETRY_MS) {
29425c719e2SGrazvydas Ignotas 			printf("%s: timedout waiting for sysctl %x to clear\n",
29525c719e2SGrazvydas Ignotas 				__func__, bit);
29625c719e2SGrazvydas Ignotas 			return;
29725c719e2SGrazvydas Ignotas 		}
29825c719e2SGrazvydas Ignotas 	}
29925c719e2SGrazvydas Ignotas }
300de941241SSukumar Ghorai 
301de941241SSukumar Ghorai static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
302de941241SSukumar Ghorai 			struct mmc_data *data)
303de941241SSukumar Ghorai {
304cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
305de941241SSukumar Ghorai 	unsigned int flags, mmc_stat;
306eb9a28f6SNishanth Menon 	ulong start;
307de941241SSukumar Ghorai 
308cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
309eb9a28f6SNishanth Menon 	start = get_timer(0);
310a7778f8fSTom Rini 	while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
311eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
312a7778f8fSTom Rini 			printf("%s: timedout waiting on cmd inhibit to clear\n",
313a7778f8fSTom Rini 					__func__);
314eb9a28f6SNishanth Menon 			return TIMEOUT;
315eb9a28f6SNishanth Menon 		}
316eb9a28f6SNishanth Menon 	}
317de941241SSukumar Ghorai 	writel(0xFFFFFFFF, &mmc_base->stat);
318eb9a28f6SNishanth Menon 	start = get_timer(0);
319eb9a28f6SNishanth Menon 	while (readl(&mmc_base->stat)) {
320eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
32115ceb1deSGrazvydas Ignotas 			printf("%s: timedout waiting for STAT (%x) to clear\n",
32215ceb1deSGrazvydas Ignotas 				__func__, readl(&mmc_base->stat));
323eb9a28f6SNishanth Menon 			return TIMEOUT;
324eb9a28f6SNishanth Menon 		}
325eb9a28f6SNishanth Menon 	}
326de941241SSukumar Ghorai 	/*
327de941241SSukumar Ghorai 	 * CMDREG
328de941241SSukumar Ghorai 	 * CMDIDX[13:8]	: Command index
329de941241SSukumar Ghorai 	 * DATAPRNT[5]	: Data Present Select
330de941241SSukumar Ghorai 	 * ENCMDIDX[4]	: Command Index Check Enable
331de941241SSukumar Ghorai 	 * ENCMDCRC[3]	: Command CRC Check Enable
332de941241SSukumar Ghorai 	 * RSPTYP[1:0]
333de941241SSukumar Ghorai 	 *	00 = No Response
334de941241SSukumar Ghorai 	 *	01 = Length 136
335de941241SSukumar Ghorai 	 *	10 = Length 48
336de941241SSukumar Ghorai 	 *	11 = Length 48 Check busy after response
337de941241SSukumar Ghorai 	 */
338de941241SSukumar Ghorai 	/* Delay added before checking the status of frq change
339de941241SSukumar Ghorai 	 * retry not supported by mmc.c(core file)
340de941241SSukumar Ghorai 	 */
341de941241SSukumar Ghorai 	if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
342de941241SSukumar Ghorai 		udelay(50000); /* wait 50 ms */
343de941241SSukumar Ghorai 
344de941241SSukumar Ghorai 	if (!(cmd->resp_type & MMC_RSP_PRESENT))
345de941241SSukumar Ghorai 		flags = 0;
346de941241SSukumar Ghorai 	else if (cmd->resp_type & MMC_RSP_136)
347de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
348de941241SSukumar Ghorai 	else if (cmd->resp_type & MMC_RSP_BUSY)
349de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT48B;
350de941241SSukumar Ghorai 	else
351de941241SSukumar Ghorai 		flags = RSP_TYPE_LGHT48;
352de941241SSukumar Ghorai 
353de941241SSukumar Ghorai 	/* enable default flags */
354de941241SSukumar Ghorai 	flags =	flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
355de941241SSukumar Ghorai 			MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
356de941241SSukumar Ghorai 
357de941241SSukumar Ghorai 	if (cmd->resp_type & MMC_RSP_CRC)
358de941241SSukumar Ghorai 		flags |= CCCE_CHECK;
359de941241SSukumar Ghorai 	if (cmd->resp_type & MMC_RSP_OPCODE)
360de941241SSukumar Ghorai 		flags |= CICE_CHECK;
361de941241SSukumar Ghorai 
362de941241SSukumar Ghorai 	if (data) {
363de941241SSukumar Ghorai 		if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
364de941241SSukumar Ghorai 			 (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
365de941241SSukumar Ghorai 			flags |= (MSBS_MULTIBLK | BCE_ENABLE);
366de941241SSukumar Ghorai 			data->blocksize = 512;
367de941241SSukumar Ghorai 			writel(data->blocksize | (data->blocks << 16),
368de941241SSukumar Ghorai 							&mmc_base->blk);
369de941241SSukumar Ghorai 		} else
370de941241SSukumar Ghorai 			writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
371de941241SSukumar Ghorai 
372de941241SSukumar Ghorai 		if (data->flags & MMC_DATA_READ)
373de941241SSukumar Ghorai 			flags |= (DP_DATA | DDIR_READ);
374de941241SSukumar Ghorai 		else
375de941241SSukumar Ghorai 			flags |= (DP_DATA | DDIR_WRITE);
376de941241SSukumar Ghorai 	}
377de941241SSukumar Ghorai 
378de941241SSukumar Ghorai 	writel(cmd->cmdarg, &mmc_base->arg);
379de941241SSukumar Ghorai 	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
380de941241SSukumar Ghorai 
381eb9a28f6SNishanth Menon 	start = get_timer(0);
382de941241SSukumar Ghorai 	do {
383de941241SSukumar Ghorai 		mmc_stat = readl(&mmc_base->stat);
384eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
385de941241SSukumar Ghorai 			printf("%s : timeout: No status update\n", __func__);
386de941241SSukumar Ghorai 			return TIMEOUT;
387de941241SSukumar Ghorai 		}
388eb9a28f6SNishanth Menon 	} while (!mmc_stat);
389de941241SSukumar Ghorai 
39025c719e2SGrazvydas Ignotas 	if ((mmc_stat & IE_CTO) != 0) {
39125c719e2SGrazvydas Ignotas 		mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
392de941241SSukumar Ghorai 		return TIMEOUT;
39325c719e2SGrazvydas Ignotas 	} else if ((mmc_stat & ERRI_MASK) != 0)
394de941241SSukumar Ghorai 		return -1;
395de941241SSukumar Ghorai 
396de941241SSukumar Ghorai 	if (mmc_stat & CC_MASK) {
397de941241SSukumar Ghorai 		writel(CC_MASK, &mmc_base->stat);
398de941241SSukumar Ghorai 		if (cmd->resp_type & MMC_RSP_PRESENT) {
399de941241SSukumar Ghorai 			if (cmd->resp_type & MMC_RSP_136) {
400de941241SSukumar Ghorai 				/* response type 2 */
401de941241SSukumar Ghorai 				cmd->response[3] = readl(&mmc_base->rsp10);
402de941241SSukumar Ghorai 				cmd->response[2] = readl(&mmc_base->rsp32);
403de941241SSukumar Ghorai 				cmd->response[1] = readl(&mmc_base->rsp54);
404de941241SSukumar Ghorai 				cmd->response[0] = readl(&mmc_base->rsp76);
405de941241SSukumar Ghorai 			} else
406de941241SSukumar Ghorai 				/* response types 1, 1b, 3, 4, 5, 6 */
407de941241SSukumar Ghorai 				cmd->response[0] = readl(&mmc_base->rsp10);
408de941241SSukumar Ghorai 		}
409de941241SSukumar Ghorai 	}
410de941241SSukumar Ghorai 
411de941241SSukumar Ghorai 	if (data && (data->flags & MMC_DATA_READ)) {
412de941241SSukumar Ghorai 		mmc_read_data(mmc_base,	data->dest,
413de941241SSukumar Ghorai 				data->blocksize * data->blocks);
414de941241SSukumar Ghorai 	} else if (data && (data->flags & MMC_DATA_WRITE)) {
415de941241SSukumar Ghorai 		mmc_write_data(mmc_base, data->src,
416de941241SSukumar Ghorai 				data->blocksize * data->blocks);
417de941241SSukumar Ghorai 	}
418de941241SSukumar Ghorai 	return 0;
419de941241SSukumar Ghorai }
420de941241SSukumar Ghorai 
421933efe64SSricharan static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
422de941241SSukumar Ghorai {
423de941241SSukumar Ghorai 	unsigned int *output_buf = (unsigned int *)buf;
424de941241SSukumar Ghorai 	unsigned int mmc_stat;
425de941241SSukumar Ghorai 	unsigned int count;
426de941241SSukumar Ghorai 
427de941241SSukumar Ghorai 	/*
428de941241SSukumar Ghorai 	 * Start Polled Read
429de941241SSukumar Ghorai 	 */
430de941241SSukumar Ghorai 	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
431de941241SSukumar Ghorai 	count /= 4;
432de941241SSukumar Ghorai 
433de941241SSukumar Ghorai 	while (size) {
434eb9a28f6SNishanth Menon 		ulong start = get_timer(0);
435de941241SSukumar Ghorai 		do {
436de941241SSukumar Ghorai 			mmc_stat = readl(&mmc_base->stat);
437eb9a28f6SNishanth Menon 			if (get_timer(0) - start > MAX_RETRY_MS) {
438eb9a28f6SNishanth Menon 				printf("%s: timedout waiting for status!\n",
439eb9a28f6SNishanth Menon 						__func__);
440eb9a28f6SNishanth Menon 				return TIMEOUT;
441eb9a28f6SNishanth Menon 			}
442de941241SSukumar Ghorai 		} while (mmc_stat == 0);
443de941241SSukumar Ghorai 
44425c719e2SGrazvydas Ignotas 		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
44525c719e2SGrazvydas Ignotas 			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
44625c719e2SGrazvydas Ignotas 
447de941241SSukumar Ghorai 		if ((mmc_stat & ERRI_MASK) != 0)
448de941241SSukumar Ghorai 			return 1;
449de941241SSukumar Ghorai 
450de941241SSukumar Ghorai 		if (mmc_stat & BRR_MASK) {
451de941241SSukumar Ghorai 			unsigned int k;
452de941241SSukumar Ghorai 
453de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BRR_MASK,
454de941241SSukumar Ghorai 				&mmc_base->stat);
455de941241SSukumar Ghorai 			for (k = 0; k < count; k++) {
456de941241SSukumar Ghorai 				*output_buf = readl(&mmc_base->data);
457de941241SSukumar Ghorai 				output_buf++;
458de941241SSukumar Ghorai 			}
459de941241SSukumar Ghorai 			size -= (count*4);
460de941241SSukumar Ghorai 		}
461de941241SSukumar Ghorai 
462de941241SSukumar Ghorai 		if (mmc_stat & BWR_MASK)
463de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BWR_MASK,
464de941241SSukumar Ghorai 				&mmc_base->stat);
465de941241SSukumar Ghorai 
466de941241SSukumar Ghorai 		if (mmc_stat & TC_MASK) {
467de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | TC_MASK,
468de941241SSukumar Ghorai 				&mmc_base->stat);
469de941241SSukumar Ghorai 			break;
470de941241SSukumar Ghorai 		}
471de941241SSukumar Ghorai 	}
472de941241SSukumar Ghorai 	return 0;
473de941241SSukumar Ghorai }
474de941241SSukumar Ghorai 
475933efe64SSricharan static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
476933efe64SSricharan 				unsigned int size)
477de941241SSukumar Ghorai {
478de941241SSukumar Ghorai 	unsigned int *input_buf = (unsigned int *)buf;
479de941241SSukumar Ghorai 	unsigned int mmc_stat;
480de941241SSukumar Ghorai 	unsigned int count;
481de941241SSukumar Ghorai 
482de941241SSukumar Ghorai 	/*
483de941241SSukumar Ghorai 	 * Start Polled Read
484de941241SSukumar Ghorai 	 */
485de941241SSukumar Ghorai 	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
486de941241SSukumar Ghorai 	count /= 4;
487de941241SSukumar Ghorai 
488de941241SSukumar Ghorai 	while (size) {
489eb9a28f6SNishanth Menon 		ulong start = get_timer(0);
490de941241SSukumar Ghorai 		do {
491de941241SSukumar Ghorai 			mmc_stat = readl(&mmc_base->stat);
492eb9a28f6SNishanth Menon 			if (get_timer(0) - start > MAX_RETRY_MS) {
493eb9a28f6SNishanth Menon 				printf("%s: timedout waiting for status!\n",
494eb9a28f6SNishanth Menon 						__func__);
495eb9a28f6SNishanth Menon 				return TIMEOUT;
496eb9a28f6SNishanth Menon 			}
497de941241SSukumar Ghorai 		} while (mmc_stat == 0);
498de941241SSukumar Ghorai 
49925c719e2SGrazvydas Ignotas 		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
50025c719e2SGrazvydas Ignotas 			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
50125c719e2SGrazvydas Ignotas 
502de941241SSukumar Ghorai 		if ((mmc_stat & ERRI_MASK) != 0)
503de941241SSukumar Ghorai 			return 1;
504de941241SSukumar Ghorai 
505de941241SSukumar Ghorai 		if (mmc_stat & BWR_MASK) {
506de941241SSukumar Ghorai 			unsigned int k;
507de941241SSukumar Ghorai 
508de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BWR_MASK,
509de941241SSukumar Ghorai 					&mmc_base->stat);
510de941241SSukumar Ghorai 			for (k = 0; k < count; k++) {
511de941241SSukumar Ghorai 				writel(*input_buf, &mmc_base->data);
512de941241SSukumar Ghorai 				input_buf++;
513de941241SSukumar Ghorai 			}
514de941241SSukumar Ghorai 			size -= (count*4);
515de941241SSukumar Ghorai 		}
516de941241SSukumar Ghorai 
517de941241SSukumar Ghorai 		if (mmc_stat & BRR_MASK)
518de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | BRR_MASK,
519de941241SSukumar Ghorai 				&mmc_base->stat);
520de941241SSukumar Ghorai 
521de941241SSukumar Ghorai 		if (mmc_stat & TC_MASK) {
522de941241SSukumar Ghorai 			writel(readl(&mmc_base->stat) | TC_MASK,
523de941241SSukumar Ghorai 				&mmc_base->stat);
524de941241SSukumar Ghorai 			break;
525de941241SSukumar Ghorai 		}
526de941241SSukumar Ghorai 	}
527de941241SSukumar Ghorai 	return 0;
528de941241SSukumar Ghorai }
529de941241SSukumar Ghorai 
530de941241SSukumar Ghorai static void mmc_set_ios(struct mmc *mmc)
531de941241SSukumar Ghorai {
532cc22b0c0SNikita Kiryanov 	struct hsmmc *mmc_base;
533de941241SSukumar Ghorai 	unsigned int dsor = 0;
534eb9a28f6SNishanth Menon 	ulong start;
535de941241SSukumar Ghorai 
536cc22b0c0SNikita Kiryanov 	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
537de941241SSukumar Ghorai 	/* configue bus width */
538de941241SSukumar Ghorai 	switch (mmc->bus_width) {
539de941241SSukumar Ghorai 	case 8:
540de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) | DTW_8_BITMODE,
541de941241SSukumar Ghorai 			&mmc_base->con);
542de941241SSukumar Ghorai 		break;
543de941241SSukumar Ghorai 
544de941241SSukumar Ghorai 	case 4:
545de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
546de941241SSukumar Ghorai 			&mmc_base->con);
547de941241SSukumar Ghorai 		writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
548de941241SSukumar Ghorai 			&mmc_base->hctl);
549de941241SSukumar Ghorai 		break;
550de941241SSukumar Ghorai 
551de941241SSukumar Ghorai 	case 1:
552de941241SSukumar Ghorai 	default:
553de941241SSukumar Ghorai 		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
554de941241SSukumar Ghorai 			&mmc_base->con);
555de941241SSukumar Ghorai 		writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
556de941241SSukumar Ghorai 			&mmc_base->hctl);
557de941241SSukumar Ghorai 		break;
558de941241SSukumar Ghorai 	}
559de941241SSukumar Ghorai 
560de941241SSukumar Ghorai 	/* configure clock with 96Mhz system clock.
561de941241SSukumar Ghorai 	 */
562de941241SSukumar Ghorai 	if (mmc->clock != 0) {
563de941241SSukumar Ghorai 		dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock);
564de941241SSukumar Ghorai 		if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock)
565de941241SSukumar Ghorai 			dsor++;
566de941241SSukumar Ghorai 	}
567de941241SSukumar Ghorai 
568de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
569de941241SSukumar Ghorai 				(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
570de941241SSukumar Ghorai 
571de941241SSukumar Ghorai 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
572de941241SSukumar Ghorai 				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
573de941241SSukumar Ghorai 
574eb9a28f6SNishanth Menon 	start = get_timer(0);
575eb9a28f6SNishanth Menon 	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
576eb9a28f6SNishanth Menon 		if (get_timer(0) - start > MAX_RETRY_MS) {
577eb9a28f6SNishanth Menon 			printf("%s: timedout waiting for ics!\n", __func__);
578eb9a28f6SNishanth Menon 			return;
579eb9a28f6SNishanth Menon 		}
580eb9a28f6SNishanth Menon 	}
581de941241SSukumar Ghorai 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
582de941241SSukumar Ghorai }
583de941241SSukumar Ghorai 
584e3913f56SNikita Kiryanov int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
585e3913f56SNikita Kiryanov 		int wp_gpio)
586de941241SSukumar Ghorai {
587cc22b0c0SNikita Kiryanov 	struct mmc *mmc = &hsmmc_dev[dev_index];
588cc22b0c0SNikita Kiryanov 	struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];
589de941241SSukumar Ghorai 
590de941241SSukumar Ghorai 	sprintf(mmc->name, "OMAP SD/MMC");
591de941241SSukumar Ghorai 	mmc->send_cmd = mmc_send_cmd;
592de941241SSukumar Ghorai 	mmc->set_ios = mmc_set_ios;
593de941241SSukumar Ghorai 	mmc->init = mmc_init_setup;
594cc22b0c0SNikita Kiryanov 	mmc->priv = priv_data;
595de941241SSukumar Ghorai 
596de941241SSukumar Ghorai 	switch (dev_index) {
597de941241SSukumar Ghorai 	case 0:
598cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
599de941241SSukumar Ghorai 		break;
6001037d585STom Rini #ifdef OMAP_HSMMC2_BASE
601de941241SSukumar Ghorai 	case 1:
602cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
603de941241SSukumar Ghorai 		break;
6041037d585STom Rini #endif
6051037d585STom Rini #ifdef OMAP_HSMMC3_BASE
606de941241SSukumar Ghorai 	case 2:
607cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
608de941241SSukumar Ghorai 		break;
6091037d585STom Rini #endif
610de941241SSukumar Ghorai 	default:
611cc22b0c0SNikita Kiryanov 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
612de941241SSukumar Ghorai 		return 1;
613de941241SSukumar Ghorai 	}
614e874d5b0SNikita Kiryanov 	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
615173ddc5bSPeter Korsgaard 	if (priv_data->cd_gpio != -1)
616173ddc5bSPeter Korsgaard 		mmc->getcd = omap_mmc_getcd;
617173ddc5bSPeter Korsgaard 
618e3913f56SNikita Kiryanov 	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
619173ddc5bSPeter Korsgaard 	if (priv_data->wp_gpio != -1)
620173ddc5bSPeter Korsgaard 		mmc->getwp = omap_mmc_getwp;
621173ddc5bSPeter Korsgaard 
622de941241SSukumar Ghorai 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
623bbbc1ae9SJonathan Solnit 	mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
624bbbc1ae9SJonathan Solnit 				MMC_MODE_HC) & ~host_caps_mask;
625de941241SSukumar Ghorai 
626de941241SSukumar Ghorai 	mmc->f_min = 400000;
627bbbc1ae9SJonathan Solnit 
628bbbc1ae9SJonathan Solnit 	if (f_max != 0)
629bbbc1ae9SJonathan Solnit 		mmc->f_max = f_max;
630bbbc1ae9SJonathan Solnit 	else {
631bbbc1ae9SJonathan Solnit 		if (mmc->host_caps & MMC_MODE_HS) {
632bbbc1ae9SJonathan Solnit 			if (mmc->host_caps & MMC_MODE_HS_52MHz)
633de941241SSukumar Ghorai 				mmc->f_max = 52000000;
634bbbc1ae9SJonathan Solnit 			else
635bbbc1ae9SJonathan Solnit 				mmc->f_max = 26000000;
636bbbc1ae9SJonathan Solnit 		} else
637bbbc1ae9SJonathan Solnit 			mmc->f_max = 20000000;
638bbbc1ae9SJonathan Solnit 	}
639de941241SSukumar Ghorai 
6408feafcc4SJohn Rigby 	mmc->b_max = 0;
6418feafcc4SJohn Rigby 
6424ca9244dSJohn Rigby #if defined(CONFIG_OMAP34XX)
6434ca9244dSJohn Rigby 	/*
6444ca9244dSJohn Rigby 	 * Silicon revs 2.1 and older do not support multiblock transfers.
6454ca9244dSJohn Rigby 	 */
6464ca9244dSJohn Rigby 	if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
6474ca9244dSJohn Rigby 		mmc->b_max = 1;
6484ca9244dSJohn Rigby #endif
6494ca9244dSJohn Rigby 
650de941241SSukumar Ghorai 	mmc_register(mmc);
651de941241SSukumar Ghorai 
652de941241SSukumar Ghorai 	return 0;
653de941241SSukumar Ghorai }
654