u-boot-2009.08在mini2440上的移植 增加SD卡功能

转载:http://www.linuxidc.com/Linux/2011-05/35982p9.htm


移植环境

1,主机环境:VMare下CentOS 5.5 ,1G内存。

2,集成开发环境:Elipse IDE

3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。

4,开发板:mini2440,2M nor flash,128M nand flash。

5,u-boot版本:u-boot-2009.08

6,参考文章:

9.1,实现u-boot的SD卡功能

SD卡的支持参考了buserror的Git代码仓库中的源码,他也是为mini2440 移植的。它使用的代码也是Openmoko的GTA2 源码。因为GTA2 可以在U-boot中使用SD卡更新系统。将其SD卡底层驱动代码搬过来,经过简单的修改就可以使用了。

这个功能需要修改 5 个文件,添加3 个驱动代码文件。

【1】打开/common/cmd_mem.c,定位到35行,加入下面代码:

 *
 * Copied from FADS ROM, Dan Malek ([email protected])
 */

#include <common.h>
#include <command.h>
#ifdef CONFIG_HAS_DATAFLASH
#include <dataflash.h>
#endif
#if defined(CONFIG_CMD_MMC)
#include <mmc.h>
#endif
#include <watchdog.h>

定位到357行,修改如下:

#if defined(CONFIG_CMD_MMC)
extern int mmc2info(ulong addr);
extern int mmc_write(uchar *src, ulong dst, int size);
#endif
int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

定位到411行附近,加入下面代码:

  puts ("Copy to Flash... ");

  rc = flash_write ((char *)addr, dest, count*size);
  if (rc != 0) {
   flash_perror (rc);
   return (1);
  }
  puts ("done\n");
  return 0;
 }
#endif
#if defined(CONFIG_CMD_MMC)
 if (mmc2info(dest)) {
  int rc;

  puts ("Copy to MMC... ");
  switch (rc = mmc_write ((uchar *)addr, dest, count*size)) {
  case 0:
   putc ('\n');
   return 1;
  case -1:
   puts ("failed\n");
   return 1;
  default:
   printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
   return 1;
  }
  puts ("done\n");
  return 0;
 }

 if (mmc2info(addr)) {
  int rc;

  puts ("Copy from MMC... ");
  switch (rc = mmc_read (addr, (uchar *)dest, count*size)) {
  case 0:
   putc ('\n');
   return 1;
  case -1:
   puts ("failed\n");
   return 1;
  default:
   printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
   return 1;
  }
  puts ("done\n");
  return 0;
 }
#endif
#ifdef CONFIG_HAS_DATAFLASH
 /* Check if we are copying from RAM or Flash to DataFlash */
 if (addr_dataflash(dest) && !addr_dataflash(addr)){
  int rc;

  puts ("Copy to DataFlash... ");

【2】打开//common/cmd_mmc.c,定位到53行,修改如下:

   cmd_usage(cmdtp);
   return 1;
  }

  if (mmc_init(dev) != 0) {//if (mmc_legacy_init(dev) != 0) {
   puts("No MMC card found\n");
   return 1;
  }

【3】打开/cpu/arm920t/s3c24x0/Makefile,定位到33行,如入下面代码:

COBJS-$(CONFIG_USE_IRQ) += interrupts.o
COBJS-y += speed.o
COBJS-y += timer.o
COBJS-y += usb.o
COBJS-y += usb_ohci.o
COBJS-y += mmc.o

SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)

【4】打开/include/mmc.h,定位到172行,修改如下:

#define MMC_RSP_R6      (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7      (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)

#if 0
struct mmc_cid {
 unsigned long psn;
 unsigned short oid;
 unsigned char mid;
 unsigned char prv;
 unsigned char mdt;
 char pnm[7];
};

struct mmc_csd
{
  u8 csd_structure:2,
  spec_vers:4,
  ... ... 

   u8 one:1;
};
#endif
struct mmc_cmd {
 ushort cmdidx;
 uint resp_type;
 uint cmdarg;
 uint response[4];
 uint flags;
};

定位到271行,修改如下:

int mmc_register(struct mmc *mmc);
int mmc_initialize(bd_t *bis);
//int mmc_init(struct mmc *mmc);
//int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
int mmc_init(int verbose);
int mmc_read(ulong src, uchar *dst, int size);
struct mmc *find_mmc_device(int dev_num);
void print_mmc_devices(char separator);

【5】打开/include/part.h,定位到65行,加入下面代码:

#define IF_TYPE_USB  4
#define IF_TYPE_DOC  5
#define IF_TYPE_MMC  6
#define IF_TYPE_SD  7
#define IF_TYPE_SATA  8
#define IF_TYPE_SDHC  9

/* Part types */
#define PART_TYPE_UNKNOWN 0x00

【6】添加的驱动代码文件/cpu/arm920t/s3c24x0/mmc.c:

/*
 * u-boot S3C2410 MMC/SD card driver
 * (C) Copyright 2006 by OpenMoko, Inc.
 * Author: Harald Welte <[email protected]>
 *
 * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c
 * (C) 2005-2005 Thomas Kleffel
 *
 * 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 <config.h>
#include <common.h>
#include <mmc.h>
#include <asm/arch/mmc.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <s3c2410.h>
#include <part.h>
#include <fat.h>

#if defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C)

#ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args)
#else
#define pr_debug(...) do { } while(0)
#endif

#define CONFIG_MMC_WIDE

static S3C2410_SDI *sdi;

static block_dev_desc_t mmc_dev;

block_dev_desc_t * mmc_get_dev(int dev)
{
 return ((block_dev_desc_t *)&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 mmc_csd_t mmc_csd;
static int mmc_ready = 0;
static int wide = 0;


#define CMD_F_RESP 0x01
#define CMD_F_RESP_LONG 0x02

#define CMD_F_RESP_R7 CMD_F_RESP

static u_int32_t *mmc_cmd(ushort cmd, ulong arg, ushort flags)
{
 static u_int32_t resp[5];

 u_int32_t ccon, csta;
 u_int32_t csta_rdy_bit = S3C2410_SDICMDSTAT_CMDSENT;

 memset(resp, 0, sizeof(resp));

 debug("mmc_cmd CMD%d arg=0x%08x flags=%x\n", cmd, arg, flags);

 sdi->SDICSTA = 0xffffffff;
 sdi->SDIDSTA = 0xffffffff;
 sdi->SDIFSTA = 0xffffffff;

 sdi->SDICARG = arg;

 ccon = cmd & S3C2410_SDICMDCON_INDEX;
 ccon |= S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART;

 if (flags & CMD_F_RESP) {
  ccon |= S3C2410_SDICMDCON_WAITRSP;
  csta_rdy_bit = S3C2410_SDICMDSTAT_RSPFIN; /* 1 << 9 */
 }

 if (flags & CMD_F_RESP_LONG)
  ccon |= S3C2410_SDICMDCON_LONGRSP;

 sdi->SDICCON = ccon;

 while (1) {
  csta = sdi->SDICSTA;
  if (csta & csta_rdy_bit)
   break;
  if (csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
   printf("===============> MMC CMD Timeout\n");
   sdi->SDICSTA |= S3C2410_SDICMDSTAT_CMDTIMEOUT;
   break;
  }
 }

 debug("final MMC CMD status 0x%x\n", csta);

 sdi->SDICSTA |= csta_rdy_bit;

 if (flags & CMD_F_RESP) {
  resp[0] = sdi->SDIRSP0;
  resp[1] = sdi->SDIRSP1;
  resp[2] = sdi->SDIRSP2;
  resp[3] = sdi->SDIRSP3;
 }

 return resp;
}

#define FIFO_FILL(host) ((host->SDIFSTA & S3C2410_SDIFSTA_COUNTMASK) >> 2)

static int mmc_block_read(uchar *dst, ulong src, ulong len)
{
 u_int32_t dcon, fifo;
 u_int32_t *dst_u32 = (u_int32_t *)dst;
 u_int32_t *resp;

 if (len == 0)
  return 0;

 debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);

 /* set block len */
 resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, len, CMD_F_RESP);
 sdi->SDIBSIZE = len;

 //sdi->SDIPRE = 0xff;

 /* setup data */
 dcon = (len >> 9) & S3C2410_SDIDCON_BLKNUM;
 dcon |= S3C2410_SDIDCON_BLOCKMODE;
 dcon |= S3C2410_SDIDCON_RXAFTERCMD|S3C2410_SDIDCON_XFER_RXSTART;
 if (wide)
  dcon |= S3C2410_SDIDCON_WIDEBUS;
#if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
 dcon |= S3C2440_SDIDCON_DS_WORD | S3C2440_SDIDCON_DATSTART;
#endif
 sdi->SDIDCON = dcon;

 /* send read command */
 resp = mmc_cmd(MMC_CMD_READ_BLOCK, (mmc_dev.if_type == IF_TYPE_SDHC) ? (src >> 9) : src, CMD_F_RESP);

 while (len > 0) {
  u_int32_t sdidsta = sdi->SDIDSTA;
  fifo = FIFO_FILL(sdi);
  if (sdidsta & (S3C2410_SDIDSTA_FIFOFAIL|
    S3C2410_SDIDSTA_CRCFAIL|
    S3C2410_SDIDSTA_RXCRCFAIL|
    S3C2410_SDIDSTA_DATATIMEOUT)) {
   printf("mmc_block_read: err SDIDSTA=0x%08x\n", sdidsta);
   return -EIO;
  }

  while (fifo--) {
   //debug("dst_u32 = 0x%08x\n", dst_u32);
   *(dst_u32++) = sdi->SDIDAT;
   if (len >= 4)
    len -= 4;
   else {
    len = 0;
    break;
   }
  }
 }

 debug("waiting for SDIDSTA  (currently 0x%08x\n", sdi->SDIDSTA);
 while (!(sdi->SDIDSTA & (1 << 4))) {}
 debug("done waiting for SDIDSTA (currently 0x%08x\n", sdi->SDIDSTA);

 sdi->SDIDCON = 0;

 if (!(sdi->SDIDSTA & S3C2410_SDIDSTA_XFERFINISH))
  debug("mmc_block_read; transfer not finished!\n");

 return 0;
}

static int mmc_block_write(ulong dst, uchar *src, int len)
{
 printf("MMC block write not yet supported on S3C2410!\n");
 return -1;
}


int 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 initialize the MMC first\n");
  return -1;
 }

 mmc_block_size = MMC_BLOCK_SIZE;
 mmc_block_address = ~(mmc_block_size - 1);

 src -= CFG_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; 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((uchar *)(dst), 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 && 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 initialize the MMC first\n");
  return -1;
 }

 mmc_block_size = MMC_BLOCK_SIZE;
 mmc_block_address = ~(mmc_block_size - 1);

 dst -= CFG_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;
}

ulong mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
{
 int mmc_block_size = MMC_BLOCK_SIZE;
 ulong src = blknr * mmc_block_size + CFG_MMC_BASE;

 mmc_read(src, dst, blkcnt*mmc_block_size);
 return blkcnt;
}

/* 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 = MMC_DEFAULT_RCA >> 16;

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_mult1 << 8;
 blocknr = (csd->c_size+1) * mult;

 return blocknr * block_len;
}

struct sd_cid {
 char  pnm_0; /* product name */
 char  oid_1; /* OEM/application ID */
 char  oid_0;
 uint8_t  mid; /* manufacturer ID */
 char  pnm_4;
 char  pnm_3;
 char  pnm_2;
 char  pnm_1;
 uint8_t  psn_2; /* product serial number */
 uint8_t  psn_1;
 uint8_t  psn_0; /* MSB */
 uint8_t  prv; /* product revision */
 uint8_t  crc; /* CRC7 checksum, b0 is unused and set to 1 */
 uint8_t  mdt_1; /* manufacturing date, LSB, RRRRyyyy yyyymmmm */
 uint8_t  mdt_0; /* MSB */
 uint8_t  psn_3; /* LSB */
};

static void print_mmc_cid(mmc_cid_t *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(const struct sd_cid *cid)
{
 printf("Manufacturer:       0x%02x, OEM \"%c%c\"\n",
     cid->mid, cid->oid_0, cid->oid_1);
 printf("Product name:       \"%c%c%c%c%c\", revision %d.%d\n",
     cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4,
     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);
}

int mmc_init(int verbose)
{
  int retries, rc = -ENODEV;
 int is_sd = 0;
 u_int32_t *resp;
 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
 block_dev_desc_t *mmc_blkdev_p = &mmc_dev;

 sdi = S3C2410_GetBase_SDI();

 debug("mmc_init(PCLK=%u)\n", get_PCLK());

 clk_power->CLKCON |= (1 << 9);

 sdi->SDIBSIZE = 512;
#if defined(CONFIG_S3C2410)
 /* S3C2410 has some bug that prevents reliable operation at higher speed */
 //sdi->SDIPRE = 0x3e;  /* SDCLK = PCLK/2 / (SDIPRE+1) = 396kHz */
 sdi->SDIPRE = 0x02;  /* 2410: SDCLK = PCLK/2 / (SDIPRE+1) = 11MHz */
 sdi->SDIDTIMER = 0xffff;
#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
 sdi->SDIPRE = 0x05;  /* 2410: SDCLK = PCLK / (SDIPRE+1) = 11MHz */
 sdi->SDIDTIMER = 0x7fffff;
#endif
 sdi->SDIIMSK = 0x0;
 sdi->SDICON = S3C2410_SDICON_FIFORESET|S3C2410_SDICON_CLOCKTYPE;
 udelay(125000); /* FIXME: 74 SDCLK cycles */

 mmc_csd.c_size = 0;

 /* reset */
 retries = 10;
 resp = mmc_cmd(MMC_CMD_RESET, 0, 0);

 mmc_dev.if_type = IF_TYPE_UNKNOWN;
 if(verbose)
  puts("mmc: Probing for SDHC ...\n");

 /* Send supported voltage range */
 /* SD cards 1.x do not answer to CMD8 */
        resp = mmc_cmd(MMC_CMD_IF_COND, ((1 << 8) | 0xAA), CMD_F_RESP_R7);
        if (!resp[0]) {
             /*
              * ARC: No answer let's try SD 1.x
              */
             if(verbose)
                     puts("mmc: No answer to CMD8 trying SD\n");
             mmc_blkdev_p->if_type = IF_TYPE_SD;
        } else {
             /*
              * ARC: probably an SDHC card
              */
             mmc_blkdev_p->if_type = IF_TYPE_SDHC;
             if(verbose)
                     puts("mmc: SD 2.0 or later card found\n");

             /* Check if the card supports this voltage */
             if (resp[0] != ((1 << 8) | 0xAA)) {
                     pr_debug("mmc: Invalid voltage range\n");
                     return -ENODEV;
             }
        }

 /*
  * ARC: HC (30) bit set according to response to
  * CMD8 command
  */

 pr_debug("mmc: Sending ACMD41 %s HC set\n",
           ((mmc_blkdev_p->if_type ==
             IF_TYPE_SDHC) ? "with" : "without"));

 printf("trying to detect SD Card...\n");
 while (retries--) {
  udelay(100000);
  resp = mmc_cmd(55, 0x00000000, CMD_F_RESP);
  resp = mmc_cmd(41, (mmc_blkdev_p->if_type == IF_TYPE_SDHC)? (0x00300000 | (1<<30)) : 0x00300000, CMD_F_RESP);

  if (resp[0] & (1 << 31)) {
   is_sd = 1;
   break;
  }
 }

 /*
 * ARC: check for HC bit, if its not set
 * sd card is SD
 */
 if (is_sd && (resp[0] & 0xc0000000) == 0x80000000) {
        mmc_dev.if_type = IF_TYPE_SD;
 }

 if (retries == 0 && !is_sd) {
  retries = 10;
  printf("failed to detect SD Card, trying MMC\n");
  mmc_blkdev_p->if_type = IF_TYPE_MMC;
  resp = mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ffc000, CMD_F_RESP);
  while (retries-- && resp && !(resp[4] & 0x80)) {
   debug("resp %x %x\n", resp[0], resp[1]);
   udelay(50);
   resp = mmc_cmd(1, 0x00ffff00, CMD_F_RESP);
  }
 }

 /* try to get card id */
 resp = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, CMD_F_RESP|CMD_F_RESP_LONG);
 if (resp) {
  if (!is_sd) {
   /* TODO configure mmc driver depending on card
      attributes */
   mmc_cid_t *cid = (mmc_cid_t *)resp;

   if (verbose)
    print_mmc_cid(cid);
   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);
  }
  else {
   struct sd_cid *cid = (struct sd_cid *) resp;

   if (verbose)
    print_sd_cid(cid);
   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);
   sprintf((char *) mmc_dev.revision, "%d.%d",
       cid->prv >> 4, cid->prv & 15);
  }

  /* fill in device description */
  if (mmc_dev.if_type == IF_TYPE_UNKNOWN)
   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 32MByte) */
  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, MMC_DEFAULT_RCA, CMD_F_RESP);
  if (is_sd)
   rca = resp[0] >> 16;

  resp = mmc_cmd(MMC_CMD_SEND_CSD, rca<<16, CMD_F_RESP|CMD_F_RESP_LONG);
  if (resp) {
   mmc_csd_t *csd = (mmc_csd_t *)resp;
   memcpy(&mmc_csd, csd, sizeof(csd));
   rc = 0;
   mmc_ready = 1;
   /* FIXME add verbose printout for csd */
   printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n",
    csd->read_bl_len, csd->c_size_mult1, csd->c_size);
   printf("size = %u\n", mmc_size(csd));
  }
 }

 resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca<<16, CMD_F_RESP);

 if (verbose)
        printf("SD Card detected RCA: 0x%x type: %s\n",
               rca, ((mmc_dev.if_type == IF_TYPE_SDHC) ? "SDHC" : ((mmc_dev.if_type == IF_TYPE_SD) ? "SD" : "MMC")));

#ifdef CONFIG_MMC_WIDE
 if (is_sd) {
  resp = mmc_cmd(55, rca<<16, CMD_F_RESP);
  resp = mmc_cmd(6, 0x02, CMD_F_RESP);
  wide = 1;
 }
#endif

 fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */

 return rc;
}

int
mmc_ident(block_dev_desc_t *dev)
{
 return 0;
}

int
mmc2info(ulong addr)
{
 /* FIXME hard codes to 32 MB device */
 if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000)
  return 1;

 return 0;
}

#endif /* defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C) */


【7】添加/include/asm-arm/arch-s3c24x0/mmc.h:

/*
 *  linux/drivers/mmc/mmc_pxa.h
 *
 *  Author: Vladimir Shebordaev, Igor Oblakov
 *  Copyright:  MontaVista Software Inc.
 *
 *  $Id: mmc_pxa.h,v 0.3.1.6 2002/09/25 19:25:48 ted Exp ted $
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 */
#ifndef __MMC_PXA_P_H__
#define __MMC_PXA_P_H__

#include <asm/arch/regs-sdi.h>

#define MMC_DEFAULT_RCA   (1<<16)

#define MMC_BLOCK_SIZE   512
#define MMC_CMD_RESET   0
#define MMC_CMD_SEND_OP_COND  1
#define MMC_CMD_ALL_SEND_CID   2
#define MMC_CMD_SET_RCA   3
#define MMC_CMD_SELECT_CARD  7
#define MMC_CMD_IF_COND                 8
#define MMC_CMD_SEND_CSD   9
#define MMC_CMD_SEND_CID   10
#define MMC_CMD_SEND_STATUS  13
#define MMC_CMD_SET_BLOCKLEN  16
#define MMC_CMD_READ_BLOCK  17
#define MMC_CMD_RD_BLK_MULTI  18
#define MMC_CMD_WRITE_BLOCK  24

#define MMC_MAX_BLOCK_SIZE  512

#define MMC_R1_IDLE_STATE  0x01
#define MMC_R1_ERASE_STATE  0x02
#define MMC_R1_ILLEGAL_CMD  0x04
#define MMC_R1_COM_CRC_ERR  0x08
#define MMC_R1_ERASE_SEQ_ERR  0x01
#define MMC_R1_ADDR_ERR   0x02
#define MMC_R1_PARAM_ERR  0x04

#define MMC_R1B_WP_ERASE_SKIP  0x0002
#define MMC_R1B_ERR   0x0004
#define MMC_R1B_CC_ERR   0x0008
#define MMC_R1B_CARD_ECC_ERR  0x0010
#define MMC_R1B_WP_VIOLATION  0x0020
#define MMC_R1B_ERASE_PARAM  0x0040
#define MMC_R1B_OOR   0x0080
#define MMC_R1B_IDLE_STATE  0x0100
#define MMC_R1B_ERASE_RESET  0x0200
#define MMC_R1B_ILLEGAL_CMD  0x0400
#define MMC_R1B_COM_CRC_ERR  0x0800
#define MMC_R1B_ERASE_SEQ_ERR  0x1000
#define MMC_R1B_ADDR_ERR  0x2000
#define MMC_R1B_PARAM_ERR  0x4000

typedef struct mmc_cid
{
 /* FIXME: BYTE_ORDER */
 uchar year:4,
  month:4;
 uchar sn[3];
 uchar fwrev:4,
  hwrev:4;
 uchar name[6];
 uchar id[3];
} mmc_cid_t;

typedef struct mmc_csd
{
 uchar ecc:2,
  file_format:2,
  tmp_write_protect:1,
  perm_write_protect:1,
  copy:1,
  file_format_grp:1;
 uint64_t content_prot_app:1,
  rsvd3:4,
  write_bl_partial:1,
  write_bl_len:4,
  r2w_factor:3,
  default_ecc:2,
  wp_grp_enable:1,
  wp_grp_size:5,
  erase_grp_mult:5,
  erase_grp_size:5,
  c_size_mult1:3,
  vdd_w_curr_max:3,
  vdd_w_curr_min:3,
  vdd_r_curr_max:3,
  vdd_r_curr_min:3,
  c_size:12,
  rsvd2:2,
  dsr_imp:1,
  read_blk_misalign:1,
  write_blk_misalign:1,
  read_bl_partial:1;

 ushort read_bl_len:4,
  ccc:12;
 uchar tran_speed;
 uchar nsac;
 uchar taac;
 uchar rsvd1:2,
    spec_vers:4,
  csd_structure:2;
} mmc_csd_t;


#endif /* __MMC_PXA_P_H__ */

 

【8】添加include/asm-arm/arch-s3c24x0/regs-sdi.h :

/* linux/include/asm/arch-s3c2410/regs-sdi.h
 *
 * Copyright (c) 2004 Simtec Electronics <[email protected]>
 *        http://www.simtec.co.uk/products/SWLINUX/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * S3C2410 MMC/SDIO register definitions
 *
 *  Changelog:
 *    18-Aug-2004 Ben Dooks      Created initial file
 *    29-Nov-2004 Koen Martens   Added some missing defines, fixed duplicates
 *    29-Nov-2004 Ben Dooks  Updated Koen's patch
*/

#ifndef __ASM_ARM_REGS_SDI
#define __ASM_ARM_REGS_SDI "regs-sdi.h"

#define S3C2440_SDICON_SDRESET        (1<<8)
#define S3C2440_SDICON_MMCCLOCK       (1<<5)
#define S3C2410_SDICON_BYTEORDER      (1<<4)
#define S3C2410_SDICON_SDIOIRQ        (1<<3)
#define S3C2410_SDICON_RWAITEN        (1<<2)
#define S3C2410_SDICON_FIFORESET      (1<<1)
#define S3C2410_SDICON_CLOCKTYPE      (1<<0)

#define S3C2410_SDICMDCON_ABORT       (1<<12)
#define S3C2410_SDICMDCON_WITHDATA    (1<<11)
#define S3C2410_SDICMDCON_LONGRSP     (1<<10)
#define S3C2410_SDICMDCON_WAITRSP     (1<<9)
#define S3C2410_SDICMDCON_CMDSTART    (1<<8)
#define S3C2410_SDICMDCON_SENDERHOST  (1<<6)
#define S3C2410_SDICMDCON_INDEX       (0x3f)

#define S3C2410_SDICMDSTAT_CRCFAIL    (1<<12)
#define S3C2410_SDICMDSTAT_CMDSENT    (1<<11)
#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10)
#define S3C2410_SDICMDSTAT_RSPFIN     (1<<9)
#define S3C2410_SDICMDSTAT_XFERING    (1<<8)
#define S3C2410_SDICMDSTAT_INDEX      (0xff)

#define S3C2440_SDIDCON_DS_BYTE       (0<<22)
#define S3C2440_SDIDCON_DS_HALFWORD   (1<<22)
#define S3C2440_SDIDCON_DS_WORD       (2<<22)
#define S3C2410_SDIDCON_IRQPERIOD     (1<<21)
#define S3C2410_SDIDCON_TXAFTERRESP   (1<<20)
#define S3C2410_SDIDCON_RXAFTERCMD    (1<<19)
#define S3C2410_SDIDCON_BUSYAFTERCMD  (1<<18)
#define S3C2410_SDIDCON_BLOCKMODE     (1<<17)
#define S3C2410_SDIDCON_WIDEBUS       (1<<16)
#define S3C2410_SDIDCON_DMAEN         (1<<15)
#define S3C2410_SDIDCON_STOP          (1<<14)
#define S3C2440_SDIDCON_DATSTART      (1<<14)
#define S3C2410_SDIDCON_DATMODE       (3<<12)
#define S3C2410_SDIDCON_BLKNUM        (0x7ff)

/* constants for S3C2410_SDIDCON_DATMODE */
#define S3C2410_SDIDCON_XFER_READY    (0<<12)
#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12)
#define S3C2410_SDIDCON_XFER_RXSTART  (2<<12)
#define S3C2410_SDIDCON_XFER_TXSTART  (3<<12)

#define S3C2410_SDIDCNT_BLKNUM_MASK   (0xFFF)
#define S3C2410_SDIDCNT_BLKNUM_SHIFT  (12)

#define S3C2410_SDIDSTA_RDYWAITREQ    (1<<10)
#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)
#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8) /* reserved on 2440 */
#define S3C2410_SDIDSTA_CRCFAIL       (1<<7)
#define S3C2410_SDIDSTA_RXCRCFAIL     (1<<6)
#define S3C2410_SDIDSTA_DATATIMEOUT   (1<<5)
#define S3C2410_SDIDSTA_XFERFINISH    (1<<4)
#define S3C2410_SDIDSTA_BUSYFINISH    (1<<3)
#define S3C2410_SDIDSTA_SBITERR       (1<<2) /* reserved on 2410a/2440 */
#define S3C2410_SDIDSTA_TXDATAON      (1<<1)
#define S3C2410_SDIDSTA_RXDATAON      (1<<0)

#define S3C2440_SDIFSTA_FIFORESET      (1<<16)
#define S3C2440_SDIFSTA_FIFOFAIL       (3<<14)  /* 3 is correct (2 bits) */
#define S3C2410_SDIFSTA_TFDET          (1<<13)
#define S3C2410_SDIFSTA_RFDET          (1<<12)
#define S3C2410_SDIFSTA_TFHALF         (1<<11)
#define S3C2410_SDIFSTA_TFEMPTY        (1<<10)
#define S3C2410_SDIFSTA_RFLAST         (1<<9)
#define S3C2410_SDIFSTA_RFFULL         (1<<8)
#define S3C2410_SDIFSTA_RFHALF         (1<<7)
#define S3C2410_SDIFSTA_COUNTMASK      (0x7f)

#define S3C2410_SDIIMSK_RESPONSECRC    (1<<17)
#define S3C2410_SDIIMSK_CMDSENT        (1<<16)
#define S3C2410_SDIIMSK_CMDTIMEOUT     (1<<15)
#define S3C2410_SDIIMSK_RESPONSEND     (1<<14)
#define S3C2410_SDIIMSK_READWAIT       (1<<13)
#define S3C2410_SDIIMSK_SDIOIRQ        (1<<12)
#define S3C2410_SDIIMSK_FIFOFAIL       (1<<11)
#define S3C2410_SDIIMSK_CRCSTATUS      (1<<10)
#define S3C2410_SDIIMSK_DATACRC        (1<<9)
#define S3C2410_SDIIMSK_DATATIMEOUT    (1<<8)
#define S3C2410_SDIIMSK_DATAFINISH     (1<<7)
#define S3C2410_SDIIMSK_BUSYFINISH     (1<<6)
#define S3C2410_SDIIMSK_SBITERR        (1<<5) /* reserved 2440/2410a */
#define S3C2410_SDIIMSK_TXFIFOHALF     (1<<4)
#define S3C2410_SDIIMSK_TXFIFOEMPTY    (1<<3)
#define S3C2410_SDIIMSK_RXFIFOLAST     (1<<2)
#define S3C2410_SDIIMSK_RXFIFOFULL     (1<<1)
#define S3C2410_SDIIMSK_RXFIFOHALF     (1<<0)

#endif /* __ASM_ARM_REGS_SDI */


【9】打开/include/configs/mini2440.h,定位到206行附近,加入宏定义:

/*
USB device support
*/
#define CONFIG_USB_DEVICE   1
#ifdef CONFIG_USB_DEVICE
#define CONFIG_USE_IRQ    1
#endif

#if 1
#define CONFIG_USB_OHCI
#define CONFIG_USB_STORAGE
#define CONFIG_DOS_PARTITION
#define CONFIG_SYS_DEVICE_DEREGISTER
#define CONFIG_SUPPORT_VFAT
#define LITTLEENDIAN
//#define CONFIG_USB_TTY
//#define CONFIG_KEYBOARD
//#define CONFIG_USB_KEYBOARD
#endif

/*
 * SD Card support
 * */
#if 1
#define CONFIG_CMD_MMC
#define CONFIG_MMC  1
#define CONFIG_MMC_S3C 1 /* Enabling the MMC driver */
#define CFG_MMC_BASE  0xff000000
#endif

9.2 重新编译测试

SD 卡的使用命令比较简单,只有初始化和设备信息的显示,读写是通过文件系统命令实现的。使用和USB 类似,在所有的命令使用前,必须先插入SD 卡,然后使用:mmc init,以初始化MMC 控制器,获取设备信息。

待编译完成后,nor档下��nand档启动,这这里插入的是128M 的SD卡,并将内核文件拷贝其中,操作如下:

[u-boot@MINI2440]# ? mmc
mmc - MMC sub-system

Usage:
mmc init [dev] - init MMC sub system
mmc device [dev] - show or set current device
[u-boot@MINI2440]# mmc init
mmc: Probing for SDHC ...
===============> MMC CMD Timeout
mmc: No answer to CMD8 trying SD
trying to detect SD Card...
Manufacturer:       0x01, OEM "PA"
Product name:       "SS128", revision 5.9
Serial number:      1142218862
Manufacturing date: 11/2009
CRC:                0x20, b0 = 1
READ_BL_LEN=6, C_SIZE_MULT=3, C_SIZE=4095
size = 0
SD Card detected RCA: 0xe06f type: SD
mmc1 is available
[u-boot@MINI2440]# mmc device
mmc1 is current device
[u-boot@MINI2440]#

下载内核文件:

[u-boot@MINI2440]# fatload mmc 1 0x30008000 uImage_T35
reading uImage_T35

2022412 bytes read
[u-boot@MINI2440]#[u-boot@MINI2440]# bootm 0x30008000
## Booting kernel from Legacy Image at 30008000 ...
   Image Name:   mini2440_linux
   Created:      2011-05-12   3:37:00 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2022348 Bytes =  1.9 MB
   Load Address: 30008000
   Entry Point:  30008040
   Verifying Checksum ... OK
   XIP Kernel Image ... OK
OK

Starting kernel ...

Uncompressing Linux.........

可以看到内核正在启动。

下一步,为u-boot-2009.08增加I2C EEPROM 功能。


你可能感兴趣的:(sd)