blob: 0f6f8b161c91a645746756cb50989e11aeea7561 [file] [log] [blame]
Andy Fleming50586ef2008-10-30 16:47:16 -05001/*
Kumar Galacc4d1222010-03-18 15:51:05 -05002 * Copyright 2007,2010 Freescale Semiconductor, Inc
Andy Fleming50586ef2008-10-30 16:47:16 -05003 * Andy Fleming
4 *
5 * Based vaguely on the pxa mmc code:
6 * (C) Copyright 2003
7 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28#include <config.h>
29#include <common.h>
30#include <command.h>
Anton Vorontsovb33433a2009-06-10 00:25:29 +040031#include <hwconfig.h>
Andy Fleming50586ef2008-10-30 16:47:16 -050032#include <mmc.h>
33#include <part.h>
34#include <malloc.h>
35#include <mmc.h>
36#include <fsl_esdhc.h>
Anton Vorontsovb33433a2009-06-10 00:25:29 +040037#include <fdt_support.h>
Andy Fleming50586ef2008-10-30 16:47:16 -050038#include <asm/io.h>
39
Andy Fleming50586ef2008-10-30 16:47:16 -050040DECLARE_GLOBAL_DATA_PTR;
41
42struct fsl_esdhc {
43 uint dsaddr;
44 uint blkattr;
45 uint cmdarg;
46 uint xfertyp;
47 uint cmdrsp0;
48 uint cmdrsp1;
49 uint cmdrsp2;
50 uint cmdrsp3;
51 uint datport;
52 uint prsstat;
53 uint proctl;
54 uint sysctl;
55 uint irqstat;
56 uint irqstaten;
57 uint irqsigen;
58 uint autoc12err;
59 uint hostcapblt;
60 uint wml;
61 char reserved1[8];
62 uint fevt;
63 char reserved2[168];
64 uint hostver;
65 char reserved3[780];
66 uint scr;
67};
68
69/* Return the XFERTYP flags for a given command and data packet */
70uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
71{
72 uint xfertyp = 0;
73
74 if (data) {
75 xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
76
77 if (data->blocks > 1) {
78 xfertyp |= XFERTYP_MSBSEL;
79 xfertyp |= XFERTYP_BCEN;
80 }
81
82 if (data->flags & MMC_DATA_READ)
83 xfertyp |= XFERTYP_DTDSEL;
84 }
85
86 if (cmd->resp_type & MMC_RSP_CRC)
87 xfertyp |= XFERTYP_CCCEN;
88 if (cmd->resp_type & MMC_RSP_OPCODE)
89 xfertyp |= XFERTYP_CICEN;
90 if (cmd->resp_type & MMC_RSP_136)
91 xfertyp |= XFERTYP_RSPTYP_136;
92 else if (cmd->resp_type & MMC_RSP_BUSY)
93 xfertyp |= XFERTYP_RSPTYP_48_BUSY;
94 else if (cmd->resp_type & MMC_RSP_PRESENT)
95 xfertyp |= XFERTYP_RSPTYP_48;
96
97 return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
98}
99
100static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
101{
102 uint wml_value;
103 int timeout;
Stefano Babicc67bee12010-02-05 15:11:27 +0100104 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
105 struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
Andy Fleming50586ef2008-10-30 16:47:16 -0500106
107 wml_value = data->blocksize/4;
108
109 if (data->flags & MMC_DATA_READ) {
110 if (wml_value > 0x10)
111 wml_value = 0x10;
112
Roy Zangab467c52010-02-09 18:23:33 +0800113 esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
Stefano Babicc67bee12010-02-05 15:11:27 +0100114 esdhc_write32(&regs->dsaddr, (u32)data->dest);
Andy Fleming50586ef2008-10-30 16:47:16 -0500115 } else {
116 if (wml_value > 0x80)
117 wml_value = 0x80;
Stefano Babicc67bee12010-02-05 15:11:27 +0100118 if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
Andy Fleming50586ef2008-10-30 16:47:16 -0500119 printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
120 return TIMEOUT;
121 }
Roy Zangab467c52010-02-09 18:23:33 +0800122
123 esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
124 wml_value << 16);
Stefano Babicc67bee12010-02-05 15:11:27 +0100125 esdhc_write32(&regs->dsaddr, (u32)data->src);
Andy Fleming50586ef2008-10-30 16:47:16 -0500126 }
127
Stefano Babicc67bee12010-02-05 15:11:27 +0100128 esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
Andy Fleming50586ef2008-10-30 16:47:16 -0500129
130 /* Calculate the timeout period for data transactions */
Stefano Babicc67bee12010-02-05 15:11:27 +0100131 timeout = fls(mmc->tran_speed/10) - 1;
Andy Fleming50586ef2008-10-30 16:47:16 -0500132 timeout -= 13;
133
134 if (timeout > 14)
135 timeout = 14;
136
137 if (timeout < 0)
138 timeout = 0;
139
Stefano Babicc67bee12010-02-05 15:11:27 +0100140 esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
Andy Fleming50586ef2008-10-30 16:47:16 -0500141
142 return 0;
143}
144
145
146/*
147 * Sends a command out on the bus. Takes the mmc pointer,
148 * a command pointer, and an optional data pointer.
149 */
150static int
151esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
152{
153 uint xfertyp;
154 uint irqstat;
Stefano Babicc67bee12010-02-05 15:11:27 +0100155 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
156 volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
Andy Fleming50586ef2008-10-30 16:47:16 -0500157
Stefano Babicc67bee12010-02-05 15:11:27 +0100158 esdhc_write32(&regs->irqstat, -1);
Andy Fleming50586ef2008-10-30 16:47:16 -0500159
160 sync();
161
162 /* Wait for the bus to be idle */
Stefano Babicc67bee12010-02-05 15:11:27 +0100163 while ((esdhc_read32(&regs->prsstat) & PRSSTAT_CICHB) ||
164 (esdhc_read32(&regs->prsstat) & PRSSTAT_CIDHB))
165 ;
Andy Fleming50586ef2008-10-30 16:47:16 -0500166
Stefano Babicc67bee12010-02-05 15:11:27 +0100167 while (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA)
168 ;
Andy Fleming50586ef2008-10-30 16:47:16 -0500169
170 /* Wait at least 8 SD clock cycles before the next command */
171 /*
172 * Note: This is way more than 8 cycles, but 1ms seems to
173 * resolve timing issues with some cards
174 */
175 udelay(1000);
176
177 /* Set up for a data transfer if we have one */
178 if (data) {
179 int err;
180
181 err = esdhc_setup_data(mmc, data);
182 if(err)
183 return err;
184 }
185
186 /* Figure out the transfer arguments */
187 xfertyp = esdhc_xfertyp(cmd, data);
188
189 /* Send the command */
Stefano Babicc67bee12010-02-05 15:11:27 +0100190 esdhc_write32(&regs->cmdarg, cmd->cmdarg);
191 esdhc_write32(&regs->xfertyp, xfertyp);
Andy Fleming50586ef2008-10-30 16:47:16 -0500192
193 /* Wait for the command to complete */
Stefano Babicc67bee12010-02-05 15:11:27 +0100194 while (!(esdhc_read32(&regs->irqstat) & IRQSTAT_CC))
195 ;
Andy Fleming50586ef2008-10-30 16:47:16 -0500196
Stefano Babicc67bee12010-02-05 15:11:27 +0100197 irqstat = esdhc_read32(&regs->irqstat);
198 esdhc_write32(&regs->irqstat, irqstat);
Andy Fleming50586ef2008-10-30 16:47:16 -0500199
200 if (irqstat & CMD_ERR)
201 return COMM_ERR;
202
203 if (irqstat & IRQSTAT_CTOE)
204 return TIMEOUT;
205
206 /* Copy the response to the response buffer */
207 if (cmd->resp_type & MMC_RSP_136) {
208 u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
209
Stefano Babicc67bee12010-02-05 15:11:27 +0100210 cmdrsp3 = esdhc_read32(&regs->cmdrsp3);
211 cmdrsp2 = esdhc_read32(&regs->cmdrsp2);
212 cmdrsp1 = esdhc_read32(&regs->cmdrsp1);
213 cmdrsp0 = esdhc_read32(&regs->cmdrsp0);
Rabin Vincent998be3d2009-04-05 13:30:56 +0530214 cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
215 cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
216 cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
217 cmd->response[3] = (cmdrsp0 << 8);
Andy Fleming50586ef2008-10-30 16:47:16 -0500218 } else
Stefano Babicc67bee12010-02-05 15:11:27 +0100219 cmd->response[0] = esdhc_read32(&regs->cmdrsp0);
Andy Fleming50586ef2008-10-30 16:47:16 -0500220
221 /* Wait until all of the blocks are transferred */
222 if (data) {
223 do {
Stefano Babicc67bee12010-02-05 15:11:27 +0100224 irqstat = esdhc_read32(&regs->irqstat);
Andy Fleming50586ef2008-10-30 16:47:16 -0500225
226 if (irqstat & DATA_ERR)
227 return COMM_ERR;
228
229 if (irqstat & IRQSTAT_DTOE)
230 return TIMEOUT;
231 } while (!(irqstat & IRQSTAT_TC) &&
Stefano Babicc67bee12010-02-05 15:11:27 +0100232 (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA));
Andy Fleming50586ef2008-10-30 16:47:16 -0500233 }
234
Stefano Babicc67bee12010-02-05 15:11:27 +0100235 esdhc_write32(&regs->irqstat, -1);
Andy Fleming50586ef2008-10-30 16:47:16 -0500236
237 return 0;
238}
239
240void set_sysctl(struct mmc *mmc, uint clock)
241{
242 int sdhc_clk = gd->sdhc_clk;
243 int div, pre_div;
Stefano Babicc67bee12010-02-05 15:11:27 +0100244 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
245 volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
Andy Fleming50586ef2008-10-30 16:47:16 -0500246 uint clk;
247
Stefano Babicc67bee12010-02-05 15:11:27 +0100248 if (clock < mmc->f_min)
249 clock = mmc->f_min;
250
Andy Fleming50586ef2008-10-30 16:47:16 -0500251 if (sdhc_clk / 16 > clock) {
252 for (pre_div = 2; pre_div < 256; pre_div *= 2)
253 if ((sdhc_clk / pre_div) <= (clock * 16))
254 break;
255 } else
256 pre_div = 2;
257
258 for (div = 1; div <= 16; div++)
259 if ((sdhc_clk / (div * pre_div)) <= clock)
260 break;
261
262 pre_div >>= 1;
263 div -= 1;
264
265 clk = (pre_div << 8) | (div << 4);
266
Kumar Galacc4d1222010-03-18 15:51:05 -0500267 esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
Stefano Babicc67bee12010-02-05 15:11:27 +0100268
269 esdhc_clrsetbits32(&regs->sysctl, SYSCTL_CLOCK_MASK, clk);
Andy Fleming50586ef2008-10-30 16:47:16 -0500270
271 udelay(10000);
272
Kumar Galacc4d1222010-03-18 15:51:05 -0500273 clk = SYSCTL_PEREN | SYSCTL_CKEN;
Stefano Babicc67bee12010-02-05 15:11:27 +0100274
275 esdhc_setbits32(&regs->sysctl, clk);
Andy Fleming50586ef2008-10-30 16:47:16 -0500276}
277
278static void esdhc_set_ios(struct mmc *mmc)
279{
Stefano Babicc67bee12010-02-05 15:11:27 +0100280 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
281 struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
Andy Fleming50586ef2008-10-30 16:47:16 -0500282
283 /* Set the clock speed */
284 set_sysctl(mmc, mmc->clock);
285
286 /* Set the bus width */
Stefano Babicc67bee12010-02-05 15:11:27 +0100287 esdhc_clrbits32(&regs->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
Andy Fleming50586ef2008-10-30 16:47:16 -0500288
289 if (mmc->bus_width == 4)
Stefano Babicc67bee12010-02-05 15:11:27 +0100290 esdhc_setbits32(&regs->proctl, PROCTL_DTW_4);
Andy Fleming50586ef2008-10-30 16:47:16 -0500291 else if (mmc->bus_width == 8)
Stefano Babicc67bee12010-02-05 15:11:27 +0100292 esdhc_setbits32(&regs->proctl, PROCTL_DTW_8);
293
Andy Fleming50586ef2008-10-30 16:47:16 -0500294}
295
296static int esdhc_init(struct mmc *mmc)
297{
Stefano Babicc67bee12010-02-05 15:11:27 +0100298 struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
299 struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
Andy Fleming50586ef2008-10-30 16:47:16 -0500300 int timeout = 1000;
Stefano Babicc67bee12010-02-05 15:11:27 +0100301 int ret = 0;
302 u8 card_absent;
Andy Fleming50586ef2008-10-30 16:47:16 -0500303
304 /* Enable cache snooping */
Stefano Babicc67bee12010-02-05 15:11:27 +0100305 if (cfg && !cfg->no_snoop)
306 esdhc_write32(&regs->scr, 0x00000040);
Andy Fleming50586ef2008-10-30 16:47:16 -0500307
Stefano Babicc67bee12010-02-05 15:11:27 +0100308 /* Reset the entire host controller */
309 esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
310
311 /* Wait until the controller is available */
312 while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
313 udelay(1000);
314
315 esdhc_write32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
Andy Fleming50586ef2008-10-30 16:47:16 -0500316
317 /* Set the initial clock speed */
318 set_sysctl(mmc, 400000);
319
320 /* Disable the BRR and BWR bits in IRQSTAT */
Stefano Babicc67bee12010-02-05 15:11:27 +0100321 esdhc_clrbits32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
Andy Fleming50586ef2008-10-30 16:47:16 -0500322
323 /* Put the PROCTL reg back to the default */
Stefano Babicc67bee12010-02-05 15:11:27 +0100324 esdhc_write32(&regs->proctl, PROCTL_INIT);
Andy Fleming50586ef2008-10-30 16:47:16 -0500325
Stefano Babicc67bee12010-02-05 15:11:27 +0100326 /* Set timout to the maximum value */
327 esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
Andy Fleming50586ef2008-10-30 16:47:16 -0500328
Stefano Babicc67bee12010-02-05 15:11:27 +0100329 /* Check if there is a callback for detecting the card */
330 if (board_mmc_getcd(&card_absent, mmc)) {
331 timeout = 1000;
332 while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) &&
333 --timeout)
334 udelay(1000);
Andy Fleming50586ef2008-10-30 16:47:16 -0500335
Stefano Babicc67bee12010-02-05 15:11:27 +0100336 if (timeout <= 0)
337 ret = NO_CARD_ERR;
338 } else {
339 if (card_absent)
340 ret = NO_CARD_ERR;
341 }
342
343 return ret;
Andy Fleming50586ef2008-10-30 16:47:16 -0500344}
345
Jerry Huang48bb3bb2010-03-18 15:57:06 -0500346static void esdhc_reset(struct fsl_esdhc *regs)
347{
348 unsigned long timeout = 100; /* wait max 100 ms */
349
350 /* reset the controller */
351 esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
352
353 /* hardware clears the bit when it is done */
354 while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
355 udelay(1000);
356 if (!timeout)
357 printf("MMC/SD: Reset never completed.\n");
358}
359
Stefano Babicc67bee12010-02-05 15:11:27 +0100360int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
Andy Fleming50586ef2008-10-30 16:47:16 -0500361{
Stefano Babicc67bee12010-02-05 15:11:27 +0100362 struct fsl_esdhc *regs;
Andy Fleming50586ef2008-10-30 16:47:16 -0500363 struct mmc *mmc;
364 u32 caps;
365
Stefano Babicc67bee12010-02-05 15:11:27 +0100366 if (!cfg)
367 return -1;
368
Andy Fleming50586ef2008-10-30 16:47:16 -0500369 mmc = malloc(sizeof(struct mmc));
370
371 sprintf(mmc->name, "FSL_ESDHC");
Stefano Babicc67bee12010-02-05 15:11:27 +0100372 regs = (struct fsl_esdhc *)cfg->esdhc_base;
373
Jerry Huang48bb3bb2010-03-18 15:57:06 -0500374 /* First reset the eSDHC controller */
375 esdhc_reset(regs);
376
Stefano Babicc67bee12010-02-05 15:11:27 +0100377 mmc->priv = cfg;
Andy Fleming50586ef2008-10-30 16:47:16 -0500378 mmc->send_cmd = esdhc_send_cmd;
379 mmc->set_ios = esdhc_set_ios;
380 mmc->init = esdhc_init;
381
382 caps = regs->hostcapblt;
383
384 if (caps & ESDHC_HOSTCAPBLT_VS18)
385 mmc->voltages |= MMC_VDD_165_195;
386 if (caps & ESDHC_HOSTCAPBLT_VS30)
387 mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
388 if (caps & ESDHC_HOSTCAPBLT_VS33)
389 mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
390
391 mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
392
393 if (caps & ESDHC_HOSTCAPBLT_HSS)
394 mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
395
396 mmc->f_min = 400000;
397 mmc->f_max = MIN(gd->sdhc_clk, 50000000);
398
399 mmc_register(mmc);
400
401 return 0;
402}
403
404int fsl_esdhc_mmc_init(bd_t *bis)
405{
Stefano Babicc67bee12010-02-05 15:11:27 +0100406 struct fsl_esdhc_cfg *cfg;
407
408 cfg = malloc(sizeof(struct fsl_esdhc_cfg));
409 memset(cfg, 0, sizeof(struct fsl_esdhc_cfg));
410 cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR;
411 return fsl_esdhc_initialize(bis, cfg);
Andy Fleming50586ef2008-10-30 16:47:16 -0500412}
Anton Vorontsovb33433a2009-06-10 00:25:29 +0400413
Stefano Babicc67bee12010-02-05 15:11:27 +0100414#ifdef CONFIG_OF_LIBFDT
Anton Vorontsovb33433a2009-06-10 00:25:29 +0400415void fdt_fixup_esdhc(void *blob, bd_t *bd)
416{
417 const char *compat = "fsl,esdhc";
418 const char *status = "okay";
419
420 if (!hwconfig("esdhc")) {
421 status = "disabled";
422 goto out;
423 }
424
425 do_fixup_by_compat_u32(blob, compat, "clock-frequency",
426 gd->sdhc_clk, 1);
427out:
428 do_fixup_by_compat(blob, compat, "status", status,
429 strlen(status) + 1, 1);
430}
Stefano Babicc67bee12010-02-05 15:11:27 +0100431#endif