]>
Commit | Line | Data |
---|---|---|
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 | ||
39 | DECLARE_GLOBAL_DATA_PTR; | |
40 | ||
41 | struct 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 */ | |
69 | uint 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 | ||
99 | static 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(®s->dsaddr, (u32)data->dest); | |
114 | } else { | |
115 | if (wml_value > 0x80) | |
116 | wml_value = 0x80; | |
117 | if ((in_be32(®s->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(®s->dsaddr, (u32)data->src); | |
123 | } | |
124 | ||
125 | out_be32(®s->wml, wml_value); | |
126 | ||
127 | out_be32(®s->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(®s->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 | */ | |
149 | static int | |
150 | esdhc_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(®s->irqstat, -1); | |
157 | ||
158 | sync(); | |
159 | ||
160 | /* Wait for the bus to be idle */ | |
161 | while ((in_be32(®s->prsstat) & PRSSTAT_CICHB) || | |
162 | (in_be32(®s->prsstat) & PRSSTAT_CIDHB)); | |
163 | ||
164 | while (in_be32(®s->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(®s->cmdarg, cmd->cmdarg); | |
187 | out_be32(®s->xfertyp, xfertyp); | |
188 | ||
189 | /* Wait for the command to complete */ | |
190 | while (!(in_be32(®s->irqstat) & IRQSTAT_CC)); | |
191 | ||
192 | irqstat = in_be32(®s->irqstat); | |
193 | out_be32(®s->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(®s->cmdrsp3); | |
206 | cmdrsp2 = in_be32(®s->cmdrsp2); | |
207 | cmdrsp1 = in_be32(®s->cmdrsp1); | |
208 | cmdrsp0 = in_be32(®s->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(®s->cmdrsp0); |
50586ef2 AF |
215 | |
216 | /* Wait until all of the blocks are transferred */ | |
217 | if (data) { | |
218 | do { | |
219 | irqstat = in_be32(®s->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(®s->prsstat) & PRSSTAT_DLA)); | |
228 | } | |
229 | ||
230 | out_be32(®s->irqstat, -1); | |
231 | ||
232 | return 0; | |
233 | } | |
234 | ||
235 | void 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(®s->sysctl, SYSCTL_CLOCK_MASK, clk); | |
259 | ||
260 | udelay(10000); | |
261 | ||
262 | setbits_be32(®s->sysctl, SYSCTL_PEREN); | |
263 | } | |
264 | ||
265 | static 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(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); | |
274 | ||
275 | if (mmc->bus_width == 4) | |
276 | setbits_be32(®s->proctl, PROCTL_DTW_4); | |
277 | else if (mmc->bus_width == 8) | |
278 | setbits_be32(®s->proctl, PROCTL_DTW_8); | |
279 | } | |
280 | ||
281 | static 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(®s->scr, 0x00000040); | |
288 | ||
289 | out_be32(®s->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(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR); | |
296 | ||
297 | /* Put the PROCTL reg back to the default */ | |
298 | out_be32(®s->proctl, PROCTL_INIT); | |
299 | ||
300 | while (!(in_be32(®s->prsstat) & PRSSTAT_CINS) && --timeout) | |
301 | udelay(1000); | |
302 | ||
303 | if (timeout <= 0) | |
304 | return NO_CARD_ERR; | |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
309 | static 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 | ||
345 | int fsl_esdhc_mmc_init(bd_t *bis) | |
346 | { | |
347 | return esdhc_initialize(bis); | |
348 | } |