]>
Commit | Line | Data |
---|---|---|
de941241 SG |
1 | /* |
2 | * (C) Copyright 2008 | |
3 | * Texas Instruments, <www.ti.com> | |
4 | * Sukumar Ghorai <s-ghorai@ti.com> | |
5 | * | |
6 | * See file CREDITS for list of people who contributed to this | |
7 | * project. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU General Public License as | |
11 | * published by the Free Software Foundation's version 2 of | |
12 | * the License. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
22 | * MA 02111-1307 USA | |
23 | */ | |
24 | ||
25 | #include <config.h> | |
26 | #include <common.h> | |
93bfd616 | 27 | #include <malloc.h> |
de941241 SG |
28 | #include <mmc.h> |
29 | #include <part.h> | |
30 | #include <i2c.h> | |
31 | #include <twl4030.h> | |
14fa2dd0 | 32 | #include <twl6030.h> |
cb199102 | 33 | #include <palmas.h> |
de941241 SG |
34 | #include <asm/io.h> |
35 | #include <asm/arch/mmc_host_def.h> | |
3b68939f RQ |
36 | #if !defined(CONFIG_SOC_KEYSTONE) |
37 | #include <asm/gpio.h> | |
96e0e7b3 | 38 | #include <asm/arch/sys_proto.h> |
3b68939f | 39 | #endif |
2a48b3a2 TR |
40 | #ifdef CONFIG_MMC_OMAP36XX_PINS |
41 | #include <asm/arch/mux.h> | |
42 | #endif | |
a9d6a7e2 M |
43 | #include <dm.h> |
44 | ||
45 | DECLARE_GLOBAL_DATA_PTR; | |
de941241 | 46 | |
ab769f22 PA |
47 | /* simplify defines to OMAP_HSMMC_USE_GPIO */ |
48 | #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \ | |
49 | (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT)) | |
50 | #define OMAP_HSMMC_USE_GPIO | |
51 | #else | |
52 | #undef OMAP_HSMMC_USE_GPIO | |
53 | #endif | |
54 | ||
25c719e2 GI |
55 | /* common definitions for all OMAPs */ |
56 | #define SYSCTL_SRC (1 << 25) | |
57 | #define SYSCTL_SRD (1 << 26) | |
58 | ||
cc22b0c0 NK |
59 | struct omap_hsmmc_data { |
60 | struct hsmmc *base_addr; | |
93bfd616 | 61 | struct mmc_config cfg; |
ab769f22 | 62 | #ifdef OMAP_HSMMC_USE_GPIO |
a9d6a7e2 M |
63 | #ifdef CONFIG_DM_MMC |
64 | struct gpio_desc cd_gpio; /* Change Detect GPIO */ | |
65 | struct gpio_desc wp_gpio; /* Write Protect GPIO */ | |
66 | bool cd_inverted; | |
67 | #else | |
e874d5b0 | 68 | int cd_gpio; |
e3913f56 | 69 | int wp_gpio; |
ab769f22 | 70 | #endif |
a9d6a7e2 | 71 | #endif |
cc22b0c0 NK |
72 | }; |
73 | ||
eb9a28f6 NM |
74 | /* If we fail after 1 second wait, something is really bad */ |
75 | #define MAX_RETRY_MS 1000 | |
76 | ||
933efe64 S |
77 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size); |
78 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, | |
79 | unsigned int siz); | |
14fa2dd0 | 80 | |
ae000e23 JJH |
81 | static inline struct omap_hsmmc_data *omap_hsmmc_get_data(struct mmc *mmc) |
82 | { | |
83 | #ifdef CONFIG_DM_MMC | |
84 | return dev_get_priv(mmc->dev); | |
85 | #else | |
86 | return (struct omap_hsmmc_data *)mmc->priv; | |
87 | #endif | |
88 | } | |
89 | ||
90 | #if defined(OMAP_HSMMC_USE_GPIO) && !defined(CONFIG_DM_MMC) | |
e874d5b0 NK |
91 | static int omap_mmc_setup_gpio_in(int gpio, const char *label) |
92 | { | |
5915a2ad | 93 | int ret; |
e874d5b0 | 94 | |
5915a2ad SG |
95 | #ifndef CONFIG_DM_GPIO |
96 | if (!gpio_is_valid(gpio)) | |
e874d5b0 | 97 | return -1; |
5915a2ad SG |
98 | #endif |
99 | ret = gpio_request(gpio, label); | |
100 | if (ret) | |
101 | return ret; | |
e874d5b0 | 102 | |
5915a2ad SG |
103 | ret = gpio_direction_input(gpio); |
104 | if (ret) | |
105 | return ret; | |
e874d5b0 NK |
106 | |
107 | return gpio; | |
108 | } | |
e874d5b0 NK |
109 | #endif |
110 | ||
750121c3 | 111 | static unsigned char mmc_board_init(struct mmc *mmc) |
de941241 | 112 | { |
de941241 SG |
113 | #if defined(CONFIG_OMAP34XX) |
114 | t2_t *t2_base = (t2_t *)T2_BASE; | |
115 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; | |
b1e725f2 | 116 | u32 pbias_lite; |
6aca17c9 AF |
117 | #ifdef CONFIG_MMC_OMAP36XX_PINS |
118 | u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL); | |
119 | #endif | |
de941241 | 120 | |
b1e725f2 GI |
121 | pbias_lite = readl(&t2_base->pbias_lite); |
122 | pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0); | |
5bfdd1fc AA |
123 | #ifdef CONFIG_TARGET_OMAP3_CAIRO |
124 | /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */ | |
125 | pbias_lite &= ~PBIASLITEVMODE0; | |
6aca17c9 AF |
126 | #endif |
127 | #ifdef CONFIG_MMC_OMAP36XX_PINS | |
128 | if (get_cpu_family() == CPU_OMAP36XX) { | |
129 | /* Disable extended drain IO before changing PBIAS */ | |
130 | wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ; | |
131 | writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL); | |
132 | } | |
5bfdd1fc | 133 | #endif |
b1e725f2 | 134 | writel(pbias_lite, &t2_base->pbias_lite); |
aac5450e | 135 | |
b1e725f2 | 136 | writel(pbias_lite | PBIASLITEPWRDNZ1 | |
de941241 SG |
137 | PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0, |
138 | &t2_base->pbias_lite); | |
139 | ||
6aca17c9 AF |
140 | #ifdef CONFIG_MMC_OMAP36XX_PINS |
141 | if (get_cpu_family() == CPU_OMAP36XX) | |
142 | /* Enable extended drain IO after changing PBIAS */ | |
143 | writel(wkup_ctrl | | |
144 | OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ, | |
145 | OMAP34XX_CTRL_WKUP_CTRL); | |
146 | #endif | |
de941241 SG |
147 | writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL, |
148 | &t2_base->devconf0); | |
149 | ||
150 | writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL, | |
151 | &t2_base->devconf1); | |
152 | ||
bbbc1ae9 | 153 | /* Change from default of 52MHz to 26MHz if necessary */ |
93bfd616 | 154 | if (!(mmc->cfg->host_caps & MMC_MODE_HS_52MHz)) |
bbbc1ae9 JS |
155 | writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL, |
156 | &t2_base->ctl_prog_io1); | |
157 | ||
de941241 SG |
158 | writel(readl(&prcm_base->fclken1_core) | |
159 | EN_MMC1 | EN_MMC2 | EN_MMC3, | |
160 | &prcm_base->fclken1_core); | |
161 | ||
162 | writel(readl(&prcm_base->iclken1_core) | | |
163 | EN_MMC1 | EN_MMC2 | EN_MMC3, | |
164 | &prcm_base->iclken1_core); | |
165 | #endif | |
166 | ||
b4b06006 | 167 | #if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX) |
14fa2dd0 | 168 | /* PBIAS config needed for MMC1 only */ |
bcce53d0 | 169 | if (mmc->block_dev.devnum == 0) |
b4b06006 | 170 | vmmc_pbias_config(LDO_VOLT_3V0); |
dd23e59d | 171 | #endif |
de941241 SG |
172 | |
173 | return 0; | |
174 | } | |
175 | ||
933efe64 | 176 | void mmc_init_stream(struct hsmmc *mmc_base) |
de941241 | 177 | { |
eb9a28f6 | 178 | ulong start; |
de941241 SG |
179 | |
180 | writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con); | |
181 | ||
182 | writel(MMC_CMD0, &mmc_base->cmd); | |
eb9a28f6 NM |
183 | start = get_timer(0); |
184 | while (!(readl(&mmc_base->stat) & CC_MASK)) { | |
185 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
186 | printf("%s: timedout waiting for cc!\n", __func__); | |
187 | return; | |
188 | } | |
189 | } | |
de941241 SG |
190 | writel(CC_MASK, &mmc_base->stat) |
191 | ; | |
192 | writel(MMC_CMD0, &mmc_base->cmd) | |
193 | ; | |
eb9a28f6 NM |
194 | start = get_timer(0); |
195 | while (!(readl(&mmc_base->stat) & CC_MASK)) { | |
196 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
197 | printf("%s: timedout waiting for cc2!\n", __func__); | |
198 | return; | |
199 | } | |
200 | } | |
de941241 SG |
201 | writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con); |
202 | } | |
203 | ||
ab769f22 | 204 | static int omap_hsmmc_init_setup(struct mmc *mmc) |
de941241 | 205 | { |
ae000e23 | 206 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
cc22b0c0 | 207 | struct hsmmc *mmc_base; |
de941241 SG |
208 | unsigned int reg_val; |
209 | unsigned int dsor; | |
eb9a28f6 | 210 | ulong start; |
de941241 | 211 | |
ae000e23 | 212 | mmc_base = priv->base_addr; |
14fa2dd0 | 213 | mmc_board_init(mmc); |
de941241 SG |
214 | |
215 | writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET, | |
216 | &mmc_base->sysconfig); | |
eb9a28f6 NM |
217 | start = get_timer(0); |
218 | while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) { | |
219 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
220 | printf("%s: timedout waiting for cc2!\n", __func__); | |
915ffa52 | 221 | return -ETIMEDOUT; |
eb9a28f6 NM |
222 | } |
223 | } | |
de941241 | 224 | writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl); |
eb9a28f6 NM |
225 | start = get_timer(0); |
226 | while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) { | |
227 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
228 | printf("%s: timedout waiting for softresetall!\n", | |
229 | __func__); | |
915ffa52 | 230 | return -ETIMEDOUT; |
eb9a28f6 NM |
231 | } |
232 | } | |
de941241 SG |
233 | writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl); |
234 | writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP, | |
235 | &mmc_base->capa); | |
236 | ||
237 | reg_val = readl(&mmc_base->con) & RESERVED_MASK; | |
238 | ||
239 | writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH | | |
240 | MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK | | |
241 | HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con); | |
242 | ||
243 | dsor = 240; | |
244 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), | |
245 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); | |
246 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, | |
247 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); | |
eb9a28f6 NM |
248 | start = get_timer(0); |
249 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { | |
250 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
251 | printf("%s: timedout waiting for ics!\n", __func__); | |
915ffa52 | 252 | return -ETIMEDOUT; |
eb9a28f6 NM |
253 | } |
254 | } | |
de941241 SG |
255 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); |
256 | ||
257 | writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl); | |
258 | ||
259 | writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE | | |
260 | IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC, | |
261 | &mmc_base->ie); | |
262 | ||
263 | mmc_init_stream(mmc_base); | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
25c719e2 GI |
268 | /* |
269 | * MMC controller internal finite state machine reset | |
270 | * | |
271 | * Used to reset command or data internal state machines, using respectively | |
272 | * SRC or SRD bit of SYSCTL register | |
273 | */ | |
274 | static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit) | |
275 | { | |
276 | ulong start; | |
277 | ||
278 | mmc_reg_out(&mmc_base->sysctl, bit, bit); | |
279 | ||
61a6cc27 OT |
280 | /* |
281 | * CMD(DAT) lines reset procedures are slightly different | |
282 | * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx). | |
283 | * According to OMAP3 TRM: | |
284 | * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it | |
285 | * returns to 0x0. | |
286 | * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset | |
287 | * procedure steps must be as follows: | |
288 | * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in | |
289 | * MMCHS_SYSCTL register (SD_SYSCTL for AM335x). | |
290 | * 2. Poll the SRC(SRD) bit until it is set to 0x1. | |
291 | * 3. Wait until the SRC (SRD) bit returns to 0x0 | |
292 | * (reset procedure is completed). | |
293 | */ | |
294 | #if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ | |
dce55b93 | 295 | defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) |
61a6cc27 OT |
296 | if (!(readl(&mmc_base->sysctl) & bit)) { |
297 | start = get_timer(0); | |
298 | while (!(readl(&mmc_base->sysctl) & bit)) { | |
299 | if (get_timer(0) - start > MAX_RETRY_MS) | |
300 | return; | |
301 | } | |
302 | } | |
303 | #endif | |
25c719e2 GI |
304 | start = get_timer(0); |
305 | while ((readl(&mmc_base->sysctl) & bit) != 0) { | |
306 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
307 | printf("%s: timedout waiting for sysctl %x to clear\n", | |
308 | __func__, bit); | |
309 | return; | |
310 | } | |
311 | } | |
312 | } | |
de941241 | 313 | |
ab769f22 | 314 | static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, |
de941241 SG |
315 | struct mmc_data *data) |
316 | { | |
ae000e23 | 317 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
cc22b0c0 | 318 | struct hsmmc *mmc_base; |
de941241 | 319 | unsigned int flags, mmc_stat; |
eb9a28f6 | 320 | ulong start; |
de941241 | 321 | |
ae000e23 | 322 | mmc_base = priv->base_addr; |
eb9a28f6 | 323 | start = get_timer(0); |
a7778f8f | 324 | while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) { |
eb9a28f6 | 325 | if (get_timer(0) - start > MAX_RETRY_MS) { |
a7778f8f TR |
326 | printf("%s: timedout waiting on cmd inhibit to clear\n", |
327 | __func__); | |
915ffa52 | 328 | return -ETIMEDOUT; |
eb9a28f6 NM |
329 | } |
330 | } | |
de941241 | 331 | writel(0xFFFFFFFF, &mmc_base->stat); |
eb9a28f6 NM |
332 | start = get_timer(0); |
333 | while (readl(&mmc_base->stat)) { | |
334 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
15ceb1de GI |
335 | printf("%s: timedout waiting for STAT (%x) to clear\n", |
336 | __func__, readl(&mmc_base->stat)); | |
915ffa52 | 337 | return -ETIMEDOUT; |
eb9a28f6 NM |
338 | } |
339 | } | |
de941241 SG |
340 | /* |
341 | * CMDREG | |
342 | * CMDIDX[13:8] : Command index | |
343 | * DATAPRNT[5] : Data Present Select | |
344 | * ENCMDIDX[4] : Command Index Check Enable | |
345 | * ENCMDCRC[3] : Command CRC Check Enable | |
346 | * RSPTYP[1:0] | |
347 | * 00 = No Response | |
348 | * 01 = Length 136 | |
349 | * 10 = Length 48 | |
350 | * 11 = Length 48 Check busy after response | |
351 | */ | |
352 | /* Delay added before checking the status of frq change | |
353 | * retry not supported by mmc.c(core file) | |
354 | */ | |
355 | if (cmd->cmdidx == SD_CMD_APP_SEND_SCR) | |
356 | udelay(50000); /* wait 50 ms */ | |
357 | ||
358 | if (!(cmd->resp_type & MMC_RSP_PRESENT)) | |
359 | flags = 0; | |
360 | else if (cmd->resp_type & MMC_RSP_136) | |
361 | flags = RSP_TYPE_LGHT136 | CICE_NOCHECK; | |
362 | else if (cmd->resp_type & MMC_RSP_BUSY) | |
363 | flags = RSP_TYPE_LGHT48B; | |
364 | else | |
365 | flags = RSP_TYPE_LGHT48; | |
366 | ||
367 | /* enable default flags */ | |
368 | flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK | | |
369 | MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE); | |
370 | ||
371 | if (cmd->resp_type & MMC_RSP_CRC) | |
372 | flags |= CCCE_CHECK; | |
373 | if (cmd->resp_type & MMC_RSP_OPCODE) | |
374 | flags |= CICE_CHECK; | |
375 | ||
376 | if (data) { | |
377 | if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) || | |
378 | (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) { | |
379 | flags |= (MSBS_MULTIBLK | BCE_ENABLE); | |
380 | data->blocksize = 512; | |
381 | writel(data->blocksize | (data->blocks << 16), | |
382 | &mmc_base->blk); | |
383 | } else | |
384 | writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk); | |
385 | ||
386 | if (data->flags & MMC_DATA_READ) | |
387 | flags |= (DP_DATA | DDIR_READ); | |
388 | else | |
389 | flags |= (DP_DATA | DDIR_WRITE); | |
390 | } | |
391 | ||
392 | writel(cmd->cmdarg, &mmc_base->arg); | |
152ba363 | 393 | udelay(20); /* To fix "No status update" error on eMMC */ |
de941241 SG |
394 | writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd); |
395 | ||
eb9a28f6 | 396 | start = get_timer(0); |
de941241 SG |
397 | do { |
398 | mmc_stat = readl(&mmc_base->stat); | |
eb9a28f6 NM |
399 | if (get_timer(0) - start > MAX_RETRY_MS) { |
400 | printf("%s : timeout: No status update\n", __func__); | |
915ffa52 | 401 | return -ETIMEDOUT; |
eb9a28f6 NM |
402 | } |
403 | } while (!mmc_stat); | |
de941241 | 404 | |
25c719e2 GI |
405 | if ((mmc_stat & IE_CTO) != 0) { |
406 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); | |
915ffa52 | 407 | return -ETIMEDOUT; |
25c719e2 | 408 | } else if ((mmc_stat & ERRI_MASK) != 0) |
de941241 SG |
409 | return -1; |
410 | ||
411 | if (mmc_stat & CC_MASK) { | |
412 | writel(CC_MASK, &mmc_base->stat); | |
413 | if (cmd->resp_type & MMC_RSP_PRESENT) { | |
414 | if (cmd->resp_type & MMC_RSP_136) { | |
415 | /* response type 2 */ | |
416 | cmd->response[3] = readl(&mmc_base->rsp10); | |
417 | cmd->response[2] = readl(&mmc_base->rsp32); | |
418 | cmd->response[1] = readl(&mmc_base->rsp54); | |
419 | cmd->response[0] = readl(&mmc_base->rsp76); | |
420 | } else | |
421 | /* response types 1, 1b, 3, 4, 5, 6 */ | |
422 | cmd->response[0] = readl(&mmc_base->rsp10); | |
423 | } | |
424 | } | |
425 | ||
426 | if (data && (data->flags & MMC_DATA_READ)) { | |
427 | mmc_read_data(mmc_base, data->dest, | |
428 | data->blocksize * data->blocks); | |
429 | } else if (data && (data->flags & MMC_DATA_WRITE)) { | |
430 | mmc_write_data(mmc_base, data->src, | |
431 | data->blocksize * data->blocks); | |
432 | } | |
433 | return 0; | |
434 | } | |
435 | ||
933efe64 | 436 | static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size) |
de941241 SG |
437 | { |
438 | unsigned int *output_buf = (unsigned int *)buf; | |
439 | unsigned int mmc_stat; | |
440 | unsigned int count; | |
441 | ||
442 | /* | |
443 | * Start Polled Read | |
444 | */ | |
445 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; | |
446 | count /= 4; | |
447 | ||
448 | while (size) { | |
eb9a28f6 | 449 | ulong start = get_timer(0); |
de941241 SG |
450 | do { |
451 | mmc_stat = readl(&mmc_base->stat); | |
eb9a28f6 NM |
452 | if (get_timer(0) - start > MAX_RETRY_MS) { |
453 | printf("%s: timedout waiting for status!\n", | |
454 | __func__); | |
915ffa52 | 455 | return -ETIMEDOUT; |
eb9a28f6 | 456 | } |
de941241 SG |
457 | } while (mmc_stat == 0); |
458 | ||
25c719e2 GI |
459 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) |
460 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); | |
461 | ||
de941241 SG |
462 | if ((mmc_stat & ERRI_MASK) != 0) |
463 | return 1; | |
464 | ||
465 | if (mmc_stat & BRR_MASK) { | |
466 | unsigned int k; | |
467 | ||
468 | writel(readl(&mmc_base->stat) | BRR_MASK, | |
469 | &mmc_base->stat); | |
470 | for (k = 0; k < count; k++) { | |
471 | *output_buf = readl(&mmc_base->data); | |
472 | output_buf++; | |
473 | } | |
474 | size -= (count*4); | |
475 | } | |
476 | ||
477 | if (mmc_stat & BWR_MASK) | |
478 | writel(readl(&mmc_base->stat) | BWR_MASK, | |
479 | &mmc_base->stat); | |
480 | ||
481 | if (mmc_stat & TC_MASK) { | |
482 | writel(readl(&mmc_base->stat) | TC_MASK, | |
483 | &mmc_base->stat); | |
484 | break; | |
485 | } | |
486 | } | |
487 | return 0; | |
488 | } | |
489 | ||
933efe64 S |
490 | static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, |
491 | unsigned int size) | |
de941241 SG |
492 | { |
493 | unsigned int *input_buf = (unsigned int *)buf; | |
494 | unsigned int mmc_stat; | |
495 | unsigned int count; | |
496 | ||
497 | /* | |
152ba363 | 498 | * Start Polled Write |
de941241 SG |
499 | */ |
500 | count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size; | |
501 | count /= 4; | |
502 | ||
503 | while (size) { | |
eb9a28f6 | 504 | ulong start = get_timer(0); |
de941241 SG |
505 | do { |
506 | mmc_stat = readl(&mmc_base->stat); | |
eb9a28f6 NM |
507 | if (get_timer(0) - start > MAX_RETRY_MS) { |
508 | printf("%s: timedout waiting for status!\n", | |
509 | __func__); | |
915ffa52 | 510 | return -ETIMEDOUT; |
eb9a28f6 | 511 | } |
de941241 SG |
512 | } while (mmc_stat == 0); |
513 | ||
25c719e2 GI |
514 | if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0) |
515 | mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); | |
516 | ||
de941241 SG |
517 | if ((mmc_stat & ERRI_MASK) != 0) |
518 | return 1; | |
519 | ||
520 | if (mmc_stat & BWR_MASK) { | |
521 | unsigned int k; | |
522 | ||
523 | writel(readl(&mmc_base->stat) | BWR_MASK, | |
524 | &mmc_base->stat); | |
525 | for (k = 0; k < count; k++) { | |
526 | writel(*input_buf, &mmc_base->data); | |
527 | input_buf++; | |
528 | } | |
529 | size -= (count*4); | |
530 | } | |
531 | ||
532 | if (mmc_stat & BRR_MASK) | |
533 | writel(readl(&mmc_base->stat) | BRR_MASK, | |
534 | &mmc_base->stat); | |
535 | ||
536 | if (mmc_stat & TC_MASK) { | |
537 | writel(readl(&mmc_base->stat) | TC_MASK, | |
538 | &mmc_base->stat); | |
539 | break; | |
540 | } | |
541 | } | |
542 | return 0; | |
543 | } | |
544 | ||
07b0b9c0 | 545 | static int omap_hsmmc_set_ios(struct mmc *mmc) |
de941241 | 546 | { |
ae000e23 | 547 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
cc22b0c0 | 548 | struct hsmmc *mmc_base; |
de941241 | 549 | unsigned int dsor = 0; |
eb9a28f6 | 550 | ulong start; |
de941241 | 551 | |
ae000e23 | 552 | mmc_base = priv->base_addr; |
de941241 SG |
553 | /* configue bus width */ |
554 | switch (mmc->bus_width) { | |
555 | case 8: | |
556 | writel(readl(&mmc_base->con) | DTW_8_BITMODE, | |
557 | &mmc_base->con); | |
558 | break; | |
559 | ||
560 | case 4: | |
561 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, | |
562 | &mmc_base->con); | |
563 | writel(readl(&mmc_base->hctl) | DTW_4_BITMODE, | |
564 | &mmc_base->hctl); | |
565 | break; | |
566 | ||
567 | case 1: | |
568 | default: | |
569 | writel(readl(&mmc_base->con) & ~DTW_8_BITMODE, | |
570 | &mmc_base->con); | |
571 | writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE, | |
572 | &mmc_base->hctl); | |
573 | break; | |
574 | } | |
575 | ||
576 | /* configure clock with 96Mhz system clock. | |
577 | */ | |
578 | if (mmc->clock != 0) { | |
579 | dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock); | |
580 | if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock) | |
581 | dsor++; | |
582 | } | |
583 | ||
584 | mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK), | |
585 | (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); | |
586 | ||
587 | mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK, | |
588 | (dsor << CLKD_OFFSET) | ICE_OSCILLATE); | |
589 | ||
eb9a28f6 NM |
590 | start = get_timer(0); |
591 | while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) { | |
592 | if (get_timer(0) - start > MAX_RETRY_MS) { | |
593 | printf("%s: timedout waiting for ics!\n", __func__); | |
07b0b9c0 | 594 | return -ETIMEDOUT; |
eb9a28f6 NM |
595 | } |
596 | } | |
de941241 | 597 | writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); |
07b0b9c0 JC |
598 | |
599 | return 0; | |
de941241 SG |
600 | } |
601 | ||
ab769f22 | 602 | #ifdef OMAP_HSMMC_USE_GPIO |
a9d6a7e2 M |
603 | #ifdef CONFIG_DM_MMC |
604 | static int omap_hsmmc_getcd(struct mmc *mmc) | |
605 | { | |
ae000e23 | 606 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
a9d6a7e2 M |
607 | int value; |
608 | ||
609 | value = dm_gpio_get_value(&priv->cd_gpio); | |
610 | /* if no CD return as 1 */ | |
611 | if (value < 0) | |
612 | return 1; | |
613 | ||
614 | if (priv->cd_inverted) | |
615 | return !value; | |
616 | return value; | |
617 | } | |
618 | ||
619 | static int omap_hsmmc_getwp(struct mmc *mmc) | |
620 | { | |
ae000e23 | 621 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
a9d6a7e2 M |
622 | int value; |
623 | ||
624 | value = dm_gpio_get_value(&priv->wp_gpio); | |
625 | /* if no WP return as 0 */ | |
626 | if (value < 0) | |
627 | return 0; | |
628 | return value; | |
629 | } | |
630 | #else | |
ab769f22 PA |
631 | static int omap_hsmmc_getcd(struct mmc *mmc) |
632 | { | |
ae000e23 | 633 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
ab769f22 PA |
634 | int cd_gpio; |
635 | ||
636 | /* if no CD return as 1 */ | |
ae000e23 | 637 | cd_gpio = priv->cd_gpio; |
ab769f22 PA |
638 | if (cd_gpio < 0) |
639 | return 1; | |
640 | ||
0b03a931 IG |
641 | /* NOTE: assumes card detect signal is active-low */ |
642 | return !gpio_get_value(cd_gpio); | |
ab769f22 PA |
643 | } |
644 | ||
645 | static int omap_hsmmc_getwp(struct mmc *mmc) | |
646 | { | |
ae000e23 | 647 | struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc); |
ab769f22 PA |
648 | int wp_gpio; |
649 | ||
650 | /* if no WP return as 0 */ | |
ae000e23 | 651 | wp_gpio = priv->wp_gpio; |
ab769f22 PA |
652 | if (wp_gpio < 0) |
653 | return 0; | |
654 | ||
0b03a931 | 655 | /* NOTE: assumes write protect signal is active-high */ |
ab769f22 PA |
656 | return gpio_get_value(wp_gpio); |
657 | } | |
658 | #endif | |
a9d6a7e2 | 659 | #endif |
ab769f22 PA |
660 | |
661 | static const struct mmc_ops omap_hsmmc_ops = { | |
662 | .send_cmd = omap_hsmmc_send_cmd, | |
663 | .set_ios = omap_hsmmc_set_ios, | |
664 | .init = omap_hsmmc_init_setup, | |
665 | #ifdef OMAP_HSMMC_USE_GPIO | |
666 | .getcd = omap_hsmmc_getcd, | |
667 | .getwp = omap_hsmmc_getwp, | |
668 | #endif | |
669 | }; | |
670 | ||
a9d6a7e2 | 671 | #ifndef CONFIG_DM_MMC |
e3913f56 NK |
672 | int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, |
673 | int wp_gpio) | |
de941241 | 674 | { |
93bfd616 | 675 | struct mmc *mmc; |
ae000e23 | 676 | struct omap_hsmmc_data *priv; |
93bfd616 PA |
677 | struct mmc_config *cfg; |
678 | uint host_caps_val; | |
679 | ||
ae000e23 JJH |
680 | priv = malloc(sizeof(*priv)); |
681 | if (priv == NULL) | |
93bfd616 | 682 | return -1; |
de941241 | 683 | |
5a20397b | 684 | host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS; |
de941241 SG |
685 | |
686 | switch (dev_index) { | |
687 | case 0: | |
ae000e23 | 688 | priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; |
de941241 | 689 | break; |
1037d585 | 690 | #ifdef OMAP_HSMMC2_BASE |
de941241 | 691 | case 1: |
ae000e23 | 692 | priv->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; |
152ba363 | 693 | #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ |
3891a54f | 694 | defined(CONFIG_DRA7XX) || defined(CONFIG_AM33XX) || \ |
3b68939f RQ |
695 | defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \ |
696 | defined(CONFIG_HSMMC2_8BIT) | |
152ba363 LP |
697 | /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */ |
698 | host_caps_val |= MMC_MODE_8BIT; | |
699 | #endif | |
de941241 | 700 | break; |
1037d585 TR |
701 | #endif |
702 | #ifdef OMAP_HSMMC3_BASE | |
de941241 | 703 | case 2: |
ae000e23 | 704 | priv->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE; |
3891a54f | 705 | #if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT) |
152ba363 LP |
706 | /* Enable 8-bit interface for eMMC on DRA7XX */ |
707 | host_caps_val |= MMC_MODE_8BIT; | |
708 | #endif | |
de941241 | 709 | break; |
1037d585 | 710 | #endif |
de941241 | 711 | default: |
ae000e23 | 712 | priv->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE; |
de941241 SG |
713 | return 1; |
714 | } | |
ab769f22 PA |
715 | #ifdef OMAP_HSMMC_USE_GPIO |
716 | /* on error gpio values are set to -1, which is what we want */ | |
ae000e23 JJH |
717 | priv->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd"); |
718 | priv->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp"); | |
ab769f22 | 719 | #endif |
173ddc5b | 720 | |
ae000e23 | 721 | cfg = &priv->cfg; |
de941241 | 722 | |
93bfd616 PA |
723 | cfg->name = "OMAP SD/MMC"; |
724 | cfg->ops = &omap_hsmmc_ops; | |
725 | ||
726 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | |
727 | cfg->host_caps = host_caps_val & ~host_caps_mask; | |
728 | ||
729 | cfg->f_min = 400000; | |
bbbc1ae9 JS |
730 | |
731 | if (f_max != 0) | |
93bfd616 | 732 | cfg->f_max = f_max; |
bbbc1ae9 | 733 | else { |
93bfd616 PA |
734 | if (cfg->host_caps & MMC_MODE_HS) { |
735 | if (cfg->host_caps & MMC_MODE_HS_52MHz) | |
736 | cfg->f_max = 52000000; | |
bbbc1ae9 | 737 | else |
93bfd616 | 738 | cfg->f_max = 26000000; |
bbbc1ae9 | 739 | } else |
93bfd616 | 740 | cfg->f_max = 20000000; |
bbbc1ae9 | 741 | } |
de941241 | 742 | |
93bfd616 | 743 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; |
8feafcc4 | 744 | |
4ca9244d JR |
745 | #if defined(CONFIG_OMAP34XX) |
746 | /* | |
747 | * Silicon revs 2.1 and older do not support multiblock transfers. | |
748 | */ | |
749 | if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21)) | |
93bfd616 | 750 | cfg->b_max = 1; |
4ca9244d | 751 | #endif |
ae000e23 | 752 | mmc = mmc_create(cfg, priv); |
93bfd616 PA |
753 | if (mmc == NULL) |
754 | return -1; | |
de941241 SG |
755 | |
756 | return 0; | |
757 | } | |
a9d6a7e2 M |
758 | #else |
759 | static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev) | |
760 | { | |
761 | struct omap_hsmmc_data *priv = dev_get_priv(dev); | |
762 | const void *fdt = gd->fdt_blob; | |
e160f7d4 | 763 | int node = dev_of_offset(dev); |
a9d6a7e2 M |
764 | struct mmc_config *cfg; |
765 | int val; | |
766 | ||
4bc5e19e M |
767 | priv->base_addr = map_physmem(dev_get_addr(dev), sizeof(struct hsmmc *), |
768 | MAP_NOCACHE); | |
a9d6a7e2 M |
769 | cfg = &priv->cfg; |
770 | ||
771 | cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; | |
772 | val = fdtdec_get_int(fdt, node, "bus-width", -1); | |
773 | if (val < 0) { | |
774 | printf("error: bus-width property missing\n"); | |
775 | return -ENOENT; | |
776 | } | |
777 | ||
778 | switch (val) { | |
779 | case 0x8: | |
780 | cfg->host_caps |= MMC_MODE_8BIT; | |
781 | case 0x4: | |
782 | cfg->host_caps |= MMC_MODE_4BIT; | |
783 | break; | |
784 | default: | |
785 | printf("error: invalid bus-width property\n"); | |
786 | return -ENOENT; | |
787 | } | |
788 | ||
789 | cfg->f_min = 400000; | |
790 | cfg->f_max = fdtdec_get_int(fdt, node, "max-frequency", 52000000); | |
791 | cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; | |
792 | cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; | |
793 | ||
4de2de51 | 794 | #ifdef OMAP_HSMMC_USE_GPIO |
a9d6a7e2 | 795 | priv->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted"); |
4de2de51 | 796 | #endif |
a9d6a7e2 M |
797 | |
798 | return 0; | |
799 | } | |
800 | ||
801 | static int omap_hsmmc_probe(struct udevice *dev) | |
802 | { | |
803 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | |
804 | struct omap_hsmmc_data *priv = dev_get_priv(dev); | |
805 | struct mmc_config *cfg; | |
806 | struct mmc *mmc; | |
807 | ||
808 | cfg = &priv->cfg; | |
809 | cfg->name = "OMAP SD/MMC"; | |
810 | cfg->ops = &omap_hsmmc_ops; | |
811 | ||
812 | mmc = mmc_create(cfg, priv); | |
813 | if (mmc == NULL) | |
814 | return -1; | |
815 | ||
5cc6a245 M |
816 | #ifdef OMAP_HSMMC_USE_GPIO |
817 | gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN); | |
818 | gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN); | |
819 | #endif | |
820 | ||
cffe5d86 | 821 | mmc->dev = dev; |
a9d6a7e2 M |
822 | upriv->mmc = mmc; |
823 | ||
824 | return 0; | |
825 | } | |
826 | ||
827 | static const struct udevice_id omap_hsmmc_ids[] = { | |
828 | { .compatible = "ti,omap3-hsmmc" }, | |
829 | { .compatible = "ti,omap4-hsmmc" }, | |
830 | { .compatible = "ti,am33xx-hsmmc" }, | |
831 | { } | |
832 | }; | |
833 | ||
834 | U_BOOT_DRIVER(omap_hsmmc) = { | |
835 | .name = "omap_hsmmc", | |
836 | .id = UCLASS_MMC, | |
837 | .of_match = omap_hsmmc_ids, | |
838 | .ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata, | |
839 | .probe = omap_hsmmc_probe, | |
840 | .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data), | |
841 | }; | |
842 | #endif |