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