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 (dmalek@jlc.net)
*/
#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 <laforge@openmoko.org>
*
* 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 <linux@simtec.co.uk>
*
*
* 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 功能。