Nandflash的驱动加载
发布时间:2020-12-15 17:43:33 所属栏目:百科 来源:网络整理
导读:分析at91sam9260ek的代码示范。 (1)板级初始化。 Board-sam9260ek.c中的初始化调用: static void __init ek_board_init(void){。。。代码略/* NAND */ek_add_device_nand();。。。代码略} ek_add_device_nand() 的代码: /* * NAND flash */static struct
分析at91sam9260ek的代码示范。 (1)板级初始化。 Board-sam9260ek.c中的初始化调用: static void __init ek_board_init(void) { 。。。代码略 /* NAND */ ek_add_device_nand(); 。。。代码略 } ek_add_device_nand()的代码: /* * NAND flash */ static struct mtd_partition __initdata ek_nand_partition[] = { //flash中的分区信息 { .name = "Partition 1",.offset = 0,.size = SZ_256K,},{ .name = "Partition 2",.offset = MTDPART_OFS_NXTBLK,.size = MTDPART_SIZ_FULL,}; //得到Nandflash分区 static struct mtd_partition * __init nand_partitions(int size,int *num_partitions) { *num_partitions = ARRAY_SIZE(ek_nand_partition); return ek_nand_partition; } //Nandflash使用的私有数据类型atmel_nand_data static struct atmel_nand_data __initdata ek_nand_data = { .ale = 21,.cle = 22,// .det_pin = ... not connected .rdy_pin = AT91_PIN_PC13,.enable_pin = AT91_PIN_PC14,.partition_info = nand_partitions,//得到Nandflash分区 #if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) .bus_width_16 = 1,//总线宽度 #else .bus_width_16 = 0,#endif }; //SMC配置 static struct sam9_smc_config __initdata ek_nand_smc_config = { .ncs_read_setup = 0,.nrd_setup = 1,.ncs_write_setup = 0,.nwe_setup = 1,.ncs_read_pulse = 3,.nrd_pulse = 3,.ncs_write_pulse = 3,.nwe_pulse = 3,.read_cycle = 5,.write_cycle = 5,.mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,.tdf_cycles = 2,}; static void __init ek_add_device_nand(void) { /* setup bus-width (8 or 16) */ if (ek_nand_data.bus_width_16) ek_nand_smc_config.mode |= AT91_SMC_DBW_16; else ek_nand_smc_config.mode |= AT91_SMC_DBW_8; /* configure chip-select 3 (NAND) */ sam9_smc_configure(3,&ek_nand_smc_config); at91_add_device_nand(&ek_nand_data); //跳到At91sam9260_devices.c中执行 } At91sam9260_devices.c中的代码: static struct atmel_nand_data nand_data; #define NAND_BASE AT91_CHIPSELECT_3 static struct resource nand_resources[] = { [0] = { .start = NAND_BASE,.end = NAND_BASE + SZ_256M - 1,.flags = IORESOURCE_MEM,[1] = { .start = AT91_BASE_SYS + AT91_ECC,.end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,} }; static struct platform_device at91sam9260_nand_device = { .name = "atmel_nand",.id = -1,.dev = { .platform_data = &nand_data,.resource = nand_resources,.num_resources = ARRAY_SIZE(nand_resources),}; void __init at91_add_device_nand(struct atmel_nand_data *data) { unsigned long csa; if (!data) return; csa = at91_sys_read(AT91_MATRIX_EBICSA); at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA); /* enable pin */ if (data->enable_pin) at91_set_gpio_output(data->enable_pin,1); /* ready/busy pin */ if (data->rdy_pin) at91_set_gpio_input(data->rdy_pin,1); /* card detect pin */ if (data->det_pin) at91_set_gpio_input(data->det_pin,1); nand_data = *data; platform_device_register(&at91sam9260_nand_device); } (2)驱动初始化 //驱动私有数据结构 struct atmel_nand_host { struct nand_chip nand_chip; //Nandflash与mtd的接口 struct mtd_info mtd; //主分区的mtd_info,创建分区使用 void __iomem *io_base; //虚拟地址 struct atmel_nand_data *board; //板级私有数据 struct device *dev; void __iomem *ecc; //ecc的虚拟地址 }; static int __init atmel_nand_probe(struct platform_device *pdev) { struct atmel_nand_host *host; struct mtd_info *mtd; struct nand_chip *nand_chip; struct resource *regs; struct resource *mem; . . . //为驱动私有数据分配空间并清0 host = kzalloc(sizeof(struct atmel_nand_host),GFP_KERNEL); . . . mtd = &host->mtd; nand_chip = &host->nand_chip; host->board = pdev->dev.platform_data; //板级私有数据 host->dev = &pdev->dev; //dev nand_chip->priv = host; /* link the private data structures */ mtd->priv = nand_chip; //链接nand_chip到mtd mtd->owner = THIS_MODULE; /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; //读地址 nand_chip->IO_ADDR_W = host->io_base; //写地址 nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; //上面这个是写命令或写地址接口 if (host->board->rdy_pin) nand_chip->dev_ready = atmel_nand_device_ready; //ECC的初始化代码,略 //从数据手册获取命令延迟时间 nand_chip->chip_delay = 20; /* 20us command delay time */ if (host->board->bus_width_16) { /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; nand_chip->read_buf = atmel_read_buf16; nand_chip->write_buf = atmel_write_buf16; } else { nand_chip->read_buf = atmel_read_buf; nand_chip->write_buf = atmel_write_buf; } platform_set_drvdata(pdev,host); //设置数据到pdev atmel_nand_enable(host); . . . /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd,1)) { res = -ENXIO; goto err_scan_ident; } //根据扫描得到的flash页大小初始化ECC硬件,代码略 /* second phase scan */ if (nand_scan_tail(mtd)) { res = -ENXIO; goto err_scan_tail; } #ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "atmel_nand"; num_partitions = parse_mtd_partitions(mtd,part_probes,//提取flash中的分区信息 &partitions,0); #endif //如果提取flash中的分区信息不存在,则读取板级初始化设定的分区信息 if (num_partitions <= 0 && host->board->partition_info) partitions = host->board->partition_info(mtd->size,&num_partitions); res = add_mtd_partitions(mtd,partitions,num_partitions); #else res = add_mtd_device(mtd); //只有一个主分区的情况,不支持分区表 #endif if (!res) return res; . . .略 }
nand_chip->cmd_ctrl是写命令或写地址接口,它可以是下面三个值: #define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) #define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) #define NAND_CTRL_CHANGE 0x80
(3)?ECC的配置 ECC的状态: /* * Constants for ECC_MODES */ typedef enum { NAND_ECC_NONE,NAND_ECC_SOFT,NAND_ECC_HW,NAND_ECC_HW_SYNDROME,} nand_ecc_modes_t; 如果是软件ECC: nand_chip->ecc.mode = NAND_ECC_SOFT; nand_chip->ecc.mode = NAND_ECC_SOFT; nand_chip->ecc.calculate = NULL; nand_chip->ecc.correct = NULL; nand_chip->ecc.hwctl = NULL; nand_chip->ecc.read_page = NULL; nand_chip->ecc.postpad = 0; nand_chip->ecc.prepad = 0; nand_chip->ecc.bytes = 0;
如果是硬件ECC: nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.calculate = atmel_nand_calculate; //计算ECC nand_chip->ecc.correct = atmel_nand_correct; //读完一页数据后判断ECC是否正确 nand_chip->ecc.hwctl = atmel_nand_hwctl; //硬件控制函数,大部分CPU不用支持 nand_chip->ecc.read_page = atmel_nand_read_page; //有硬件ECC的情况下读一个页数据的接口 nand_chip->ecc.bytes = 4; nand_chip->ecc.layout是一个结构: struct nand_oobfree { __u32 offset; __u32 length; }; #define MTD_MAX_OOBFREE_ENTRIES 8 /* * ECC layout control structure. Exported to userspace for * diagnosis and to allow creation of raw images */ struct nand_ecclayout { __u32 eccbytes; //ECC的大小(字节) __u32 eccpos[64]; //ECC所在的字节位置 __u32 oobavail; struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; //OOB可用的数据空间 }; 例子: /* oob layout for large page size * bad block info is on bytes 0 and 1 * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ static struct nand_ecclayout atmel_oobinfo_large = { .eccbytes = 4,.eccpos = {60,61,62,63},.oobfree = { {2,58} },}; /* oob layout for small page size * bad block info is on bytes 4 and 5 * the bytes have to be consecutives to avoid * several NAND_CMD_RNDOUT during read */ static struct nand_ecclayout atmel_oobinfo_small = { .eccbytes = 4,.eccpos = {0,1,2,3},.oobfree = { {6,10} },}; ? 总结: NAND Flash的加载过程中,定义了一个结构atmel_nand_host,它的成员包含了nand_chip和mtd_info结构。nand_chip->priv指向atmel_nand_host结构,mtd_info->priv指向nand_chip结构。Nand_base.c中的nand_scan_ident函数完成NAND Flash探测的大部分工作。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |