Chinaunix首页 | 论坛 | 博客
  • 博客访问: 183562
  • 博文数量: 42
  • 博客积分: 606
  • 博客等级: 中士
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-14 15:51
文章分类

全部博文(42)

文章存档

2013年(3)

2012年(39)

我的朋友

分类:

2012-04-18 13:58:05

上面一章分析了MTD的实现(未完)接上文
在完成了函数的初始化以后则是调用smc_insert()
函数:

inline int
smc_insert(struct nand_chip *this) {
    /* Scan to find existance of the device */
    if (smc_scan(mymtd)) {
        return -ENXIO;
    }
    /* Allocate memory for internal data buffer */
    this->data_buf = mmalloc(sizeof(u_char) *
             (mymtd->oobblock + mymtd->oobsize));

    if (!this->data_buf) {
        printk("Unable to allocate NAND data buffer for S3C2440.\n");
        this->data_buf = NULL;
        return -ENOMEM;
    }

    return 0;
}


这个函数包括两个部分
inline int smc_insert(struct nand_chip *this);
1:smc_insert()函数的功能就是调用smc_scan()函数
2:然后就是给this结构内部数据申请内存:this->data_buf = mmalloc(sizeof(u_char) *(mymtd->oobblock + mymtd->oobsize));
第2部分很好理解(在vivi的第5部分heap_init中有关于mmalloc函数的源代码)
现在来分析第一部分,smc_scan()函数
在分析smc_scan函数之前,我们先来看一个nand_flash_dev结构,这个结构定义了一些常用的nand flash的基本信息:

static struct nand_flash_dev nand_flash_ids[] = { 
    {"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000}, // 2Mb 5V

    {"Toshiba TC58V16BDC", NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000}, // 2Mb 3.3V

    {"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000}, // 4Mb 5V

    {"Toshiba TC58V32DC", NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000}, // 4Mb 3.3V

    {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000}, // 8Mb 3.3V

    {"Toshiba TH58V128DC", NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000}, // 16Mb

    {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000}, // 32Mb

    {"Toshiba TH58512FT", NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000}, // 64Mb

    {"Toshiba TH58NS100/DC", NAND_MFR_TOSHIBA, 0x79, 27, 0, 3, 0x4000}, // 128Mb

    {"Samsung KM29N16000", NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000}, // 2Mb 5V

    {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000}, // 2Mb 3.3V

    {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000}, // 4Mb 5V

    {"Samsung KM29W32000", NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000}, // 4Mb 3.3V

    {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000}, // 4Mb 3.3V

    {"Samsung KM29U64000", NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000}, // 8Mb 3.3V

    {"Samsung KM29U128T", NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000}, // 16Mb

    {"Samsung KM29U256T", NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000}, // 32Mb

    {"Samsung K9D1208V0M", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000}, // 64Mb

    {"Samsung K9D1G08V0M", NAND_MFR_SAMSUNG, 0x79, 27, 0, 3, 0x4000}, // 128Mb

    {NULL,}
};



先来分析smc_scan(struct mtd_info *mtd)函数的基本流程:
smc_scan-->nand_select()
        -->nand_command(mtd, NAND_CMD_READID, 0x00, -1)
        -->this->wait_for_ready();等待flash设备准备好
        -->在找到于上面结构匹配的flash之后则是对mtd_info结构赋值
        -->nand_deselect();
        -->解析填充MTD driver中的数据

其实总结一下就是使能我们使用的nand flash,并且读出ID其信息,然后与在已知寻找与之匹配的设备,并且对其初始化

在知道了大概的流程和功能后我们来对每一个函数进行具体的分析:
一:nand_select();
这个函数是用一个宏来定义的,具体定义如下
#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); \
                        nand_command(mtd, NAND_CMD_RESET, -1, -1); \
                        udelay(10);
这个宏定义其实就是调用了3个函数,
第一个函数我们在第一章里面就说明了,其实就是调用smc_hwcontrol(NAND_CTL_SETNCE)函数,作用就是enable the chip select
第二个函数调用:nand_command()函数,现来看看nand_command函数的原型:
(vivi/drivers/mtd/nand/smc_core.c)

/*
 * Send command to NAND device
 */

static void 
nand_command(struct mtd_info *mtd, unsigned command, int column, intpage_addr)
{
    register struct nand_chip *this = mtd->priv;

    /* Begin command latch cycle */
    this->hwcontrol(NAND_CTL_SETCLE);

    this->hwcontrol(NAND_CTL_DAT_OUT);

    /* 
     * Write out the command to the device.
     */

    if (command != NAND_CMD_SEQIN)
        this->write_cmd(command);
    else {
        if (mtd->oobblock == 256 && column >= 256) {
            column -= 256; 
            this->write_cmd(NAND_CMD_RESET);
            this->write_cmd(NAND_CMD_READOOB);
            this->write_cmd(NAND_CMD_SEQIN);
        } else if (mtd->oobblock == 512 && column >= 256) {
            if (column < 512) {
                column -= 256; 
                this->write_cmd(NAND_CMD_READ1);
                this->write_cmd(NAND_CMD_SEQIN);
            } else {
                column -= 512; 
                this->write_cmd(NAND_CMD_READOOB);
                this->write_cmd(NAND_CMD_SEQIN);
            } 
        } else {
            this->write_cmd(NAND_CMD_READ0);
            this->write_cmd(NAND_CMD_SEQIN);
        } 
    } 

    /* Set ALE and clear CLE to start address cycle */
    this->hwcontrol(NAND_CTL_CLRCLE);
    this->hwcontrol(NAND_CTL_SETALE);

    /* Serially input address */
    if (column != -1)
        this->write_addr(column);
    if (page_addr != -1) {
        this->write_addr((u_char)(page_addr & 0xff));
        this->write_addr((u_char)((page_addr >> 8) & 0xff));
        /* One more address cycle for higher density devices */
        if (mtd->size & 0x0c000000) {
            this->write_addr((u_char)((page_addr >> 16) & 0xff));
        }
    }

    /* Latch in address */
    this->hwcontrol(NAND_CTL_CLRALE);

    this->hwcontrol(NAND_CTL_DAT_IN);
    /* Pause for 15us */
    udelay(15);
 }


从这里可以看出是使得nand_flash重启,
3):延时.
二:nand_command(mtd, NAND_CMD_READID, 0x00, -1);
从上面的nand_command函数的原型中可以看出,这个函数的目的就是读取nand flash的设备ID
三:this->wait_for_ready();
四:遍历常用nand flash结构数组,找到匹配的设备,并且初始化mtd_info 和 nand_chip结构
五:nand_deselect();
这个函数的原型也有一个宏定义;
#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE)   //disable chip select
继续填充MTD drivers中的数据(初始化各种数据和函数)
下面是vivi中smc_scan(struct mtd_info *mtd)的原型


/*
 * Scan for the SMC device
 */

int
smc_scan(struct mtd_info *mtd)
{
    int i, nand_maf_id, nand_dev_id;
    struct nand_chip *this = mtd->priv;

    /* Select the device */
    nand_select();

    /* Send the command for reading device ID */
    nand_command(mtd, NAND_CMD_READID, 0x00, -1);

    this->wait_for_ready();

    /* Read manufacturer and device IDs */
    nand_maf_id = this->read_data();
    nand_dev_id = this->read_data();

    /* Print and sotre flash device information */
    for (i = 0; nand_flash_ids[i].name != NULL; i++) {
        if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
            nand_dev_id == nand_flash_ids[i].model_id) {
#ifdef USE_256BYTE_NAND_FLASH
            if (!mtd->size) {
                mtd->name = nand_flash_ids[i].name;
                mtd->erasesize = nand_flash_ids[i].erasesize;
                mtd->size = (1 << nand_flash_ids[i].chipshift);
                mtd->eccsize = 256;
                if (nand_flash_ids[i].page256) {
                    mtd->oobblock = 256;
                    mtd->oobsize = 8;
                    this->page_shift = 8;
                } else {
                    mtd->oobblock = 512;
                    mtd->oobsize = 16;
                    this->page_shift = 9;
                }
                this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
            }
#else
            if (!(mtd->size) && !(nand_flash_ids[i].page256)) {
                mtd->name = nand_flash_ids[i].name;
                mtd->erasesize = nand_flash_ids[i].erasesize;
                mtd->size = (1 << nand_flash_ids[i].chipshift);
                mtd->eccsize = 256;
                mtd->oobblock = 512;
                mtd->oobsize = 16;
                this->page_shift = 9;
                this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
            }
#endif
            printk("NAND device: Manufacture ID:" \
                " 0x%02x, Chip ID: 0x%02x (%s)\n",
                nand_maf_id, nand_dev_id, mtd->name);
            break;
        }
    }

    /* De-select the device */
    nand_deselect();

    /* Print warning message for no device */
    if (!mtd->size) {
        printk("No NAND device found!!!\n");
        return 1;
    }

    /* Fill in remaining MTD driver data */
    mtd->type = MTD_NANDFLASH;
    mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
    mtd->module = NULL;
    mtd->ecctype = MTD_ECC_SW;
    mtd->erase = nand_erase;
    mtd->point = NULL;
    mtd->unpoint = NULL;
    mtd->read = nand_read;
    mtd->write = nand_write;
    mtd->read_ecc = nand_read_ecc;
    mtd->write_ecc = nand_write_ecc;
    mtd->read_oob = nand_read_oob;
    mtd->write_oob = nand_write_oob;
    mtd->lock = NULL;
    mtd->unlock = NULL;

    /* Return happy */
    return 0;
}


这是函数的整体的概括,后面会陆续分析具体函数的实现。从来彻底了解在vivi中MTD中间驱动层的概念(未完,待续!
后一章位置:
阅读(907) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~