]>
Commit | Line | Data |
---|---|---|
fc26c97b HS |
1 | /* |
2 | * Copyright (C) 2004-2006 Atmel Corporation | |
3 | * | |
4 | * See file CREDITS for list of people who contributed to this | |
5 | * project. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2 of | |
10 | * the License, or (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
20 | * MA 02111-1307 USA | |
21 | */ | |
22 | #include <common.h> | |
23 | ||
fc26c97b HS |
24 | #include <part.h> |
25 | #include <mmc.h> | |
26 | ||
27 | #include <asm/io.h> | |
28 | #include <asm/errno.h> | |
29 | #include <asm/byteorder.h> | |
30 | #include <asm/arch/clk.h> | |
31 | #include <asm/arch/memory-map.h> | |
32 | ||
33 | #include "atmel_mci.h" | |
34 | ||
35 | #ifdef DEBUG | |
36 | #define pr_debug(fmt, args...) printf(fmt, ##args) | |
37 | #else | |
38 | #define pr_debug(...) do { } while(0) | |
39 | #endif | |
40 | ||
6d0f6bcf JCPV |
41 | #ifndef CONFIG_SYS_MMC_CLK_OD |
42 | #define CONFIG_SYS_MMC_CLK_OD 150000 | |
fc26c97b HS |
43 | #endif |
44 | ||
6d0f6bcf JCPV |
45 | #ifndef CONFIG_SYS_MMC_CLK_PP |
46 | #define CONFIG_SYS_MMC_CLK_PP 5000000 | |
fc26c97b HS |
47 | #endif |
48 | ||
6d0f6bcf JCPV |
49 | #ifndef CONFIG_SYS_MMC_OP_COND |
50 | #define CONFIG_SYS_MMC_OP_COND 0x00100000 | |
fc26c97b HS |
51 | #endif |
52 | ||
53 | #define MMC_DEFAULT_BLKLEN 512 | |
54 | #define MMC_DEFAULT_RCA 1 | |
55 | ||
56 | static unsigned int mmc_rca; | |
a0845830 | 57 | static int mmc_card_is_sd; |
fc26c97b HS |
58 | static block_dev_desc_t mmc_blkdev; |
59 | ||
60 | block_dev_desc_t *mmc_get_dev(int dev) | |
61 | { | |
62 | return &mmc_blkdev; | |
63 | } | |
64 | ||
65 | static void mci_set_mode(unsigned long hz, unsigned long blklen) | |
66 | { | |
67 | unsigned long bus_hz; | |
68 | unsigned long clkdiv; | |
69 | ||
70 | bus_hz = get_mci_clk_rate(); | |
71 | clkdiv = (bus_hz / hz) / 2 - 1; | |
72 | ||
73 | pr_debug("mmc: setting clock %lu Hz, block size %lu\n", | |
74 | hz, blklen); | |
75 | ||
76 | if (clkdiv & ~255UL) { | |
77 | clkdiv = 255; | |
78 | printf("mmc: clock %lu too low; setting CLKDIV to 255\n", | |
79 | hz); | |
80 | } | |
81 | ||
82 | blklen &= 0xfffc; | |
83 | mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) | |
f0d1246e HS |
84 | | MMCI_BF(BLKLEN, blklen) |
85 | | MMCI_BIT(RDPROOF) | |
86 | | MMCI_BIT(WRPROOF))); | |
fc26c97b HS |
87 | } |
88 | ||
89 | #define RESP_NO_CRC 1 | |
90 | #define R1 MMCI_BF(RSPTYP, 1) | |
91 | #define R2 MMCI_BF(RSPTYP, 2) | |
92 | #define R3 (R1 | RESP_NO_CRC) | |
93 | #define R6 R1 | |
94 | #define NID MMCI_BF(MAXLAT, 0) | |
95 | #define NCR MMCI_BF(MAXLAT, 1) | |
96 | #define TRCMD_START MMCI_BF(TRCMD, 1) | |
97 | #define TRDIR_READ MMCI_BF(TRDIR, 1) | |
98 | #define TRTYP_BLOCK MMCI_BF(TRTYP, 0) | |
99 | #define INIT_CMD MMCI_BF(SPCMD, 1) | |
100 | #define OPEN_DRAIN MMCI_BF(OPDCMD, 1) | |
101 | ||
102 | #define ERROR_FLAGS (MMCI_BIT(DTOE) \ | |
103 | | MMCI_BIT(RDIRE) \ | |
104 | | MMCI_BIT(RENDE) \ | |
105 | | MMCI_BIT(RINDE) \ | |
106 | | MMCI_BIT(RTOE)) | |
107 | ||
108 | static int | |
109 | mmc_cmd(unsigned long cmd, unsigned long arg, | |
110 | void *resp, unsigned long flags) | |
111 | { | |
112 | unsigned long *response = resp; | |
113 | int i, response_words = 0; | |
114 | unsigned long error_flags; | |
115 | u32 status; | |
116 | ||
117 | pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", | |
118 | cmd, arg, flags); | |
119 | ||
120 | error_flags = ERROR_FLAGS; | |
121 | if (!(flags & RESP_NO_CRC)) | |
122 | error_flags |= MMCI_BIT(RCRCE); | |
123 | ||
124 | flags &= ~MMCI_BF(CMDNB, ~0UL); | |
125 | ||
126 | if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) | |
127 | response_words = 1; | |
128 | else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) | |
129 | response_words = 4; | |
130 | ||
131 | mmci_writel(ARGR, arg); | |
132 | mmci_writel(CMDR, cmd | flags); | |
133 | do { | |
134 | udelay(40); | |
135 | status = mmci_readl(SR); | |
136 | } while (!(status & MMCI_BIT(CMDRDY))); | |
137 | ||
f2302d44 | 138 | pr_debug("mmc: status 0x%08x\n", status); |
fc26c97b | 139 | |
e92a5bf8 | 140 | if (status & error_flags) { |
f2302d44 | 141 | printf("mmc: command %lu failed (status: 0x%08x)\n", |
fc26c97b HS |
142 | cmd, status); |
143 | return -EIO; | |
144 | } | |
145 | ||
146 | if (response_words) | |
147 | pr_debug("mmc: response:"); | |
148 | ||
149 | for (i = 0; i < response_words; i++) { | |
150 | response[i] = mmci_readl(RSPR); | |
151 | pr_debug(" %08lx", response[i]); | |
152 | } | |
153 | pr_debug("\n"); | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
158 | static int mmc_acmd(unsigned long cmd, unsigned long arg, | |
159 | void *resp, unsigned long flags) | |
160 | { | |
161 | unsigned long aresp[4]; | |
162 | int ret; | |
163 | ||
164 | /* | |
165 | * Seems like the APP_CMD part of an ACMD has 64 cycles max | |
166 | * latency even though the ACMD part doesn't. This isn't | |
167 | * entirely clear in the SD Card spec, but some cards refuse | |
168 | * to work if we attempt to use 5 cycles max latency here... | |
169 | */ | |
170 | ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, | |
171 | R1 | NCR | (flags & OPEN_DRAIN)); | |
172 | if (ret) | |
173 | return ret; | |
174 | if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) | |
175 | return -ENODEV; | |
176 | ||
177 | ret = mmc_cmd(cmd, arg, resp, flags); | |
178 | return ret; | |
179 | } | |
180 | ||
181 | static unsigned long | |
182 | mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, | |
7a96ddad | 183 | void *buffer) |
fc26c97b HS |
184 | { |
185 | int ret, i = 0; | |
186 | unsigned long resp[4]; | |
187 | unsigned long card_status, data; | |
188 | unsigned long wordcount; | |
7a96ddad | 189 | u32 *p = buffer; |
fc26c97b HS |
190 | u32 status; |
191 | ||
192 | if (blkcnt == 0) | |
193 | return 0; | |
194 | ||
195 | pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", | |
196 | dev, start, blkcnt); | |
197 | ||
198 | /* Put the device into Transfer state */ | |
199 | ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); | |
4d5fa99c | 200 | if (ret) goto out; |
fc26c97b HS |
201 | |
202 | /* Set block length */ | |
203 | ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); | |
4d5fa99c | 204 | if (ret) goto out; |
fc26c97b HS |
205 | |
206 | pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); | |
207 | ||
208 | for (i = 0; i < blkcnt; i++, start++) { | |
209 | ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, | |
210 | start * mmc_blkdev.blksz, resp, | |
211 | (R1 | NCR | TRCMD_START | TRDIR_READ | |
212 | | TRTYP_BLOCK)); | |
4d5fa99c | 213 | if (ret) goto out; |
fc26c97b HS |
214 | |
215 | ret = -EIO; | |
216 | wordcount = 0; | |
217 | do { | |
218 | do { | |
219 | status = mmci_readl(SR); | |
220 | if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) | |
4d5fa99c | 221 | goto read_error; |
fc26c97b HS |
222 | } while (!(status & MMCI_BIT(RXRDY))); |
223 | ||
224 | if (status & MMCI_BIT(RXRDY)) { | |
225 | data = mmci_readl(RDR); | |
b99c1e6d | 226 | /* pr_debug("%x\n", data); */ |
7a96ddad | 227 | *p++ = data; |
fc26c97b HS |
228 | wordcount++; |
229 | } | |
f0d1246e | 230 | } while(wordcount < (mmc_blkdev.blksz / 4)); |
fc26c97b HS |
231 | |
232 | pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); | |
233 | ||
234 | do { | |
235 | status = mmci_readl(SR); | |
236 | } while (!(status & MMCI_BIT(BLKE))); | |
237 | ||
238 | putc('.'); | |
239 | } | |
240 | ||
241 | out: | |
242 | /* Put the device back into Standby state */ | |
243 | mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); | |
244 | return i; | |
245 | ||
4d5fa99c | 246 | read_error: |
fc26c97b | 247 | mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); |
f2302d44 | 248 | printf("mmc: bread failed, status = %08x, card status = %08lx\n", |
4d5fa99c | 249 | status, card_status); |
fc26c97b HS |
250 | goto out; |
251 | } | |
252 | ||
253 | static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) | |
254 | { | |
255 | cid->mid = resp[0] >> 24; | |
256 | cid->oid = (resp[0] >> 8) & 0xffff; | |
257 | cid->pnm[0] = resp[0]; | |
258 | cid->pnm[1] = resp[1] >> 24; | |
259 | cid->pnm[2] = resp[1] >> 16; | |
260 | cid->pnm[3] = resp[1] >> 8; | |
261 | cid->pnm[4] = resp[1]; | |
262 | cid->pnm[5] = resp[2] >> 24; | |
263 | cid->pnm[6] = 0; | |
264 | cid->prv = resp[2] >> 16; | |
265 | cid->psn = (resp[2] << 16) | (resp[3] >> 16); | |
266 | cid->mdt = resp[3] >> 8; | |
267 | } | |
268 | ||
269 | static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) | |
270 | { | |
271 | cid->mid = resp[0] >> 24; | |
272 | cid->oid = (resp[0] >> 8) & 0xffff; | |
273 | cid->pnm[0] = resp[0]; | |
274 | cid->pnm[1] = resp[1] >> 24; | |
275 | cid->pnm[2] = resp[1] >> 16; | |
276 | cid->pnm[3] = resp[1] >> 8; | |
277 | cid->pnm[4] = resp[1]; | |
278 | cid->pnm[5] = 0; | |
279 | cid->pnm[6] = 0; | |
280 | cid->prv = resp[2] >> 24; | |
281 | cid->psn = (resp[2] << 8) | (resp[3] >> 24); | |
282 | cid->mdt = (resp[3] >> 8) & 0x0fff; | |
283 | } | |
284 | ||
285 | static void mmc_dump_cid(const struct mmc_cid *cid) | |
286 | { | |
f2302d44 SR |
287 | printf("Manufacturer ID: %02X\n", cid->mid); |
288 | printf("OEM/Application ID: %04X\n", cid->oid); | |
fc26c97b | 289 | printf("Product name: %s\n", cid->pnm); |
f2302d44 | 290 | printf("Product Revision: %u.%u\n", |
fc26c97b HS |
291 | cid->prv >> 4, cid->prv & 0x0f); |
292 | printf("Product Serial Number: %lu\n", cid->psn); | |
f2302d44 | 293 | printf("Manufacturing Date: %02u/%02u\n", |
fc26c97b HS |
294 | cid->mdt >> 4, cid->mdt & 0x0f); |
295 | } | |
296 | ||
297 | static void mmc_dump_csd(const struct mmc_csd *csd) | |
298 | { | |
299 | unsigned long *csd_raw = (unsigned long *)csd; | |
300 | printf("CSD data: %08lx %08lx %08lx %08lx\n", | |
301 | csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); | |
302 | printf("CSD structure version: 1.%u\n", csd->csd_structure); | |
303 | printf("MMC System Spec version: %u\n", csd->spec_vers); | |
304 | printf("Card command classes: %03x\n", csd->ccc); | |
305 | printf("Read block length: %u\n", 1 << csd->read_bl_len); | |
306 | if (csd->read_bl_partial) | |
307 | puts("Supports partial reads\n"); | |
308 | else | |
309 | puts("Does not support partial reads\n"); | |
310 | printf("Write block length: %u\n", 1 << csd->write_bl_len); | |
311 | if (csd->write_bl_partial) | |
312 | puts("Supports partial writes\n"); | |
313 | else | |
314 | puts("Does not support partial writes\n"); | |
315 | if (csd->wp_grp_enable) | |
316 | printf("Supports group WP: %u\n", csd->wp_grp_size + 1); | |
317 | else | |
318 | puts("Does not support group WP\n"); | |
319 | printf("Card capacity: %u bytes\n", | |
320 | (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * | |
321 | (1 << csd->read_bl_len)); | |
322 | printf("File format: %u/%u\n", | |
323 | csd->file_format_grp, csd->file_format); | |
324 | puts("Write protection: "); | |
325 | if (csd->perm_write_protect) | |
326 | puts(" permanent"); | |
327 | if (csd->tmp_write_protect) | |
328 | puts(" temporary"); | |
329 | putc('\n'); | |
330 | } | |
331 | ||
332 | static int mmc_idle_cards(void) | |
333 | { | |
334 | int ret; | |
335 | ||
336 | /* Reset and initialize all cards */ | |
337 | ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); | |
338 | if (ret) | |
339 | return ret; | |
340 | ||
341 | /* Keep the bus idle for 74 clock cycles */ | |
342 | return mmc_cmd(0, 0, NULL, INIT_CMD); | |
343 | } | |
344 | ||
345 | static int sd_init_card(struct mmc_cid *cid, int verbose) | |
346 | { | |
347 | unsigned long resp[4]; | |
348 | int i, ret = 0; | |
349 | ||
350 | mmc_idle_cards(); | |
351 | for (i = 0; i < 1000; i++) { | |
6d0f6bcf | 352 | ret = mmc_acmd(SD_CMD_APP_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND, |
fc26c97b HS |
353 | resp, R3 | NID); |
354 | if (ret || (resp[0] & 0x80000000)) | |
355 | break; | |
356 | ret = -ETIMEDOUT; | |
357 | } | |
358 | ||
359 | if (ret) | |
360 | return ret; | |
361 | ||
362 | ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); | |
363 | if (ret) | |
364 | return ret; | |
365 | sd_parse_cid(cid, resp); | |
366 | if (verbose) | |
367 | mmc_dump_cid(cid); | |
368 | ||
369 | /* Get RCA of the card that responded */ | |
341188b9 | 370 | ret = mmc_cmd(SD_CMD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); |
fc26c97b HS |
371 | if (ret) |
372 | return ret; | |
373 | ||
374 | mmc_rca = resp[0] >> 16; | |
375 | if (verbose) | |
376 | printf("SD Card detected (RCA %u)\n", mmc_rca); | |
a0845830 | 377 | mmc_card_is_sd = 1; |
fc26c97b HS |
378 | return 0; |
379 | } | |
380 | ||
381 | static int mmc_init_card(struct mmc_cid *cid, int verbose) | |
382 | { | |
383 | unsigned long resp[4]; | |
384 | int i, ret = 0; | |
385 | ||
386 | mmc_idle_cards(); | |
387 | for (i = 0; i < 1000; i++) { | |
6d0f6bcf | 388 | ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND, resp, |
fc26c97b HS |
389 | R3 | NID | OPEN_DRAIN); |
390 | if (ret || (resp[0] & 0x80000000)) | |
391 | break; | |
392 | ret = -ETIMEDOUT; | |
393 | } | |
394 | ||
395 | if (ret) | |
396 | return ret; | |
397 | ||
398 | /* Get CID of all cards. FIXME: Support more than one card */ | |
399 | ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); | |
400 | if (ret) | |
401 | return ret; | |
402 | mmc_parse_cid(cid, resp); | |
403 | if (verbose) | |
404 | mmc_dump_cid(cid); | |
405 | ||
406 | /* Set Relative Address of the card that responded */ | |
407 | ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, | |
408 | R1 | NCR | OPEN_DRAIN); | |
409 | return ret; | |
410 | } | |
411 | ||
a0845830 HS |
412 | static void mci_set_data_timeout(struct mmc_csd *csd) |
413 | { | |
414 | static const unsigned int dtomul_to_shift[] = { | |
415 | 0, 4, 7, 8, 10, 12, 16, 20, | |
416 | }; | |
417 | static const unsigned int taac_exp[] = { | |
418 | 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, | |
419 | }; | |
420 | static const unsigned int taac_mant[] = { | |
421 | 0, 10, 12, 13, 15, 60, 25, 30, | |
422 | 35, 40, 45, 50, 55, 60, 70, 80, | |
423 | }; | |
424 | unsigned int timeout_ns, timeout_clks; | |
425 | unsigned int e, m; | |
426 | unsigned int dtocyc, dtomul; | |
427 | unsigned int shift; | |
428 | u32 dtor; | |
429 | ||
430 | e = csd->taac & 0x07; | |
431 | m = (csd->taac >> 3) & 0x0f; | |
432 | ||
433 | timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; | |
434 | timeout_clks = csd->nsac * 100; | |
435 | ||
436 | timeout_clks += (((timeout_ns + 9) / 10) | |
6d0f6bcf | 437 | * ((CONFIG_SYS_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; |
a0845830 HS |
438 | if (!mmc_card_is_sd) |
439 | timeout_clks *= 10; | |
440 | else | |
441 | timeout_clks *= 100; | |
442 | ||
443 | dtocyc = timeout_clks; | |
444 | dtomul = 0; | |
7a96ddad | 445 | shift = 0; |
a0845830 HS |
446 | while (dtocyc > 15 && dtomul < 8) { |
447 | dtomul++; | |
448 | shift = dtomul_to_shift[dtomul]; | |
449 | dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; | |
450 | } | |
451 | ||
452 | if (dtomul >= 8) { | |
453 | dtomul = 7; | |
454 | dtocyc = 15; | |
455 | puts("Warning: Using maximum data timeout\n"); | |
456 | } | |
457 | ||
458 | dtor = (MMCI_BF(DTOMUL, dtomul) | |
459 | | MMCI_BF(DTOCYC, dtocyc)); | |
460 | mmci_writel(DTOR, dtor); | |
461 | ||
462 | printf("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", | |
463 | dtocyc << shift, dtor); | |
464 | } | |
465 | ||
fc26c97b HS |
466 | int mmc_init(int verbose) |
467 | { | |
468 | struct mmc_cid cid; | |
469 | struct mmc_csd csd; | |
f0d1246e | 470 | unsigned int max_blksz; |
fc26c97b HS |
471 | int ret; |
472 | ||
473 | /* Initialize controller */ | |
474 | mmci_writel(CR, MMCI_BIT(SWRST)); | |
475 | mmci_writel(CR, MMCI_BIT(MCIEN)); | |
476 | mmci_writel(DTOR, 0x5f); | |
477 | mmci_writel(IDR, ~0UL); | |
6d0f6bcf | 478 | mci_set_mode(CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); |
fc26c97b | 479 | |
a0845830 HS |
480 | mmc_card_is_sd = 0; |
481 | ||
fc26c97b HS |
482 | ret = sd_init_card(&cid, verbose); |
483 | if (ret) { | |
484 | mmc_rca = MMC_DEFAULT_RCA; | |
485 | ret = mmc_init_card(&cid, verbose); | |
486 | } | |
487 | if (ret) | |
488 | return ret; | |
489 | ||
490 | /* Get CSD from the card */ | |
491 | ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); | |
492 | if (ret) | |
493 | return ret; | |
494 | if (verbose) | |
495 | mmc_dump_csd(&csd); | |
496 | ||
a0845830 HS |
497 | mci_set_data_timeout(&csd); |
498 | ||
fc26c97b HS |
499 | /* Initialize the blockdev structure */ |
500 | mmc_blkdev.if_type = IF_TYPE_MMC; | |
501 | mmc_blkdev.part_type = PART_TYPE_DOS; | |
502 | mmc_blkdev.block_read = mmc_bread; | |
503 | sprintf((char *)mmc_blkdev.vendor, | |
f2302d44 | 504 | "Man %02x%04x Snr %08lx", |
fc26c97b HS |
505 | cid.mid, cid.oid, cid.psn); |
506 | strncpy((char *)mmc_blkdev.product, cid.pnm, | |
507 | sizeof(mmc_blkdev.product)); | |
508 | sprintf((char *)mmc_blkdev.revision, "%x %x", | |
509 | cid.prv >> 4, cid.prv & 0x0f); | |
f0d1246e HS |
510 | |
511 | /* | |
512 | * If we can't use 512 byte blocks, refuse to deal with the | |
513 | * card. Tons of code elsewhere seems to depend on this. | |
514 | */ | |
515 | max_blksz = 1 << csd.read_bl_len; | |
516 | if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { | |
517 | printf("Card does not support 512 byte reads, aborting.\n"); | |
518 | return -ENODEV; | |
519 | } | |
520 | mmc_blkdev.blksz = 512; | |
fc26c97b HS |
521 | mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); |
522 | ||
6d0f6bcf | 523 | mci_set_mode(CONFIG_SYS_MMC_CLK_PP, mmc_blkdev.blksz); |
fc26c97b HS |
524 | |
525 | #if 0 | |
526 | if (fat_register_device(&mmc_blkdev, 1)) | |
527 | printf("Could not register MMC fat device\n"); | |
528 | #else | |
529 | init_part(&mmc_blkdev); | |
530 | #endif | |
531 | ||
532 | return 0; | |
533 | } | |
534 | ||
535 | int mmc_read(ulong src, uchar *dst, int size) | |
536 | { | |
537 | return -ENOSYS; | |
538 | } | |
539 | ||
540 | int mmc_write(uchar *src, ulong dst, int size) | |
541 | { | |
542 | return -ENOSYS; | |
543 | } | |
544 | ||
545 | int mmc2info(ulong addr) | |
546 | { | |
547 | return 0; | |
548 | } |