3 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27 #include <asm/errno.h>
28 #include <asm/arch/hardware.h>
33 fat_register_read(int(*block_read)(int device, ulong blknr, ulong blkcnt, uchar *buffer));
36 * FIXME needs to read cid and csd info to determine block size
37 * and other parameters
39 static uchar mmc_buf[MMC_BLOCK_SIZE];
40 static mmc_csd_t mmc_csd;
41 static int mmc_ready = 0;
45 /****************************************************/
46 mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat)
47 /****************************************************/
49 static uchar resp[20];
53 debug("mmc_cmd %x %x %x %x\n", cmd, argh, argl, cmdat);
54 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
55 MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF;
56 while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF));
61 MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES;
62 MMC_STRPCL = MMC_STRPCL_START_CLK;
63 while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES));
66 debug("MMC status %x\n", status);
67 if (status & MMC_STAT_TIME_OUT_RESPONSE)
86 for (i = words-1; i >= 0; i--)
88 ulong res_fifo = MMC_RES;
91 resp[offset] = ((uchar *)&res_fifo)[0];
92 resp[offset+1] = ((uchar *)&res_fifo)[1];
95 for (i=0; i<words*2; i += 2)
97 printf("MMC resp[%d] = %02x\n", i, resp[i]);
98 printf("MMC resp[%d] = %02x\n", i+1, resp[i+1]);
105 /****************************************************/
106 mmc_block_read(uchar *dst, ulong src, ulong len)
107 /****************************************************/
118 debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);
124 resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
126 /* send read command */
129 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
133 resp = mmc_cmd(MMC_CMD_READ_BLOCK, argh, argl,
134 MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN);
137 MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ;
140 if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ)
146 if (status & MMC_STAT_ERRORS)
148 printf("MMC_STAT error %lx\n", status);
152 MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
153 while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE));
155 if (status & MMC_STAT_ERRORS)
157 printf("MMC_STAT error %lx\n", status);
164 /****************************************************/
165 mmc_block_write(ulong dst, uchar *src, int len)
166 /****************************************************/
177 debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong)src, len);
183 resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
185 /* send write command */
188 MMC_STRPCL = MMC_STRPCL_STOP_CLK;
191 resp = mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl,
192 MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN);
194 MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;
197 if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ)
199 int i, bytes = min(32,len);
201 for (i=0; i<bytes; i++)
207 MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
212 if (status & MMC_STAT_ERRORS)
214 printf("MMC_STAT error %lx\n", status);
218 MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
219 while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE));
220 MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;
221 while (!(MMC_I_REG & MMC_I_REG_PRG_DONE));
223 if (status & MMC_STAT_ERRORS)
225 printf("MMC_STAT error %lx\n", status);
233 /****************************************************/
234 mmc_read(ulong src, uchar *dst, int size)
235 /****************************************************/
237 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
238 ulong mmc_block_size, mmc_block_address;
247 printf("Please initial the MMC first\n");
251 mmc_block_size = MMC_BLOCK_SIZE;
252 mmc_block_address = ~(mmc_block_size - 1);
256 part_start = ~mmc_block_address & src;
257 part_end = ~mmc_block_address & end;
258 aligned_start = mmc_block_address & src;
259 aligned_end = mmc_block_address & end;
261 /* all block aligned accesses */
262 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
263 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
266 part_len = mmc_block_size - part_start;
267 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
268 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
269 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
273 memcpy(dst, mmc_buf+part_start, part_len);
277 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
278 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
279 for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size)
281 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
282 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
283 if ((mmc_block_read((uchar *)(dst), src, mmc_block_size)) < 0)
288 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
289 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
290 if (part_end && src < end)
292 debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
293 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
294 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0)
298 memcpy(dst, mmc_buf, part_end);
304 /****************************************************/
305 mmc_write(uchar *src, ulong dst, int size)
306 /****************************************************/
308 ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
309 ulong mmc_block_size, mmc_block_address;
318 printf("Please initial the MMC first\n");
322 mmc_block_size = MMC_BLOCK_SIZE;
323 mmc_block_address = ~(mmc_block_size - 1);
327 part_start = ~mmc_block_address & dst;
328 part_end = ~mmc_block_address & end;
329 aligned_start = mmc_block_address & dst;
330 aligned_end = mmc_block_address & end;
332 /* all block aligned accesses */
333 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
334 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
337 part_len = mmc_block_size - part_start;
338 debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
339 (ulong)src, dst, end, part_start, part_end, aligned_start, aligned_end);
340 if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0)
344 memcpy(mmc_buf+part_start, src, part_len);
345 if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0)
352 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
353 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
354 for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size)
356 debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
357 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
358 if ((mmc_block_write(dst, (uchar *)src, mmc_block_size)) < 0)
363 debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
364 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
365 if (part_end && dst < end)
367 debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
368 src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
369 if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0)
373 memcpy(mmc_buf, src, part_end);
374 if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0)
383 /****************************************************/
384 mmc_bread(int dev_num, ulong blknr, ulong blkcnt, uchar *dst)
385 /****************************************************/
387 int mmc_block_size = MMC_BLOCK_SIZE;
388 ulong src = blknr * mmc_block_size + CFG_MMC_BASE;
390 mmc_read(src, (uchar *)dst, blkcnt*mmc_block_size);
395 /****************************************************/
396 mmc_init(int verbose)
397 /****************************************************/
399 int retries, rc = -ENODEV;
402 #ifdef CONFIG_LUBBOCK
403 set_GPIO_mode( GPIO6_MMCCLK_MD );
404 set_GPIO_mode( GPIO8_MMCCS0_MD );
406 CKEN |= CKEN12_MMC; /* enable MMC unit clock */
410 MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
411 MMC_RESTO = MMC_RES_TO_MAX;
412 MMC_SPI = MMC_SPI_DISABLE;
416 resp = mmc_cmd(0, 0, 0, 0);
417 resp = mmc_cmd(1, 0x00ff, 0xc000, MMC_CMDAT_INIT|MMC_CMDAT_BUSY|MMC_CMDAT_R3);
418 while (retries-- && resp && !(resp[4] & 0x80))
420 debug("resp %x %x\n", resp[0], resp[1]);
422 resp = mmc_cmd(1, 0x00ff, 0xff00, MMC_CMDAT_BUSY|MMC_CMDAT_R3);
425 /* try to get card id */
426 resp = mmc_cmd(2, 0, 0, MMC_CMDAT_R2);
429 /* TODO configure mmc driver depending on card attributes */
430 mmc_cid_t *cid = (mmc_cid_t *)resp;
433 printf("MMC found. Card desciption is:\n");
434 printf("Manufacturer ID = %02x%02x%02x\n",
435 cid->id[0], cid->id[1], cid->id[2]);
436 printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
437 cid->hwrev = cid->fwrev = 0; /* null terminate string */
438 printf("Product Name = %s\n",cid->name);
439 printf("Serial Number = %02x%02x%02x\n",
440 cid->sn[0], cid->sn[1], cid->sn[2]);
441 printf("Month = %d\n",cid->month);
442 printf("Year = %d\n",1997 + cid->year);
445 /* MMC exists, get CSD too */
446 resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1);
447 resp = mmc_cmd(MMC_CMD_SEND_CSD, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R2);
450 mmc_csd_t *csd = (mmc_csd_t *)resp;
451 memcpy(&mmc_csd, csd, sizeof(csd));
454 /* FIXME add verbose printout for csd */
458 MMC_CLKRT = 0; /* 20 MHz */
459 resp = mmc_cmd(7, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1);
461 fat_register_read(mmc_bread);
467 mmc_ident(block_dev_desc_t *dev)
475 /* FIXME hard codes to 32 MB device */
476 if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000)