Blame view

drivers/mmc/omap_hsmmc.c 18.5 KB
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * (C) Copyright 2008
   * Texas Instruments, <www.ti.com>
   * Sukumar Ghorai <s-ghorai@ti.com>
   *
   * See file CREDITS for list of people who contributed to this
   * project.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation's version 2 of
   * the License.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   * MA 02111-1307 USA
   */
  
  #include <config.h>
  #include <common.h>
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
27
  #include <malloc.h>
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
28
29
30
31
  #include <mmc.h>
  #include <part.h>
  #include <i2c.h>
  #include <twl4030.h>
14fa2dd00   Balaji T K   mmc: omap: config...
32
  #include <twl6030.h>
cb199102b   Nishanth Menon   twl6035: rename t...
33
  #include <palmas.h>
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
34
  #include <asm/gpio.h>
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
35
36
  #include <asm/io.h>
  #include <asm/arch/mmc_host_def.h>
96e0e7b36   Dirk Behme   MMC: omap_hsmmc.c...
37
  #include <asm/arch/sys_proto.h>
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
38

ab769f227   Pantelis Antoniou   mmc: Remove ops f...
39
40
41
42
43
44
45
  /* simplify defines to OMAP_HSMMC_USE_GPIO */
  #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
  	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
  #define OMAP_HSMMC_USE_GPIO
  #else
  #undef OMAP_HSMMC_USE_GPIO
  #endif
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
46
47
48
  /* common definitions for all OMAPs */
  #define SYSCTL_SRC	(1 << 25)
  #define SYSCTL_SRD	(1 << 26)
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
49
50
  struct omap_hsmmc_data {
  	struct hsmmc *base_addr;
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
51
  	struct mmc_config cfg;
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
52
  #ifdef OMAP_HSMMC_USE_GPIO
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
53
  	int cd_gpio;
e3913f56a   Nikita Kiryanov   omap_hsmmc: add d...
54
  	int wp_gpio;
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
55
  #endif
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
56
  };
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
57
58
  /* If we fail after 1 second wait, something is really bad */
  #define MAX_RETRY_MS	1000
933efe641   Sricharan   omap: Checkpatch ...
59
60
61
  static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
  static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
  			unsigned int siz);
14fa2dd00   Balaji T K   mmc: omap: config...
62

ab769f227   Pantelis Antoniou   mmc: Remove ops f...
63
  #ifdef OMAP_HSMMC_USE_GPIO
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
64
65
  static int omap_mmc_setup_gpio_in(int gpio, const char *label)
  {
5915a2ad0   Simon Glass   dm: omap: gpio: S...
66
  	int ret;
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
67

5915a2ad0   Simon Glass   dm: omap: gpio: S...
68
69
  #ifndef CONFIG_DM_GPIO
  	if (!gpio_is_valid(gpio))
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
70
  		return -1;
5915a2ad0   Simon Glass   dm: omap: gpio: S...
71
72
73
74
  #endif
  	ret = gpio_request(gpio, label);
  	if (ret)
  		return ret;
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
75

5915a2ad0   Simon Glass   dm: omap: gpio: S...
76
77
78
  	ret = gpio_direction_input(gpio);
  	if (ret)
  		return ret;
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
79
80
81
  
  	return gpio;
  }
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
82
  #endif
14fa2dd00   Balaji T K   mmc: omap: config...
83
84
85
86
  #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
  static void omap4_vmmc_pbias_config(struct mmc *mmc)
  {
  	u32 value = 0;
14fa2dd00   Balaji T K   mmc: omap: config...
87

c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
88
  	value = readl((*ctrl)->control_pbiaslite);
14fa2dd00   Balaji T K   mmc: omap: config...
89
  	value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
90
  	writel(value, (*ctrl)->control_pbiaslite);
14fa2dd00   Balaji T K   mmc: omap: config...
91
92
  	/* set VMMC to 3V */
  	twl6030_power_mmc_init();
c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
93
  	value = readl((*ctrl)->control_pbiaslite);
14fa2dd00   Balaji T K   mmc: omap: config...
94
  	value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
95
  	writel(value, (*ctrl)->control_pbiaslite);
14fa2dd00   Balaji T K   mmc: omap: config...
96
97
  }
  #endif
cb199102b   Nishanth Menon   twl6035: rename t...
98
  #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
dd23e59d5   Balaji T K   omap5: pbias ldo9...
99
100
101
  static void omap5_pbias_config(struct mmc *mmc)
  {
  	u32 value = 0;
dd23e59d5   Balaji T K   omap5: pbias ldo9...
102

c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
103
  	value = readl((*ctrl)->control_pbias);
a5d439c2d   Balaji T K   mmc: omap_hsmmc: ...
104
105
106
107
  	value &= ~SDCARD_PWRDNZ;
  	writel(value, (*ctrl)->control_pbias);
  	udelay(10); /* wait 10 us */
  	value &= ~SDCARD_BIAS_PWRDNZ;
c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
108
  	writel(value, (*ctrl)->control_pbias);
dd23e59d5   Balaji T K   omap5: pbias ldo9...
109

384bcae01   Nishanth Menon   palmas: rename tw...
110
  	palmas_mmc1_poweron_ldo();
dd23e59d5   Balaji T K   omap5: pbias ldo9...
111

c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
112
  	value = readl((*ctrl)->control_pbias);
a5d439c2d   Balaji T K   mmc: omap_hsmmc: ...
113
  	value |= SDCARD_BIAS_PWRDNZ;
c43c8339f   Lokesh Vutla   ARM: OMAP4+: Make...
114
  	writel(value, (*ctrl)->control_pbias);
a5d439c2d   Balaji T K   mmc: omap_hsmmc: ...
115
116
117
118
  	udelay(150); /* wait 150 us */
  	value |= SDCARD_PWRDNZ;
  	writel(value, (*ctrl)->control_pbias);
  	udelay(150); /* wait 150 us */
dd23e59d5   Balaji T K   omap5: pbias ldo9...
119
120
  }
  #endif
750121c35   Jeroen Hofstee   mmc: prevent some...
121
  static unsigned char mmc_board_init(struct mmc *mmc)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
122
  {
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
123
124
125
  #if defined(CONFIG_OMAP34XX)
  	t2_t *t2_base = (t2_t *)T2_BASE;
  	struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
b1e725f2c   Grazvydas Ignotas   mmc: omap: follow...
126
  	u32 pbias_lite;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
127

b1e725f2c   Grazvydas Ignotas   mmc: omap: follow...
128
129
  	pbias_lite = readl(&t2_base->pbias_lite);
  	pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
5bfdd1fc9   Albert ARIBAUD \(3ADEV\)   omap3: mmc: add 1...
130
131
132
133
  #ifdef CONFIG_TARGET_OMAP3_CAIRO
  	/* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
  	pbias_lite &= ~PBIASLITEVMODE0;
  #endif
b1e725f2c   Grazvydas Ignotas   mmc: omap: follow...
134
  	writel(pbias_lite, &t2_base->pbias_lite);
aac5450ea   Paul Kocialkowski   omap_hsmmc: Board...
135

b1e725f2c   Grazvydas Ignotas   mmc: omap: follow...
136
  	writel(pbias_lite | PBIASLITEPWRDNZ1 |
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
137
138
139
140
141
142
143
144
  		PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
  		&t2_base->pbias_lite);
  
  	writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
  		&t2_base->devconf0);
  
  	writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
  		&t2_base->devconf1);
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
145
  	/* Change from default of 52MHz to 26MHz if necessary */
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
146
  	if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz))
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
147
148
  		writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
  			&t2_base->ctl_prog_io1);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
149
150
151
152
153
154
155
156
  	writel(readl(&prcm_base->fclken1_core) |
  		EN_MMC1 | EN_MMC2 | EN_MMC3,
  		&prcm_base->fclken1_core);
  
  	writel(readl(&prcm_base->iclken1_core) |
  		EN_MMC1 | EN_MMC2 | EN_MMC3,
  		&prcm_base->iclken1_core);
  #endif
14fa2dd00   Balaji T K   mmc: omap: config...
157
158
159
160
161
  #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
  	/* PBIAS config needed for MMC1 only */
  	if (mmc->block_dev.dev == 0)
  		omap4_vmmc_pbias_config(mmc);
  #endif
cb199102b   Nishanth Menon   twl6035: rename t...
162
  #if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
dd23e59d5   Balaji T K   omap5: pbias ldo9...
163
164
165
  	if (mmc->block_dev.dev == 0)
  		omap5_pbias_config(mmc);
  #endif
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
166
167
168
  
  	return 0;
  }
933efe641   Sricharan   omap: Checkpatch ...
169
  void mmc_init_stream(struct hsmmc *mmc_base)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
170
  {
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
171
  	ulong start;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
172
173
174
175
  
  	writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
  
  	writel(MMC_CMD0, &mmc_base->cmd);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
176
177
178
179
180
181
182
183
  	start = get_timer(0);
  	while (!(readl(&mmc_base->stat) & CC_MASK)) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for cc!
  ", __func__);
  			return;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
184
185
186
187
  	writel(CC_MASK, &mmc_base->stat)
  		;
  	writel(MMC_CMD0, &mmc_base->cmd)
  		;
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
188
189
190
191
192
193
194
195
  	start = get_timer(0);
  	while (!(readl(&mmc_base->stat) & CC_MASK)) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for cc2!
  ", __func__);
  			return;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
196
197
  	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
  }
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
198
  static int omap_hsmmc_init_setup(struct mmc *mmc)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
199
  {
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
200
  	struct hsmmc *mmc_base;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
201
202
  	unsigned int reg_val;
  	unsigned int dsor;
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
203
  	ulong start;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
204

cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
205
  	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
14fa2dd00   Balaji T K   mmc: omap: config...
206
  	mmc_board_init(mmc);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
207
208
209
  
  	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
  		&mmc_base->sysconfig);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
210
211
212
213
214
215
216
217
  	start = get_timer(0);
  	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for cc2!
  ", __func__);
  			return TIMEOUT;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
218
  	writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
219
220
221
222
223
224
225
226
227
  	start = get_timer(0);
  	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for softresetall!
  ",
  				__func__);
  			return TIMEOUT;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
  	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
  		&mmc_base->capa);
  
  	reg_val = readl(&mmc_base->con) & RESERVED_MASK;
  
  	writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
  		MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
  		HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
  
  	dsor = 240;
  	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
  		(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
  	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
  		(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
243
244
245
246
247
248
249
250
  	start = get_timer(0);
  	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for ics!
  ", __func__);
  			return TIMEOUT;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
251
252
253
254
255
256
257
258
259
260
261
262
  	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
  
  	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
  
  	writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
  		IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
  		&mmc_base->ie);
  
  	mmc_init_stream(mmc_base);
  
  	return 0;
  }
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
263
264
265
266
267
268
269
270
271
272
273
  /*
   * MMC controller internal finite state machine reset
   *
   * Used to reset command or data internal state machines, using respectively
   * SRC or SRD bit of SYSCTL register
   */
  static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
  {
  	ulong start;
  
  	mmc_reg_out(&mmc_base->sysctl, bit, bit);
61a6cc27b   Oleksandr Tyshchenko   omap_hsmmc: omap4...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  	/*
  	 * CMD(DAT) lines reset procedures are slightly different
  	 * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
  	 * According to OMAP3 TRM:
  	 * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
  	 * returns to 0x0.
  	 * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
  	 * procedure steps must be as follows:
  	 * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
  	 *    MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
  	 * 2. Poll the SRC(SRD) bit until it is set to 0x1.
  	 * 3. Wait until the SRC (SRD) bit returns to 0x0
  	 *    (reset procedure is completed).
  	 */
  #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
  	defined(CONFIG_AM33XX)
  	if (!(readl(&mmc_base->sysctl) & bit)) {
  		start = get_timer(0);
  		while (!(readl(&mmc_base->sysctl) & bit)) {
  			if (get_timer(0) - start > MAX_RETRY_MS)
  				return;
  		}
  	}
  #endif
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
298
299
300
301
302
303
304
305
306
307
  	start = get_timer(0);
  	while ((readl(&mmc_base->sysctl) & bit) != 0) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for sysctl %x to clear
  ",
  				__func__, bit);
  			return;
  		}
  	}
  }
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
308

ab769f227   Pantelis Antoniou   mmc: Remove ops f...
309
  static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
310
311
  			struct mmc_data *data)
  {
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
312
  	struct hsmmc *mmc_base;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
313
  	unsigned int flags, mmc_stat;
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
314
  	ulong start;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
315

cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
316
  	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
317
  	start = get_timer(0);
a7778f8fb   Tom Rini   omap_hsmmc: Wait ...
318
  	while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
319
  		if (get_timer(0) - start > MAX_RETRY_MS) {
a7778f8fb   Tom Rini   omap_hsmmc: Wait ...
320
321
322
  			printf("%s: timedout waiting on cmd inhibit to clear
  ",
  					__func__);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
323
324
325
  			return TIMEOUT;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
326
  	writel(0xFFFFFFFF, &mmc_base->stat);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
327
328
329
  	start = get_timer(0);
  	while (readl(&mmc_base->stat)) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
15ceb1de8   Grazvydas Ignotas   mmc: omap: improv...
330
331
332
  			printf("%s: timedout waiting for STAT (%x) to clear
  ",
  				__func__, readl(&mmc_base->stat));
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
333
334
335
  			return TIMEOUT;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  	/*
  	 * CMDREG
  	 * CMDIDX[13:8]	: Command index
  	 * DATAPRNT[5]	: Data Present Select
  	 * ENCMDIDX[4]	: Command Index Check Enable
  	 * ENCMDCRC[3]	: Command CRC Check Enable
  	 * RSPTYP[1:0]
  	 *	00 = No Response
  	 *	01 = Length 136
  	 *	10 = Length 48
  	 *	11 = Length 48 Check busy after response
  	 */
  	/* Delay added before checking the status of frq change
  	 * retry not supported by mmc.c(core file)
  	 */
  	if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
  		udelay(50000); /* wait 50 ms */
  
  	if (!(cmd->resp_type & MMC_RSP_PRESENT))
  		flags = 0;
  	else if (cmd->resp_type & MMC_RSP_136)
  		flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
  	else if (cmd->resp_type & MMC_RSP_BUSY)
  		flags = RSP_TYPE_LGHT48B;
  	else
  		flags = RSP_TYPE_LGHT48;
  
  	/* enable default flags */
  	flags =	flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
  			MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
  
  	if (cmd->resp_type & MMC_RSP_CRC)
  		flags |= CCCE_CHECK;
  	if (cmd->resp_type & MMC_RSP_OPCODE)
  		flags |= CICE_CHECK;
  
  	if (data) {
  		if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
  			 (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
  			flags |= (MSBS_MULTIBLK | BCE_ENABLE);
  			data->blocksize = 512;
  			writel(data->blocksize | (data->blocks << 16),
  							&mmc_base->blk);
  		} else
  			writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
  
  		if (data->flags & MMC_DATA_READ)
  			flags |= (DP_DATA | DDIR_READ);
  		else
  			flags |= (DP_DATA | DDIR_WRITE);
  	}
  
  	writel(cmd->cmdarg, &mmc_base->arg);
152ba3636   Lubomir Popov   ARM: OMAP: Enable...
389
  	udelay(20);		/* To fix "No status update" error on eMMC */
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
390
  	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
391
  	start = get_timer(0);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
392
393
  	do {
  		mmc_stat = readl(&mmc_base->stat);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
394
395
396
397
398
399
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s : timeout: No status update
  ", __func__);
  			return TIMEOUT;
  		}
  	} while (!mmc_stat);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
400

25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
401
402
  	if ((mmc_stat & IE_CTO) != 0) {
  		mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
403
  		return TIMEOUT;
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
404
  	} else if ((mmc_stat & ERRI_MASK) != 0)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  		return -1;
  
  	if (mmc_stat & CC_MASK) {
  		writel(CC_MASK, &mmc_base->stat);
  		if (cmd->resp_type & MMC_RSP_PRESENT) {
  			if (cmd->resp_type & MMC_RSP_136) {
  				/* response type 2 */
  				cmd->response[3] = readl(&mmc_base->rsp10);
  				cmd->response[2] = readl(&mmc_base->rsp32);
  				cmd->response[1] = readl(&mmc_base->rsp54);
  				cmd->response[0] = readl(&mmc_base->rsp76);
  			} else
  				/* response types 1, 1b, 3, 4, 5, 6 */
  				cmd->response[0] = readl(&mmc_base->rsp10);
  		}
  	}
  
  	if (data && (data->flags & MMC_DATA_READ)) {
  		mmc_read_data(mmc_base,	data->dest,
  				data->blocksize * data->blocks);
  	} else if (data && (data->flags & MMC_DATA_WRITE)) {
  		mmc_write_data(mmc_base, data->src,
  				data->blocksize * data->blocks);
  	}
  	return 0;
  }
933efe641   Sricharan   omap: Checkpatch ...
431
  static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
432
433
434
435
436
437
438
439
440
441
442
443
  {
  	unsigned int *output_buf = (unsigned int *)buf;
  	unsigned int mmc_stat;
  	unsigned int count;
  
  	/*
  	 * Start Polled Read
  	 */
  	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
  	count /= 4;
  
  	while (size) {
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
444
  		ulong start = get_timer(0);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
445
446
  		do {
  			mmc_stat = readl(&mmc_base->stat);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
447
448
449
450
451
452
  			if (get_timer(0) - start > MAX_RETRY_MS) {
  				printf("%s: timedout waiting for status!
  ",
  						__func__);
  				return TIMEOUT;
  			}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
453
  		} while (mmc_stat == 0);
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
454
455
  		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
  			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
  		if ((mmc_stat & ERRI_MASK) != 0)
  			return 1;
  
  		if (mmc_stat & BRR_MASK) {
  			unsigned int k;
  
  			writel(readl(&mmc_base->stat) | BRR_MASK,
  				&mmc_base->stat);
  			for (k = 0; k < count; k++) {
  				*output_buf = readl(&mmc_base->data);
  				output_buf++;
  			}
  			size -= (count*4);
  		}
  
  		if (mmc_stat & BWR_MASK)
  			writel(readl(&mmc_base->stat) | BWR_MASK,
  				&mmc_base->stat);
  
  		if (mmc_stat & TC_MASK) {
  			writel(readl(&mmc_base->stat) | TC_MASK,
  				&mmc_base->stat);
  			break;
  		}
  	}
  	return 0;
  }
933efe641   Sricharan   omap: Checkpatch ...
483
484
  static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
  				unsigned int size)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
485
486
487
488
489
490
  {
  	unsigned int *input_buf = (unsigned int *)buf;
  	unsigned int mmc_stat;
  	unsigned int count;
  
  	/*
152ba3636   Lubomir Popov   ARM: OMAP: Enable...
491
  	 * Start Polled Write
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
492
493
494
495
496
  	 */
  	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
  	count /= 4;
  
  	while (size) {
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
497
  		ulong start = get_timer(0);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
498
499
  		do {
  			mmc_stat = readl(&mmc_base->stat);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
500
501
502
503
504
505
  			if (get_timer(0) - start > MAX_RETRY_MS) {
  				printf("%s: timedout waiting for status!
  ",
  						__func__);
  				return TIMEOUT;
  			}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
506
  		} while (mmc_stat == 0);
25c719e2c   Grazvydas Ignotas   mmc: omap: handle...
507
508
  		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
  			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  		if ((mmc_stat & ERRI_MASK) != 0)
  			return 1;
  
  		if (mmc_stat & BWR_MASK) {
  			unsigned int k;
  
  			writel(readl(&mmc_base->stat) | BWR_MASK,
  					&mmc_base->stat);
  			for (k = 0; k < count; k++) {
  				writel(*input_buf, &mmc_base->data);
  				input_buf++;
  			}
  			size -= (count*4);
  		}
  
  		if (mmc_stat & BRR_MASK)
  			writel(readl(&mmc_base->stat) | BRR_MASK,
  				&mmc_base->stat);
  
  		if (mmc_stat & TC_MASK) {
  			writel(readl(&mmc_base->stat) | TC_MASK,
  				&mmc_base->stat);
  			break;
  		}
  	}
  	return 0;
  }
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
536
  static void omap_hsmmc_set_ios(struct mmc *mmc)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
537
  {
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
538
  	struct hsmmc *mmc_base;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
539
  	unsigned int dsor = 0;
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
540
  	ulong start;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
541

cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
542
  	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  	/* configue bus width */
  	switch (mmc->bus_width) {
  	case 8:
  		writel(readl(&mmc_base->con) | DTW_8_BITMODE,
  			&mmc_base->con);
  		break;
  
  	case 4:
  		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
  			&mmc_base->con);
  		writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
  			&mmc_base->hctl);
  		break;
  
  	case 1:
  	default:
  		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
  			&mmc_base->con);
  		writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
  			&mmc_base->hctl);
  		break;
  	}
  
  	/* configure clock with 96Mhz system clock.
  	 */
  	if (mmc->clock != 0) {
  		dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock);
  		if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock)
  			dsor++;
  	}
  
  	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
  				(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
  
  	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
  				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
eb9a28f69   Nishanth Menon   mmc: omap: timeou...
579
580
581
582
583
584
585
586
  	start = get_timer(0);
  	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
  		if (get_timer(0) - start > MAX_RETRY_MS) {
  			printf("%s: timedout waiting for ics!
  ", __func__);
  			return;
  		}
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
587
588
  	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
  }
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
589
590
591
592
593
594
595
596
597
598
  #ifdef OMAP_HSMMC_USE_GPIO
  static int omap_hsmmc_getcd(struct mmc *mmc)
  {
  	struct omap_hsmmc_data *priv_data = mmc->priv;
  	int cd_gpio;
  
  	/* if no CD return as 1 */
  	cd_gpio = priv_data->cd_gpio;
  	if (cd_gpio < 0)
  		return 1;
0b03a931a   Igor Grinberg   omap: hsmmc: assu...
599
600
  	/* NOTE: assumes card detect signal is active-low */
  	return !gpio_get_value(cd_gpio);
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
601
602
603
604
605
606
607
608
609
610
611
  }
  
  static int omap_hsmmc_getwp(struct mmc *mmc)
  {
  	struct omap_hsmmc_data *priv_data = mmc->priv;
  	int wp_gpio;
  
  	/* if no WP return as 0 */
  	wp_gpio = priv_data->wp_gpio;
  	if (wp_gpio < 0)
  		return 0;
0b03a931a   Igor Grinberg   omap: hsmmc: assu...
612
  	/* NOTE: assumes write protect signal is active-high */
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
613
614
615
616
617
618
619
620
621
622
623
624
625
  	return gpio_get_value(wp_gpio);
  }
  #endif
  
  static const struct mmc_ops omap_hsmmc_ops = {
  	.send_cmd	= omap_hsmmc_send_cmd,
  	.set_ios	= omap_hsmmc_set_ios,
  	.init		= omap_hsmmc_init_setup,
  #ifdef OMAP_HSMMC_USE_GPIO
  	.getcd		= omap_hsmmc_getcd,
  	.getwp		= omap_hsmmc_getwp,
  #endif
  };
e3913f56a   Nikita Kiryanov   omap_hsmmc: add d...
626
627
  int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
  		int wp_gpio)
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
628
  {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
629
630
631
632
633
634
635
636
  	struct mmc *mmc;
  	struct omap_hsmmc_data *priv_data;
  	struct mmc_config *cfg;
  	uint host_caps_val;
  
  	priv_data = malloc(sizeof(*priv_data));
  	if (priv_data == NULL)
  		return -1;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
637

5a20397b0   Rob Herring   mmc: remove the M...
638
  	host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
639
640
641
  
  	switch (dev_index) {
  	case 0:
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
642
  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
643
  		break;
1037d585d   Tom Rini   mmc: omap: Allow ...
644
  #ifdef OMAP_HSMMC2_BASE
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
645
  	case 1:
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
646
  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
152ba3636   Lubomir Popov   ARM: OMAP: Enable...
647
  #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
d11ac4b56   Felipe Balbi   arm: omap: add su...
648
649
       defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && \
  		defined(CONFIG_HSMMC2_8BIT)
152ba3636   Lubomir Popov   ARM: OMAP: Enable...
650
651
652
  		/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
  		host_caps_val |= MMC_MODE_8BIT;
  #endif
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
653
  		break;
1037d585d   Tom Rini   mmc: omap: Allow ...
654
655
  #endif
  #ifdef OMAP_HSMMC3_BASE
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
656
  	case 2:
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
657
  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
d11ac4b56   Felipe Balbi   arm: omap: add su...
658
  #if (defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX)) && defined(CONFIG_HSMMC3_8BIT)
152ba3636   Lubomir Popov   ARM: OMAP: Enable...
659
660
661
  		/* Enable 8-bit interface for eMMC on DRA7XX */
  		host_caps_val |= MMC_MODE_8BIT;
  #endif
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
662
  		break;
1037d585d   Tom Rini   mmc: omap: Allow ...
663
  #endif
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
664
  	default:
cc22b0c01   Nikita Kiryanov   omap_hsmmc: intro...
665
  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
666
667
  		return 1;
  	}
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
668
669
  #ifdef OMAP_HSMMC_USE_GPIO
  	/* on error gpio values are set to -1, which is what we want */
e874d5b00   Nikita Kiryanov   omap_hsmmc: imple...
670
  	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
e3913f56a   Nikita Kiryanov   omap_hsmmc: add d...
671
  	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
ab769f227   Pantelis Antoniou   mmc: Remove ops f...
672
  #endif
173ddc5b6   Peter Korsgaard   mmc: omap_hsmmc.c...
673

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
674
  	cfg = &priv_data->cfg;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
675

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
676
677
678
679
680
681
682
  	cfg->name = "OMAP SD/MMC";
  	cfg->ops = &omap_hsmmc_ops;
  
  	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
  	cfg->host_caps = host_caps_val & ~host_caps_mask;
  
  	cfg->f_min = 400000;
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
683
684
  
  	if (f_max != 0)
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
685
  		cfg->f_max = f_max;
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
686
  	else {
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
687
688
689
  		if (cfg->host_caps & MMC_MODE_HS) {
  			if (cfg->host_caps & MMC_MODE_HS_52MHz)
  				cfg->f_max = 52000000;
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
690
  			else
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
691
  				cfg->f_max = 26000000;
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
692
  		} else
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
693
  			cfg->f_max = 20000000;
bbbc1ae92   Jonathan Solnit   ARM:OMAP+:MMC: Ad...
694
  	}
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
695

93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
696
  	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
8feafcc49   John Rigby   MMC: make b_max u...
697

4ca9244d7   John Rigby   MMC: omap_hsmmc.c...
698
699
700
701
702
  #if defined(CONFIG_OMAP34XX)
  	/*
  	 * Silicon revs 2.1 and older do not support multiblock transfers.
  	 */
  	if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
703
  		cfg->b_max = 1;
4ca9244d7   John Rigby   MMC: omap_hsmmc.c...
704
  #endif
93bfd6167   Pantelis Antoniou   mmc: Split mmc st...
705
706
707
  	mmc = mmc_create(cfg, priv_data);
  	if (mmc == NULL)
  		return -1;
de941241a   Sukumar Ghorai   ARMV7: OMAP: Add ...
708
709
710
  
  	return 0;
  }