RT5350 nvram驱动分析

一、相关版本

sdk版本:MTK_Ralink_ApSoC_SDK_4200_20131106

kernel版本:linux-2.6.21.x

二、分析

1.nvram初始化接口:void nvram_init(int index)

a. 编译配置:cat sdk/RT288x_SDK/source/linux-2.6.21/.config | grep NVRAM

CONFIG_KERNEL_NVRAM=y
CONFIG_HOSTAP_FIRMWARE_NVRAM=y

a. 位置:sdk/RT288x_SDK/source/lib/libnvram/nvram_env.c

b. nvram_init代码片段

    from = fb[index].flash_offset + sizeof(fb[index].env.crc);
    len = fb[index].flash_max_len - sizeof(fb[index].env.crc);
    fb[index].env.data = (char *)malloc(len);
    nvr.index = index;
    nvr.value = fb[index].env.data;
    fd = open(NV_DEV, O_RDONLY);
    if (fd < 0) {
        perror(NV_DEV);
        goto out;
    }
    if (ioctl(fd, RALINK_NVRAM_IOCTL_GETALL, &nvr) < 0) {
        perror("ioctl");
        close(fd);
        goto out;
    }


    p = fb[index].env.data;
    for (i = 0; i < MAX_CACHE_ENTRY; i++) {
        if (NULL == (q = strchr(p, '='))) {
            LIBNV_PRINT("parsed failed - cannot find '='\n");
            break;
        }
        *q = '\0'; //strip '='
        fb[index].cache[i].name = strdup(p);
        //printf("  %d '%s'->", i, p);

        p = q + 1; //value
        if (NULL == (q = strchr(p, '\0'))) {
            LIBNV_PRINT("parsed failed - cannot find '\\0'\n");
            break;
        }
        fb[index].cache[i].value = strdup(p);
        //printf("'%s'\n", p);

        p = q + 1; //next entry
        if (p - fb[index].env.data + 1 >= len) //end of block
            break;
        if (*p == '\0') //end of env
            break;
    }

这里主要是跟进fb全局变量,获取flash块信息,打开NV_DEV ("/dev/nvram" )设备,通过ioctl对其进行读入操作,并复制到内存空间。所以nvram接口是对/dev/nvram设备进行操作的。那么/dev/nvram设备是怎么被加载的呢?

2. nvram设备

a. 根据CONFIG_KERNEL_NVRAM=y ,在内核make menuconfig查找KERNEL_NVRAM

Symbol: KERNEL_NVRAM [=y]                                                                                                                │  
  │ Prompt: Kernel NVRAM                                                                                                                     │  
  │   Defined at arch/mips/rt2880/Kconfig:182                                                                                                │  
  │   Location:                                                                                                                              │  
  │     -> Machine selection

b. arch/mips/rt2880/Makefile:

obj-$(CONFIG_KERNEL_NVRAM) += nvram.o

发现nvram设备。

c. arch/mips/rt2880/nvram.c

late_initcall(ra_nvram_init);
module_exit(ra_nvram_exit);
EXPORT_SYMBOL(nvram_get);
EXPORT_SYMBOL(nvram_set);
EXPORT_SYMBOL(nvram_commit);


设备注册接口。

d. 设备初始化接口ra_nvram_init

    r = register_chrdev(ralink_nvram_major, RALINK_NVRAM_DEVNAME,
            &ralink_nvram_fops);
    if (r < 0) {
        printk(KERN_ERR "ralink_nvram: unable to register character device\n");
        return r;
    }
    if (ralink_nvram_major == 0) {
        ralink_nvram_major = r;
        printk(KERN_DEBUG "ralink_nvram: got dynamic major %d\n", r);
    }

    init_MUTEX(&nvram_sem);

    down(&nvram_sem);
    for (i = 0; i < FLASH_BLOCK_NUM; i++)
        init_nvram_block(i);
    up(&nvram_sem);

先调用register_chrdev注册设备RALINK_NVRAM_DEVNAME("nvram")接口,然后调用init_nvram_block对复制flash到内存进行初始化。终于找到flash读入的接口了。

3. init_nvram_block接口

    //read data from flash
    from = from + len;
    len = fb[i].flash_max_len - len;
    fb[i].env.data = (char *)kmalloc(len, GFP_KERNEL);
    if (!fb[i].env.data)
        return -ENOMEM;

    ra_mtd_read_nm(RALINK_NVRAM_MTDNAME, from, len, (unsigned char *)fb[i].env.data);

调用MTD设备接口ra_mtd_read_nm对设备RALINK_NVRAM_MTDNAME("Config")进行读入。

 Symbol: MTD_SPI_RALINK [=y]                                                                                                               │  
  │ Prompt: SPI                                                                                                                               │  
  │   Defined at arch/mips/rt2880/Kconfig:143                                                                                                 │  
  │   Depends on: <choice> && !RALINK_RT2880                                                                                                  │  
  │   Location:                                                                                                                               │  
  │     -> Machine selection                                                                                                                  │  
  │       -> Flash Type (<choice> [=y]) 

4. MTD设备接口ra_mtd_read_nm

位置:drivers/mtd/maps/ralink-flash.c

    mtd = get_mtd_device_nm(name);
    if (IS_ERR(mtd))
        return (int)mtd;

    ret = mtd->read(mtd, from, len, &rdlen, buf);

通过对mtd设备"Config"读接口操作。

5. MTD设备初始化接口rt2880_mtd_init

    for (i = 0; i < NUM_FLASH_BANKS; i++) {
        printk(KERN_NOTICE "ralink flash device: 0x%x at 0x%x\n",
                ralink_map[i].size, ralink_map[i].phys);

        ralink_map[i].virt = ioremap_nocache(ralink_map[i].phys, ralink_map[i].size);
        if (!ralink_map[i].virt) {
            printk("Failed to ioremap\n");
            return -EIO;
        }
        simple_map_init(&ralink_map[i]);

        ralink_mtd[i] = do_map_probe("cfi_probe", &ralink_map[i]);
        if (ralink_mtd[i]) {
            ralink_mtd[i]->owner = THIS_MODULE;
            ralink_mtd[i]->lock = ralink_lock;
            ralink_mtd[i]->unlock = ralink_unlock;
            ++found;
        }
        else
            iounmap(ralink_map[i].virt);
    }
    if (found == NUM_FLASH_BANKS) {
#ifdef CONFIG_RT2880_FLASH_32M
        merged_mtd = mtd_concat_create(ralink_mtd, NUM_FLASH_BANKS,
                "Ralink Merged Flash");
        ret = add_mtd_partitions(merged_mtd, rt2880_partitions,
                ARRAY_SIZE(rt2880_partitions));
#else
        ret = add_mtd_partitions(ralink_mtd[0], rt2880_partitions,
                ARRAY_SIZE(rt2880_partitions));
#endif
        if (ret) {
            for (i = 0; i < NUM_FLASH_BANKS; i++)
                iounmap(ralink_map[i].virt);
            return ret;
        }
    }
    else {
        printk("Error: %d flash device was found\n", found);
        return -ENXIO;
    }
#endif

构造map_info结构,调用do_map_probe,根据名字"cfi_probe"找到芯片驱动linux-2.6.21.x/drivers/mtd/chips/cfi_probe.c。

6. cfi_probe

    return mtd_do_chip_probe(map, &cfi_chip_probe);


cfi_probe()直接调用mtd_do_chip_probe(),传入cfi_probe_chip()函数指针和map_info。

7. mtd_do_chip_probe(linux-2.6.21.x/drivers/mtd/chips/gen_probe.c)

    cfi = genprobe_ident_chips(map, cp);

    if (!cfi)
        return NULL;

    map->fldrv_priv = cfi;
    /* OK we liked it. Now find a driver for the command set it talks */

    mtd = check_cmd_set(map, 1); /* First the primary cmdset */
    if (!mtd)
        mtd = check_cmd_set(map, 0); /* Then the secondary */

先调用genprobe_ident_chips(),cfi_probe_chip根据map_info探测芯片信息,后调用check_cmd_set()获取和初始化芯片命令集。

8. ralink_spi.c(linux-2.6.21.x/drivers/mtd/ralink/ralink_spi.c)

static struct mtd_partition rt2880_partitions[] = {
    {
                name:           "ALL",
                size:           MTDPART_SIZ_FULL,
                offset:         0,
        },
    /* Put your own partition definitions here */
        {
                name:           "Bootloader",
                size:           MTD_BOOT_PART_SIZE,
                offset:         0,
        }, {
                name:           "Config",
                size:           MTD_CONFIG_PART_SIZE,
                offset:         MTDPART_OFS_APPEND
        }, {
                name:           "Factory",
                size:           MTD_FACTORY_PART_SIZE,
                offset:         MTDPART_OFS_APPEND
#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH
        }, {
                name:           "Kernel",
                size:           MTD_KERN_PART_SIZE,
                offset:         MTDPART_OFS_APPEND,
        }, {
                name:           "RootFS",
                size:           MTD_ROOTFS_PART_SIZE,
                offset:         MTDPART_OFS_APPEND,
#ifdef CONFIG_ROOTFS_IN_FLASH_NO_PADDING
        }, {
                name:           "Kernel_RootFS",
                size:           MTD_KERN_PART_SIZE + MTD_ROOTFS_PART_SIZE,
                offset:         MTD_BOOT_PART_SIZE + MTD_CONFIG_PART_SIZE + MTD_FACTORY_PART_SIZE,
#endif
#else //CONFIG_RT2880_ROOTFS_IN_RAM
        }, {
                name:           "Kernel",
                size:           MTD_KERN_PART_SIZE,
                offset:         MTDPART_OFS_APPEND,
#endif
#ifdef CONFIG_DUAL_IMAGE
        }, {
                name:           "Kernel2",
                size:           MTD_KERN2_PART_SIZE,
                offset:         MTD_KERN2_PART_OFFSET,
#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH
        }, {
                name:           "RootFS2",
                size:           MTD_ROOTFS2_PART_SIZE,
                offset:         MTD_ROOTFS2_PART_OFFSET,
#endif
#endif
        }
};

mtd分区,cfi_probe_chip通过分区信息表关联mtd接口到该设备的操作接口。

static int __init raspi_init(void)
{
    register_mtd_chip_driver(&raspi_chipdrv);
    
        raspi_chipdrv.probe(NULL);

    return 0;
}


mtd设备初始化。

    flash->chip = chip;
    flash->mtd.name = "raspi";

    flash->mtd.type = MTD_NORFLASH;
    flash->mtd.writesize = 1;
    flash->mtd.flags = MTD_CAP_NORFLASH;
    flash->mtd.size = chip->sector_size * chip->n_sectors;
    flash->mtd.erasesize = chip->sector_size;
    flash->mtd.erase = ramtd_erase;
    flash->mtd.read = ramtd_read;
    flash->mtd.write = ramtd_write;
    flash->mtd.lock = ramtd_lock;
    flash->mtd.unlock = ramtd_unlock;

flash驱动具体操作接口。

转载于:https://my.oschina.net/u/2319290/blog/483998

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值