]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/mmc/fsl_esdhc.c
Add simple hwconfig infrastructure
[people/ms/u-boot.git] / drivers / mmc / fsl_esdhc.c
CommitLineData
50586ef2
AF
1/*
2 * Copyright 2007, Freescale Semiconductor, Inc
3 * 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>
31#include <mmc.h>
32#include <part.h>
33#include <malloc.h>
34#include <mmc.h>
35#include <fsl_esdhc.h>
36#include <asm/io.h>
37
38
39DECLARE_GLOBAL_DATA_PTR;
40
41struct fsl_esdhc {
42 uint dsaddr;
43 uint blkattr;
44 uint cmdarg;
45 uint xfertyp;
46 uint cmdrsp0;
47 uint cmdrsp1;
48 uint cmdrsp2;
49 uint cmdrsp3;
50 uint datport;
51 uint prsstat;
52 uint proctl;
53 uint sysctl;
54 uint irqstat;
55 uint irqstaten;
56 uint irqsigen;
57 uint autoc12err;
58 uint hostcapblt;
59 uint wml;
60 char reserved1[8];
61 uint fevt;
62 char reserved2[168];
63 uint hostver;
64 char reserved3[780];
65 uint scr;
66};
67
68/* Return the XFERTYP flags for a given command and data packet */
69uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
70{
71 uint xfertyp = 0;
72
73 if (data) {
74 xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
75
76 if (data->blocks > 1) {
77 xfertyp |= XFERTYP_MSBSEL;
78 xfertyp |= XFERTYP_BCEN;
79 }
80
81 if (data->flags & MMC_DATA_READ)
82 xfertyp |= XFERTYP_DTDSEL;
83 }
84
85 if (cmd->resp_type & MMC_RSP_CRC)
86 xfertyp |= XFERTYP_CCCEN;
87 if (cmd->resp_type & MMC_RSP_OPCODE)
88 xfertyp |= XFERTYP_CICEN;
89 if (cmd->resp_type & MMC_RSP_136)
90 xfertyp |= XFERTYP_RSPTYP_136;
91 else if (cmd->resp_type & MMC_RSP_BUSY)
92 xfertyp |= XFERTYP_RSPTYP_48_BUSY;
93 else if (cmd->resp_type & MMC_RSP_PRESENT)
94 xfertyp |= XFERTYP_RSPTYP_48;
95
96 return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
97}
98
99static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
100{
101 uint wml_value;
102 int timeout;
103 struct fsl_esdhc *regs = mmc->priv;
104
105 wml_value = data->blocksize/4;
106
107 if (data->flags & MMC_DATA_READ) {
108 if (wml_value > 0x10)
109 wml_value = 0x10;
110
111 wml_value = 0x100000 | wml_value;
112
113 out_be32(&regs->dsaddr, (u32)data->dest);
114 } else {
115 if (wml_value > 0x80)
116 wml_value = 0x80;
117 if ((in_be32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
118 printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
119 return TIMEOUT;
120 }
121 wml_value = wml_value << 16 | 0x10;
122 out_be32(&regs->dsaddr, (u32)data->src);
123 }
124
125 out_be32(&regs->wml, wml_value);
126
127 out_be32(&regs->blkattr, data->blocks << 16 | data->blocksize);
128
129 /* Calculate the timeout period for data transactions */
130 timeout = __ilog2(mmc->tran_speed/10);
131 timeout -= 13;
132
133 if (timeout > 14)
134 timeout = 14;
135
136 if (timeout < 0)
137 timeout = 0;
138
139 clrsetbits_be32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
140
141 return 0;
142}
143
144
145/*
146 * Sends a command out on the bus. Takes the mmc pointer,
147 * a command pointer, and an optional data pointer.
148 */
149static int
150esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
151{
152 uint xfertyp;
153 uint irqstat;
154 volatile struct fsl_esdhc *regs = mmc->priv;
155
156 out_be32(&regs->irqstat, -1);
157
158 sync();
159
160 /* Wait for the bus to be idle */
161 while ((in_be32(&regs->prsstat) & PRSSTAT_CICHB) ||
162 (in_be32(&regs->prsstat) & PRSSTAT_CIDHB));
163
164 while (in_be32(&regs->prsstat) & PRSSTAT_DLA);
165
166 /* Wait at least 8 SD clock cycles before the next command */
167 /*
168 * Note: This is way more than 8 cycles, but 1ms seems to
169 * resolve timing issues with some cards
170 */
171 udelay(1000);
172
173 /* Set up for a data transfer if we have one */
174 if (data) {
175 int err;
176
177 err = esdhc_setup_data(mmc, data);
178 if(err)
179 return err;
180 }
181
182 /* Figure out the transfer arguments */
183 xfertyp = esdhc_xfertyp(cmd, data);
184
185 /* Send the command */
186 out_be32(&regs->cmdarg, cmd->cmdarg);
187 out_be32(&regs->xfertyp, xfertyp);
188
189 /* Wait for the command to complete */
190 while (!(in_be32(&regs->irqstat) & IRQSTAT_CC));
191
192 irqstat = in_be32(&regs->irqstat);
193 out_be32(&regs->irqstat, irqstat);
194
195 if (irqstat & CMD_ERR)
196 return COMM_ERR;
197
198 if (irqstat & IRQSTAT_CTOE)
199 return TIMEOUT;
200
201 /* Copy the response to the response buffer */
202 if (cmd->resp_type & MMC_RSP_136) {
203 u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
204
205 cmdrsp3 = in_be32(&regs->cmdrsp3);
206 cmdrsp2 = in_be32(&regs->cmdrsp2);
207 cmdrsp1 = in_be32(&regs->cmdrsp1);
208 cmdrsp0 = in_be32(&regs->cmdrsp0);
998be3dd
RV
209 cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
210 cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
211 cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
212 cmd->response[3] = (cmdrsp0 << 8);
50586ef2 213 } else
998be3dd 214 cmd->response[0] = in_be32(&regs->cmdrsp0);
50586ef2
AF
215
216 /* Wait until all of the blocks are transferred */
217 if (data) {
218 do {
219 irqstat = in_be32(&regs->irqstat);
220
221 if (irqstat & DATA_ERR)
222 return COMM_ERR;
223
224 if (irqstat & IRQSTAT_DTOE)
225 return TIMEOUT;
226 } while (!(irqstat & IRQSTAT_TC) &&
227 (in_be32(&regs->prsstat) & PRSSTAT_DLA));
228 }
229
230 out_be32(&regs->irqstat, -1);
231
232 return 0;
233}
234
235void set_sysctl(struct mmc *mmc, uint clock)
236{
237 int sdhc_clk = gd->sdhc_clk;
238 int div, pre_div;
239 volatile struct fsl_esdhc *regs = mmc->priv;
240 uint clk;
241
242 if (sdhc_clk / 16 > clock) {
243 for (pre_div = 2; pre_div < 256; pre_div *= 2)
244 if ((sdhc_clk / pre_div) <= (clock * 16))
245 break;
246 } else
247 pre_div = 2;
248
249 for (div = 1; div <= 16; div++)
250 if ((sdhc_clk / (div * pre_div)) <= clock)
251 break;
252
253 pre_div >>= 1;
254 div -= 1;
255
256 clk = (pre_div << 8) | (div << 4);
257
258 clrsetbits_be32(&regs->sysctl, SYSCTL_CLOCK_MASK, clk);
259
260 udelay(10000);
261
262 setbits_be32(&regs->sysctl, SYSCTL_PEREN);
263}
264
265static void esdhc_set_ios(struct mmc *mmc)
266{
267 struct fsl_esdhc *regs = mmc->priv;
268
269 /* Set the clock speed */
270 set_sysctl(mmc, mmc->clock);
271
272 /* Set the bus width */
273 clrbits_be32(&regs->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
274
275 if (mmc->bus_width == 4)
276 setbits_be32(&regs->proctl, PROCTL_DTW_4);
277 else if (mmc->bus_width == 8)
278 setbits_be32(&regs->proctl, PROCTL_DTW_8);
279}
280
281static int esdhc_init(struct mmc *mmc)
282{
283 struct fsl_esdhc *regs = mmc->priv;
284 int timeout = 1000;
285
286 /* Enable cache snooping */
287 out_be32(&regs->scr, 0x00000040);
288
289 out_be32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
290
291 /* Set the initial clock speed */
292 set_sysctl(mmc, 400000);
293
294 /* Disable the BRR and BWR bits in IRQSTAT */
295 clrbits_be32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
296
297 /* Put the PROCTL reg back to the default */
298 out_be32(&regs->proctl, PROCTL_INIT);
299
300 while (!(in_be32(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
301 udelay(1000);
302
303 if (timeout <= 0)
304 return NO_CARD_ERR;
305
306 return 0;
307}
308
309static int esdhc_initialize(bd_t *bis)
310{
311 struct fsl_esdhc *regs = (struct fsl_esdhc *)CONFIG_SYS_FSL_ESDHC_ADDR;
312 struct mmc *mmc;
313 u32 caps;
314
315 mmc = malloc(sizeof(struct mmc));
316
317 sprintf(mmc->name, "FSL_ESDHC");
318 mmc->priv = regs;
319 mmc->send_cmd = esdhc_send_cmd;
320 mmc->set_ios = esdhc_set_ios;
321 mmc->init = esdhc_init;
322
323 caps = regs->hostcapblt;
324
325 if (caps & ESDHC_HOSTCAPBLT_VS18)
326 mmc->voltages |= MMC_VDD_165_195;
327 if (caps & ESDHC_HOSTCAPBLT_VS30)
328 mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
329 if (caps & ESDHC_HOSTCAPBLT_VS33)
330 mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
331
332 mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
333
334 if (caps & ESDHC_HOSTCAPBLT_HSS)
335 mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
336
337 mmc->f_min = 400000;
338 mmc->f_max = MIN(gd->sdhc_clk, 50000000);
339
340 mmc_register(mmc);
341
342 return 0;
343}
344
345int fsl_esdhc_mmc_init(bd_t *bis)
346{
347 return esdhc_initialize(bis);
348}