flash驱动分析

简介: struct device {    struct device        *parent;    struct device_private    *p;    struct kobject kobj;    const char        *init_name; /* i...
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         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         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;
}
目录
相关文章
|
2天前
|
云安全 人工智能 自然语言处理
AI说的每一句话,都靠谱吗?
阿里云提供AI全栈安全能力,其中针对AI输入与输出环节的安全合规挑战,我们构建了“开箱即用”与“按需增强”相结合的多层次、可配置的内容安全机制。
|
6天前
|
存储 人工智能 安全
AI 越智能,数据越危险?
阿里云提供AI全栈安全能力,为客户构建全链路数据保护体系,让企业敢用、能用、放心用
|
8天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
3天前
|
消息中间件 安全 NoSQL
阿里云通过中国信通院首批安全可信中间件评估
近日,由中国信通院主办的 2025(第五届)数字化转型发展大会在京举行。会上,“阿里云应用服务器软件 AliEE”、“消息队列软件 RocketMQ”、“云数据库 Tair”三款产品成功通过中国信通院“安全可信中间件”系列评估,成为首批获此认证的中间件产品。此次评估覆盖安全可信要求、功能完备性、安全防护能力、性能表现、可靠性与可维护性等核心指标,标志着阿里云中间件产品在多架构适配与安全能力上达到行业领先水平。
301 192
|
3天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
333 165
|
2天前
|
开发者
「玩透ESA」ESA启用和加速-ER在加速场景中的应用
本文介绍三种配置方法:通过“A鉴权”模板创建函数并设置触发器路由;在ESA上配置回源302跟随;以及自定义响应头。每步均配有详细截图指引,帮助开发者快速完成相关功能设置,提升服务安全性与灵活性。
302 2
|
7天前
|
数据采集 人工智能 自然语言处理
3分钟采集134篇AI文章!深度解析如何通过云无影AgentBay实现25倍并发 + LlamaIndex智能推荐
结合阿里云无影 AgentBay 云端并发采集与 LlamaIndex 智能分析,3分钟高效抓取134篇 AI Agent 文章,实现 AI 推荐、智能问答与知识沉淀,打造从数据获取到价值提炼的完整闭环。
457 93