RT5350 nvram驅動分析

1、相關版本

sdk版本:MTK_Ralink_ApSoC_SDK_4200_20131106linux

kernel版本:linux-2.6.21.xide

2、分析

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
spa

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;
    }ip

////////////////////////////////////////////////////////////////
內存

    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;
    }
rem

這裏主要是跟進fb全局變量,獲取flash塊信息,打開NV_DEV ("/dev/nvram" )設備,經過ioctl對其進行讀入操做,並複製到內存空間。因此nvram接口是對/dev/nvram設備進行操做的。那麼/dev/nvram設備是怎麼被加載的呢?get

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驅動具體操做接口。

相關文章
相關標籤/搜索