Chinaunix首页 | 论坛 | 博客
  • 博客访问: 641400
  • 博文数量: 363
  • 博客积分: 110
  • 博客等级: 民兵
  • 技术积分: 1347
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-22 16:07
文章分类

全部博文(363)

文章存档

2018年(83)

2016年(1)

2014年(2)

2013年(34)

2012年(236)

2011年(7)

分类:

2012-05-21 18:14:15

原文地址:flash驱动分析 作者:lwchsz

struct device {
    struct device        *parent;

    struct device_private    *p;

    struct kobject kobj;
    const char        *init_name; /* initial name of the device */
    struct device_type    *type;

    struct semaphore    sem;    /* semaphore to synchronize calls to
                     * its driver.
                     */

    struct bus_type    *bus;        /* type of bus device is on */
    struct device_driver *driver;    /* which driver has allocated this
                       device */
    void        *driver_data;    /* data private to the driver */
    void        *platform_data;    /* Platform specific data, device
                       core doesn't touch it */
    struct dev_pm_info    power;

#ifdef CONFIG_NUMA
    int        numa_node;    /* NUMA node this device is close to */
#endif
    u64        *dma_mask;    /* dma mask (if dma'able device) */
    u64        coherent_dma_mask;/* Like dma_mask, but for
                         alloc_coherent mappings as
                         not all hardware supports
                         64 bit addresses for consistent
                         allocations such descriptors. */

    struct device_dma_parameters *dma_parms;

    struct list_head    dma_pools;    /* dma pools (if dma'ble) */

    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                         override */
    /* arch specific additions */
    struct dev_archdata    archdata;

    dev_t            devt;    /* dev_t, creates the sysfs "dev" */

    spinlock_t        devres_lock;
    struct list_head    devres_head;

    struct klist_node    knode_class;
    struct class        *class;
    struct attribute_group    **groups;    /* optional groups */

    void    (*release)(struct device *dev);
};

struct platform_device {
    const char    * name;
    int        id;
    struct device    dev;
    u32        num_resources;
    struct resource    * resource;

    struct platform_device_id    *id_entry;
};

struct platform_device cns3xxx_flash_device = {
    .name            = "cns3xxxflash",//设备名称,要与设备驱动名称一致
    .id            = 0,
    .dev            = {
        .platform_data    = &cns3xxx_flash_data,//设备特定数据
    },
};

struct flash_platform_data {//该结构体只有ARM体系结构有定义
    const char    *map_name;
    const char    *name;
    unsigned int    width;
    int        (*init)(void);
    void        (*exit)(void);
    void        (*set_vpp)(int on);
    void        (*mmcontrol)(struct mtd_info *mtd, int sync_read);
    struct mtd_partition *parts;
    unsigned int    nr_parts;
};
static struct flash_platform_data cns3xxx_flash_data = {
    .map_name        = "cfi_probe",//cfi 类型flash
    .width            = 2,//16位宽
    .init            = cns3xxx_flash_init,
    .exit            = cns3xxx_flash_exit,
    .set_vpp        = cns3xxx_flash_set_vpp,
};

static int cns3xxx_flash_init(void)
{

    return 0;
}

static void cns3xxx_flash_exit(void)
{

}

static void cns3xxx_flash_set_vpp(int on)
{

}

int cns3xxx_flash_register(struct resource *res, u32 num)//特定的flash资源注册函数
{
    cns3xxx_flash_device.resource = res;
    cns3xxx_flash_device.num_resources = num;
    return platform_device_register(&cns3xxx_flash_device);//注册flash设备
}

/*
 * Cavium Networks ARM11 MPCore platform devices
 */
static struct resource cns3xxx_flash_resource[] = {
    [0] = {
        .start        = CNS3XXX_FLASH0_BASE,
        .end        = CNS3XXX_FLASH0_BASE + CNS3XXX_FLASH0_SIZE - 1,
        .flags        = IORESOURCE_MEM,
    }, /*
    [1] = {
        .start        = CNS3XXX_FLASH1_BASE,
        .end        = CNS3XXX_FLASH1_BASE + CNS3XXX_FLASH1_SIZE - 1,
        .flags        = IORESOURCE_MEM,
    }, */
};

#define CNS3XXX_FLASH0_BASE            0x10000000    /* Flash/SRAM Memory Bank 0 */
#ifdef CONFIG_SILICON
#define CNS3XXX_FLASH0_SIZE            SZ_128M
#else
#define CNS3XXX_FLASH0_SIZE            SZ_8M
#endif

static void __init cns3xxx_init(void)
{
    int i;

#ifdef CONFIG_CACHE_L2X0
    /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
     * Bits:  .... ...0 0111 1001 0000 .... .... .... */
    l2x0_init((void __iomem *) CNS3XXX_TC11MP_L220_BASE_VIRT, 0x00790000, 0xfe000fff);
#endif

#ifdef CONFIG_CACHE_L2CC
    l2cc_init((void __iomem *) CNS3XXX_L2C_BASE_VIRT);
#endif

#ifdef CONFIG_CNS3XXX_DMAC
    dmac_init();
#endif

#ifdef CONFIG_CNS3XXX_RAID
    cns_rdma_init();
#endif
   Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;}

   cns3xxx_flash_register(cns3xxx_flash_resource, ARRAY_SIZE(cns3xxx_flash_resource));//此时注册FLASH资源


    platform_add_devices(cns3xxx_devs, ARRAY_SIZE(cns3xxx_devs));

    for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
        struct amba_device *d = amba_devs[i];
        int ret;
       
        cns3xxx_pwr_power_up(CNS3XXX_PWR_PLL(PLL_LCD));
        cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(LCDC));
        cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(LCDC));

        ret = amba_device_register(d, &iomem_resource);
        if(ret)
            printk("%s=>%d: %d\n", __FUNCTION__, __LINE__, ret);
    }

    lm_device_register(&cns3xxx_usb_otg_device);
   
    i2c_register_board_info(0, cns3xxx_i2c_devices, ARRAY_SIZE(cns3xxx_i2c_devices));
    i2c_register_board_info(1, cns3xxx_i2c_gpio_devices, ARRAY_SIZE(cns3xxx_i2c_gpio_devices));

    spi_register_board_info(cns3xxx_spi_devices, ARRAY_SIZE(cns3xxx_spi_devices));

    cns3xxx_proc_dir = proc_mkdir("cns3xxx", NULL);
#ifdef CONFIG_DEBUG_FS
    cns3xxx_debugfs_dir = debugfs_create_dir("cns3xxx", NULL);
#endif

#ifdef CONFIG_CACHE_L2CC
    l2cc_proc_init();
#endif

    pm_power_off = cns3xxx_power_off;
}


//FLASH驱动结构
static struct platform_driver cns3xxxflash_driver = {
    .probe        = cns3xxxflash_probe,//初始化函数
    .remove        = cns3xxxflash_remove,
    .driver        = {
        .name    = "cns3xxxflash",//设备驱动名称,与上面设备名称一致
        .owner    = THIS_MODULE,
    },
};

static int cns3xxxflash_probe(struct platform_device *dev)
{
    struct flash_platform_data *plat = dev->dev.platform_data;
    struct resource *res = dev->resource;
    unsigned int size = res->end - res->start + 1;
    struct cns3xxxflash_info *info;
    int err;
    void __iomem *base;
    struct mtd_partition *parts;
    int nb_parts = 0;
    int parsed_nr_parts = 0;

    parts = cns3xxx_flash_partitions;//分区表
    nb_parts = ARRAY_SIZE(cns3xxx_flash_partitions);//分区数目
    //分配一个驱动自定义结构
    info = kzalloc(sizeof(struct cns3xxxflash_info), GFP_KERNEL);
    if (!info) {
        err = -ENOMEM;
        goto out;
    }

    info->plat = plat;
    if (plat && plat->init) {//此时调用的其实是cns3xxx_flash_init,它不做任何事情
        err = plat->init();
        if (err)
            goto no_resource;
    }

    info->res = request_mem_region(res->start, size, "flash");//登记内存资源使用情况
    if (!info->res) {
        err = -EBUSY;
        goto no_resource;
    }

    base = ioremap(res->start, size);//把物理地址映射到内核讯地址,方便内核进行访问
    if (!base) {
        err = -ENOMEM;
        goto no_mem;
    }

    /*
     * look for CFI based flash parts fitted to this board//cfi 相关初始化
     */
    info->map.size        = size;
    info->map.bankwidth    = plat->width;
    info->map.phys        = res->start;
    info->map.virt        = base;
    info->map.name        = "cns3xxxflash";

    simple_map_init(&info->map);//对MAP进行进一步初始化

    /*
     * Also, the CFI layer automatically works out what size
     * of chips we have, and does the necessary identification
     * for us automatically.
     */
    info->mtd = do_map_probe(plat->map_name, &info->map);//进行flash驱动的自n动探测,因//map_name为"cfi_probe",所以其实调用了cfi驱动模块进行处理
    if (!info->mtd) {
        err = -ENXIO;
        goto no_device;
    }

    info->mtd->owner = THIS_MODULE;

    if (parsed_nr_parts > 0) {//条件为假
        parts = parsed_parts;
        nb_parts = parsed_nr_parts;
    }

    if (nb_parts == 0) {
        printk(KERN_NOTICE "CNS3XXX NOR flash: No partition info available \n");
        if (add_mtd_device(info->mtd))
            return -ENXIO;
    } else {
        printk(KERN_NOTICE "CNS3XXX NOR flash: Using static partition definition\n");
        return add_mtd_partitions(info->mtd, parts, nb_parts);//增加mtd分区信息
    }

    platform_set_drvdata(dev, info);

    err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
    if (err > 0) {
        err = add_mtd_partitions(info->mtd, info->parts, err);
        if (err)
            printk(KERN_ERR
                   "mtd partition registration failed: %d\n", err);
    }

    if (err == 0)
        platform_set_drvdata(dev, info);

    /*
     * If we got an error, free all resources.
     */
    if (err < 0) {
        if (info->mtd) {
            del_mtd_partitions(info->mtd);
            map_destroy(info->mtd);
        }
        kfree(info->parts);

 no_device:
        iounmap(base);
 no_mem:
        release_mem_region(res->start, size);
 no_resource:
        if (plat && plat->exit)
            plat->exit();
        kfree(info);
    }
 out:
    return err;
}

struct cns3xxxflash_info {//驱动特定结构
    struct flash_platform_data *plat;
    struct resource        *res;//指向资源信息
    struct mtd_partition    *parts;//分区信息
    struct mtd_info        *mtd;//mtd信息
    struct map_info        map;//map信息
};

//对FLASH的位宽进行合法性判断
#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))

static inline int map_bankwidth_supported(int w)
{
    switch (w) {
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
    case 1:
#endif
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
    case 2:
#endif
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
    case 4:
#endif
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
    case 8:
#endif
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
    case 16:
#endif
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
    case 32:
#endif
        return 1;

    default:
        return 0;
    }
}

static int cns3xxxflash_remove(struct platform_device *dev)
{
    struct cns3xxxflash_info *info = platform_get_drvdata(dev);

    platform_set_drvdata(dev, NULL);

    if (info) {
        if (info->mtd) {
            del_mtd_partitions(info->mtd);//删除分区
            map_destroy(info->mtd);//销毁mtd设备
        }
        kfree(info->parts);

        iounmap(info->map.virt);
        release_resource(info->res);
        kfree(info->res);

        if (info->plat && info->plat->exit)
            info->plat->exit();

        kfree(info);
    }

    return 0;
}
阅读(381) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~