blob: a430ff458f6e85ab5bf9341b230a2851426fd4b2 [file] [log] [blame]
/*
* (C) Copyright 2003
* Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#if defined(CONFIG_CMD_MMC)
#include <config.h>
#include <mmc.h>
#include <fat.h>
#include <asm/errno.h>
#include <part.h>
#include "mv_mmc.h"
#include "mvOs.h"
static int is_sdhc;
//extern int fat_register_device(block_dev_desc_t *dev_desc, int part_no);
static block_dev_desc_t mmc_dev;
block_dev_desc_t *mmc_get_dev(int dev)
{
return &mmc_dev;
}
/*
* FIXME needs to read cid and csd info to determine block size
* and other parameters
*/
static uchar mmc_buf[MMC_BLOCK_SIZE];
static struct mmc_csd mmc_csd_s;
static int mmc_ready = 0;
/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code
that expects it to be shifted. */
static u_int16_t rca = 0;
#ifdef DEBUG
static u_int32_t mmc_size(const struct mmc_csd *csd)
{
u_int32_t block_len, mult, blocknr;
block_len = csd->read_bl_len << 12;
mult = csd->c_size_mult << 8;
blocknr = (csd->c_size+1) * mult;
return blocknr * block_len;
}
#endif
#if 0
static int isprint (unsigned char ch)
{
if (ch >= 32 && ch < 127)
return (1);
return (0);
}
static int toprint(char *dst, char c)
{
if (isprint(c)) {
*dst = c;
return 1;
}
return sprintf(dst,"\\x%02x", c);
}
#endif
#ifdef DEBUG
static void mmc_dump_cid(const struct mmc_cid *cid)
{
printf("Manufacturer ID: %02X\n", cid->mid);
printf("OEM/Application ID: %04X\n", cid->oid);
printf("Product name: %s\n", cid->pnm);
printf("Product Revision: %u.%u\n",
cid->prv >> 4, cid->prv & 0x0f);
printf("Product Serial Number: %lu\n", cid->psn);
printf("Manufacturing Date: %02u/%02u\n",
cid->mdt >> 4, cid->mdt & 0x0f);
}
static void mmc_dump_csd(const struct mmc_csd *csd)
{
unsigned long *csd_raw = (unsigned long *)csd;
printf("CSD data: %08lx %08lx %08lx %08lx\n",
csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
printf("CSD structure version: 1.%u\n", csd->csd_structure);
printf("MMC System Spec version: %u\n", csd->spec_vers);
printf("Card command classes: %03x\n", csd->ccc);
printf("Read block length: %u\n", 1 << csd->read_bl_len);
if (csd->read_bl_partial)
puts("Supports partial reads\n");
else
puts("Does not support partial reads\n");
printf("Write block length: %u\n", 1 << csd->write_bl_len);
if (csd->write_bl_partial)
puts("Supports partial writes\n");
else
puts("Does not support partial writes\n");
if (csd->wp_grp_enable)
printf("Supports group WP: %u\n", csd->wp_grp_size + 1);
else
puts("Does not support group WP\n");
printf("Card capacity: %u bytes\n",
(csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) *
(1 << csd->read_bl_len));
printf("File format: %u/%u\n",
csd->file_format_grp, csd->file_format);
puts("Write protection: ");
if (csd->perm_write_protect)
puts(" permanent");
if (csd->tmp_write_protect)
puts(" temporary");
putc('\n');
}
#endif /* DEBUG */
#if 0
static void print_mmc_cid(struct mmc_cid *cid)
{
printf("MMC found. Card desciption is:\n");
printf("Manufacturer ID = %02x%02x%02x\n",
cid->id[0], cid->id[1], cid->id[2]);
printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
cid->hwrev = cid->fwrev = 0; /* null terminate string */
printf("Product Name = %s\n",cid->name);
printf("Serial Number = %02x%02x%02x\n",
cid->sn[0], cid->sn[1], cid->sn[2]);
printf("Month = %d\n",cid->month);
printf("Year = %d\n",1997 + cid->year);
}
static void print_sd_cid(struct mmc_csd *cid)
{
int len;
char tbuf[64];
printf("SD%s found. Card desciption is:\n", is_sdhc?"HC":"");
len = 0;
len += toprint(&tbuf[len], cid->oid_0);
len += toprint(&tbuf[len], cid->oid_1);
tbuf[len] = 0;
printf("Manufacturer: 0x%02x, OEM \"%s\"\n",
cid->mid, tbuf);
len = 0;
len += toprint(&tbuf[len], cid->pnm_0);
len += toprint(&tbuf[len], cid->pnm_1);
len += toprint(&tbuf[len], cid->pnm_2);
len += toprint(&tbuf[len], cid->pnm_3);
len += toprint(&tbuf[len], cid->pnm_4);
tbuf[len] = 0;
printf("Product name: \"%s\", revision %d.%d\n",
tbuf,
cid->prv >> 4, cid->prv & 15);
printf("Serial number: %u\n",
cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 |
cid->psn_3);
printf("Manufacturing date: %d/%d\n",
cid->mdt_1 & 15,
2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4));
printf("CRC: 0x%02x, b0 = %d\n",
cid->crc >> 1, cid->crc & 1);
}
#endif
static void mvsdmmc_set_clock(unsigned int clock)
{
unsigned int m;
m = MVSDMMC_BASE_FAST_CLOCK/(2*clock) - 1;
debug("mvsdmmc_set_clock: dividor = 0x%x clock=%d\n",
m, clock);
SDIO_REG_WRITE32(SDIO_CLK_DIV, m & 0x7ff);
//if (isprint(1))
udelay(10*1000);
}
static ulong * mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype)
{
static ulong resp[4];
ushort done ;
int err = 0 ;
ulong curr, start, diff, hz;
ushort response[8], resp_indx = 0;
debug("mmc_cmd %x, arg: %x,xfer: %x,resp: %x, wait : %x\n", cmd, arg, xfermode, resptype, waittype);
//clear status
SDIO_REG_WRITE16(SDIO_NOR_INTR_STATUS, 0xffff);
SDIO_REG_WRITE16(SDIO_ERR_INTR_STATUS, 0xffff);
start = get_ticks();
hz = get_tbclk();
while((SDIO_REG_READ16(SDIO_PRESENT_STATE0) & CARD_BUSY)) {
curr = get_ticks();
diff = (long) curr - (long) start;
if (diff > (3*hz))
{
// 3 seconds timeout, card busy, can't sent cmd
printf("card too busy \n");
return 0;
}
}
SDIO_REG_WRITE16(SDIO_ARG_LOW, (ushort)(arg&0xffff) );
SDIO_REG_WRITE16(SDIO_ARG_HI, (ushort)(arg>>16) );
SDIO_REG_WRITE16(SDIO_XFER_MODE, xfermode);
if( (cmd == MMC_CMD_READ_BLOCK) || (cmd == 25) )
{
SDIO_REG_WRITE16(SDIO_CMD, ((cmd << 8) | resptype | 0x3c ) );
debug("cmd reg : %x\n", SDIO_REG_READ16( SDIO_CMD )) ;
}
else
{
SDIO_REG_WRITE16(SDIO_CMD, ((cmd << 8) | resptype ) );
}
done = SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & waittype;
start = get_ticks();
while( done!=waittype)
{
done = SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & waittype;
if( SDIO_REG_READ16(SDIO_NOR_INTR_STATUS) & 0x8000 )
{
printf("Error! cmd : %ld, err : %04x\n", cmd, SDIO_REG_READ16(SDIO_ERR_INTR_STATUS) ) ;
return 0 ; // error happen
}
curr = get_ticks();
diff = (long) curr - (long) start;
if (diff > (3*hz))
{
printf("cmd timeout, status : %04x\n", SDIO_REG_READ16(SDIO_NOR_INTR_STATUS));
printf("xfer mode : %04x\n", SDIO_REG_READ16(SDIO_XFER_MODE));
err = 1 ;
break;
}
}
for (resp_indx = 0 ; resp_indx < 8; resp_indx++)
response[resp_indx] = SDIO_REG_READ16(SDIO_RSP(resp_indx));
memset(resp, 0, sizeof(resp));
switch (resptype & 0x3) {
case SDIO_CMD_RSP_48:
case SDIO_CMD_RSP_48BUSY:
resp[0] = ((response[2] & 0x3f) << (8 - 8)) |
((response[1] & 0xffff) << (14 - 8)) |
((response[0] & 0x3ff) << (30 - 8));
resp[1] = ((response[0] & 0xfc00) >> 10);
break;
case SDIO_CMD_RSP_136:
resp[3] = ((response[7] & 0x3fff) << 8) |
((response[6] & 0x3ff) << 22);
resp[2] = ((response[6] & 0xfc00) >> 10) |
((response[5] & 0xffff) << 6) |
((response[4] & 0x3ff) << 22);
resp[1] = ((response[4] & 0xfc00) >> 10) |
((response[3] & 0xffff) << 6) |
((response[2] & 0x3ff) << 22);
resp[0] = ((response[2] & 0xfc00) >> 10) |
((response[1] & 0xffff) << 6) |
((response[0] & 0x3ff) << 22);
break;
default:
return 0;
}
#ifdef MMC_DEBUG
int i;
printf("MMC resp :");
for (i=0; i<4; ++i ) {
printf(" %08x", resp[i]);
}
printf("\n");
#endif
if( err )
return NULL ;
else
return resp;
}
int mmc_block_read(uchar *dst, ulong src, ulong len)
{
ulong *resp;
//ushort argh, argl;
//ulong status;
if (len == 0) {
return 0;
}
if (is_sdhc) {
/* SDHC: use block address */
src >>= 9;
}
debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);
#if 0
/* set block len */
resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
if (!resp) {
printf("mmc_block_read: set blk len fails\n");
return -EIO;
}
#endif
// prepare for dma transfer
SDIO_REG_WRITE16(SDIO_SYS_ADDR_LOW,((ulong)(dst))&0xffff);
SDIO_REG_WRITE16(SDIO_SYS_ADDR_HI,(((ulong)dst)>>16)&0xffff);
SDIO_REG_WRITE16(SDIO_BLK_SIZE,len);
SDIO_REG_WRITE16(SDIO_BLK_COUNT,1);
/* send read command */
resp = mmc_cmd(MMC_CMD_READ_BLOCK, src, 0x10 , // 0x12,
SDIO_CMD_RSP_48, SDIO_NOR_XFER_DONE);
if (!resp) {
printf("mmc_block_read: mmc read block cmd fails\n");
return -EIO;
}
return 0;
}
int mmc_block_write(ulong dst, uchar *src, int len)
{
//uchar *resp;
//ushort argh, argl;
//ulong status;
return -1 ;
#if 0
if (len == 0) {
return 0;
}
debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong)src, len);
argh = len >> 16;
argl = len & 0xffff;
/* set block len */
resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
/* send write command */
argh = dst >> 16;
argl = dst & 0xffff;
MMC_STRPCL = MMC_STRPCL_STOP_CLK;
MMC_NOB = 1;
MMC_BLKLEN = len;
resp = mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl,
MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN);
MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;
while (len) {
if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) {
int i, bytes = min(32,len);
for (i=0; i<bytes; i++) {
MMC_TXFIFO = *src++;
}
if (bytes < 32) {
MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
}
len -= bytes;
}
status = MMC_STAT;
if (status & MMC_STAT_ERRORS) {
printf("MMC_STAT error %lx\n", status);
return -1;
}
}
MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE));
MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;
while (!(MMC_I_REG & MMC_I_REG_PRG_DONE));
status = MMC_STAT;
if (status & MMC_STAT_ERRORS) {
printf("MMC_STAT error %lx\n", status);
return -1;
}
return 0;
#endif
}
int mv_mmc_read(ulong src, uchar *dst, int size)
{
ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
ulong mmc_block_size, mmc_block_address;
if (size == 0) {
return 0;
}
if (!mmc_ready) {
printf("Please initial the MMC first\n");
return -1;
}
mmc_block_size = MMC_BLOCK_SIZE;
mmc_block_address = ~(mmc_block_size - 1);
src -= CONFIG_SYS_MMC_BASE;
end = src + size;
part_start = ~mmc_block_address & src;
part_end = ~mmc_block_address & end;
aligned_start = mmc_block_address & src;
aligned_end = mmc_block_address & end;
/* all block aligned accesses */
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if (part_start) {
part_len = mmc_block_size - part_start;
debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) {
return -1;
}
memcpy(dst, mmc_buf+part_start, part_len);
dst += part_len;
src += part_len;
}
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
for (; src < aligned_end; aligned_start +=mmc_block_size, src += mmc_block_size, dst += mmc_block_size) {
debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) {
printf("mmc block read error\n");
return -1;
}
//printf("mem copy from %x to %x, size %d\n", (ulong)mmc_buf, (ulong)dst, mmc_block_size );
memcpy(dst, mmc_buf, mmc_block_size);
}
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if (part_end && src < end) {
debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
return -1;
}
memcpy(dst, mmc_buf, part_end);
}
return 0;
}
int mmc_write(uchar *src, ulong dst, int size)
{
ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
ulong mmc_block_size, mmc_block_address;
if (size == 0) {
return 0;
}
if (!mmc_ready) {
printf("Please initial the MMC first\n");
return -1;
}
mmc_block_size = MMC_BLOCK_SIZE;
mmc_block_address = ~(mmc_block_size - 1);
dst -= CONFIG_SYS_MMC_BASE;
end = dst + size;
part_start = ~mmc_block_address & dst;
part_end = ~mmc_block_address & end;
aligned_start = mmc_block_address & dst;
aligned_end = mmc_block_address & end;
/* all block aligned accesses */
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if (part_start) {
part_len = mmc_block_size - part_start;
debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
(ulong)src, dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) {
return -1;
}
memcpy(mmc_buf+part_start, src, part_len);
if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0) {
return -1;
}
dst += part_len;
src += part_len;
}
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_write(dst, (uchar *)src, mmc_block_size)) < 0) {
return -1;
}
}
debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if (part_end && dst < end) {
debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
return -1;
}
memcpy(mmc_buf, src, part_end);
if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) {
return -1;
}
}
return 0;
}
unsigned long mmc_bread(int dev_num, unsigned long blknr, lbaint_t blkcnt, void *dst)
{
int mmc_block_size = MMC_BLOCK_SIZE;
ulong src = blknr * mmc_block_size + CONFIG_SYS_MMC_BASE;
mv_mmc_read(src, (uchar *)dst, blkcnt*mmc_block_size);
return blkcnt;
}
//int mmc_init(int verbose)
int mmc_legacy_init(int verbose)
{
int retries, rc = -ENODEV;
ulong *resp;
int sd_ver20;
int is_sd;
ushort reg;
uchar cidbuf[64];
sd_ver20 = 0;
is_sdhc = 0;
is_sd = 0;
// Initial Host Ctrl : Timeout : max , Normal Speed mode, 4-bit data mode
// Big Endian, SD memory Card, Push_pull CMD Line
SDIO_REG_WRITE16(SDIO_HOST_CTRL,
SDIO_HOST_CTRL_TMOUT(0xf) |
SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
SDIO_HOST_CTRL_BIG_ENDIAN |
SDIO_HOST_CTRL_PUSH_PULL_EN |
SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY );
SDIO_REG_WRITE16(SDIO_CLK_CTRL, 0);
//enable status
SDIO_REG_WRITE16(SDIO_NOR_STATUS_EN, 0xffff);
SDIO_REG_WRITE16(SDIO_ERR_STATUS_EN, 0xffff);
//disable interrupts
SDIO_REG_WRITE16(SDIO_NOR_INTR_EN, 0);
SDIO_REG_WRITE16(SDIO_ERR_INTR_EN, 0);
SDIO_REG_WRITE16(SDIO_SW_RESET,0x100);
udelay(10000);
mmc_csd_s.c_size = 0;
/* reset */
retries = 10;
//mmc_cmd(ulong cmd, ulong arg, ushort xfermode, ushort resptype, ushort waittype);
resp = mmc_cmd(0, 0, 0, SDIO_CMD_RSP_NONE , SDIO_NOR_CMD_DONE );
debug("cmd 0 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
debug ("trying to detect SD card version\n");
resp = mmc_cmd(8, 0x000001aa, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
debug("cmd 8 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (resp && (resp[0] & 0x1ff)==0x1aa) {
debug("sd version 2.0 card detected\n");
sd_ver20 = 1;
}
if (sd_ver20)
retries = 50;
else
retries = 10;
while (retries--) {
resp = mmc_cmd(55, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
debug("cmd 55 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (sd_ver20)
resp = mmc_cmd(41, 0x40300000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
else
resp = mmc_cmd(41, 0x00300000, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
debug("cmd 41 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (resp && (resp[0] & 0x80000000)) {
debug ("detected SD card\n");
is_sd = 1;
break;
}
udelay(100*1000);
}
if (retries <= 0 && !is_sd) {
debug ("failed to detect SD card, trying MMC\n");
retries = 10;
while (retries--) {
resp = mmc_cmd(1, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
debug("cmd 01 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (resp && (resp[0] & 0x80000000)) {
debug ("detected MMC card\n");
reg = SDIO_REG_READ16(SDIO_HOST_CTRL);
reg &= ~(0x3<<1);
reg |= SDIO_HOST_CTRL_CARD_TYPE_IO_MMC;
SDIO_REG_WRITE16(SDIO_HOST_CTRL, reg);
break;
}
udelay(100*1000);
}
}
if (retries <= 0) {
debug ("detect fails\n");
return -ENODEV;
}
/* try to get card id */
resp = mmc_cmd(2, 0, 0, SDIO_CMD_RSP_136, SDIO_NOR_CMD_DONE );
debug("cmd 2 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (resp == NULL) {
debug ("read cid fails\n");
return -ENODEV;
}
if (is_sd) {
/* struct mmc_csd *cid = (struct mmc_csd *) resp;*/
memcpy(cidbuf, resp, sizeof(struct mmc_csd));
/* sprintf((char *) mmc_dev.vendor,
"Man %02x OEM %c%c \"%c%c%c%c%c\"",
cid->mid, cid->oid_0, cid->oid_1,
cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4);
sprintf((char *) mmc_dev.product, "%d",
(cid->psn_0 << 24) | (cid->psn_1 <<16) | (cid->psn_2 << 8) | (cid->psn_3 << 8));
sprintf((char *) mmc_dev.revision, "%d.%d", cid->prv>>4, cid->prv & 0xff);
*/
} else {
/* TODO configure mmc driver depending on card attributes */
/* struct mmc_cid *cid = (struct mmc_cid *) resp;*/
memcpy(cidbuf, resp, sizeof(struct mmc_csd));
/*
sprintf((char *) mmc_dev.vendor,
"Man %02x%02x%02x Snr %02x%02x%02x",
cid->id[0], cid->id[1], cid->id[2],
cid->sn[0], cid->sn[1], cid->sn[2]);
sprintf((char *) mmc_dev.product, "%s", cid->name);
sprintf((char *) mmc_dev.revision, "%x %x", cid->hwrev, cid->fwrev);
*/
}
/* fill in device description */
mmc_dev.if_type = IF_TYPE_MMC;
mmc_dev.part_type = PART_TYPE_DOS;
mmc_dev.dev = 0;
mmc_dev.lun = 0;
mmc_dev.type = 0;
/* FIXME fill in the correct size (is set to 128MByte) */
mmc_dev.blksz = 512;
mmc_dev.lba = 0x10000;
mmc_dev.removable = 0;
mmc_dev.block_read = mmc_bread;
/* MMC exists, get CSD too */
resp = mmc_cmd(MMC_CMD_SET_RCA, 0, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
if (resp == NULL) {
debug ("set rca fails\n");
return -ENODEV;
}
debug("cmd3 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]);
if (is_sd)
rca = resp[0] >> 16;
else
rca = 0;
resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, 0, SDIO_CMD_RSP_136,SDIO_NOR_CMD_DONE );
debug("cmd 9 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (resp == NULL) {
debug ("read csd fails\n");
return -ENODEV;
}
memcpy(&mmc_csd_s, (struct mmc_csd *) resp, sizeof(struct mmc_csd));
rc = 0;
mmc_ready = 1;
/* FIXME add verbose printout for csd */
debug ("size = %u\n", mmc_size(&mmc_csd_s));
resp = mmc_cmd(7, rca<<16, 0, SDIO_CMD_RSP_48BUSY, SDIO_NOR_CMD_DONE);
if (resp == NULL) {
debug ("select card fails\n");
return -ENODEV;
}
debug("cmd 7 resp : %08x %08x %08x %08x\n", resp[0], resp[1], resp[2], resp[3] );
if (is_sd) {
resp = mmc_cmd(55, rca<<16, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
if (resp == NULL) {
debug ("cmd55 fails\n");
return -ENODEV;
}
debug("cmd55 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]);
resp = mmc_cmd(6, (rca<<16) | 0x2 , 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
if (resp == NULL) {
debug ("cmd55 fails\n");
return -ENODEV;
}
debug("cmd6 resp : 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]);
}
resp = (ulong *) &mmc_csd_s;
debug("csd: 0x%08x 0x%08x 0x%08x 0x%08x\n", resp[0], resp[1], resp[2], resp[3]);
/* check SDHC */
if ((resp[0]&0xf0000000)==0x40000000)
is_sdhc = 1;
/* set block len */
resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, 512, 0, SDIO_CMD_RSP_48, SDIO_NOR_CMD_DONE );
if (!resp) {
printf("mmc_block_read: set blk len fails\n");
return -EIO;
}
/* if (verbose) {
if (is_sd)
print_sd_cid((struct mmc_csd *) cidbuf);
else
print_mmc_cid((struct mmc_cid *) cidbuf);
}*/
mvsdmmc_set_clock(25000000);
fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
return rc;
}
#if 0
int
mmc_ident(block_dev_desc_t *dev)
{
return 0;
}
int
mmc2info(ulong addr)
{
/* FIXME hard codes to 256 MB device */
if (addr >= CONFIG_SYS_MMC_BASE && addr < CONFIG_SYS_MMC_BASE + 0xffffffff) {
return 1;
}
return 0;
}
#endif
#endif /* CONFIG_MMC */