uClinux2.6(bf561)的NorFlash驱动实现分析(1): 基本参数

本文详细介绍了在uClinux环境下NorFlash的配置过程及原理,包括如何通过代码实现NorFlash的基本参数设置、位扩展机制的理解及命令发送与响应读取的处理方式。
 
   
下文开发环境为:AM29LV320MT(4M,16位),uclinux-2.6,VDSP4.5,bf561
在uClinux启动时可以看到类似的提示:
BF561 EZKIT Map: Found 1 x16 devices at 0x0 in 16-bit bank
它的输出是由:
       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank/n",
              map->name, cfi->interleave, cfi->device_type*8, base,
              map->bankwidth*8);
进行控制的。这行信息揭示了NorFlash的一些基本参数:
l         map->bankwidth:MTD设备的接口总线宽度,其值可以为1,2或4。
l         cfi->interleave:交错数,几块芯片平行连接成一块芯片,使bankwidth变大。
l         cfi->device_type:单个芯片的总线宽度,其值为1、2或4。
l         device_addr:nor flash设备的总线地址(寻址)范围视具体芯片以及其采用的位宽而定。
对于位扩展来讲:bankwidth=device_type*interleave
如富士通的29LV650:其容量是8Mbyte,共128个sector,每个sector的大小是64 kbyte。如果选择位宽为x8,设备总线的每个地址代表了一个byte的存储单元,其总线地址范围为8M(0x000000~0x7fffff)。如果选择位宽为x16,设备总线的每个地址代表了两个byte的存储单元,固其总线地址范围为4M(0x000000~0x3fffff)。
再如intel的E29F128:其容量为16Mbyte,共128个sector,每个sector的大小是128Kbyte。如果选择位宽为x8,设备总线的每个地址代表了一个byte的存储单元,其总线地址范围为16M(0x000000~0xffffff)。如果选择位宽为x16,这时候设备的A0脚不可用,所以不能访问到奇地址的存储单元,而只能0、2、4...地址的来访问,其总线地址范围为8M(0x000000~0xffffff的偶地址)。
在uClinux进行芯片检测时就充分考虑了各种可能的接线方式:
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
                   struct cfi_private *cfi)
{
     int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
     int max_chips = map_bankwidth(map); /* And minimum 1 */
     int nr_chips, type;
 
     for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
 
         if (!cfi_interleave_supported(nr_chips))
             continue;
 
         cfi->interleave = nr_chips;
 
         /* Minimum device size. Don't look for one 8-bit device
            in a 16-bit bus, etc.
            每个芯片的位宽 = (总线宽度 / 芯片数量)。
*/
         type = map_bankwidth(map) / nr_chips;
        
         for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
              cfi->device_type = type;
 
              if (cp->probe_chip(map, 0, NULL, cfi))
                   return 1;
         }
     }
     return 0;
}
在向norflash发送命令并读取flash的响应结果时则考虑到设备地址的问题:
 
/*
 * Returns the command address according to the given geometry.
 */
static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type)
{
     return (cmd_ofs * type) * interleave;
}
 
/*
 * Transforms the CFI command for the given geometry (bus width & interleave).
*/
map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
{
     map_word val = { {0} };
     int wordwidth, words_per_bus, chip_mode, chips_per_word;
     unsigned long onecmd;
     int i;
 
     /* We do it this way to give the compiler a fighting chance
        of optimising away all the crap for 'bankwidth' larger than
        an unsigned long, in the common case where that support is
        disabled */
     if (map_bankwidth_is_large(map)) {
         wordwidth = sizeof(unsigned long);
         words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
     } else {
         wordwidth = map_bankwidth(map);
         words_per_bus = 1;
     }
 
     chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
     chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
 
     /* First, determine what the bit-pattern should be for a single
        device, according to chip mode and endianness... */
     switch (chip_mode) {
     default: BUG();
     case 1:
         onecmd = cmd;
         break;
     case 2:
         onecmd = cpu_to_cfi16(cmd);
         break;
     case 4:
         onecmd = cpu_to_cfi32(cmd);
         break;
     }
 
     /* Now replicate it across the size of an unsigned long, or
        just to the bus width as appropriate */
     switch (chips_per_word) {
     default: BUG();
#if BITS_PER_LONG >= 64
     case 8:
         onecmd |= (onecmd << (chip_mode * 32));
#endif
     case 4:
         onecmd |= (onecmd << (chip_mode * 16));
     case 2:
         onecmd |= (onecmd << (chip_mode * 8));
     case 1:
         ;
     }
 
     /* And finally, for the multi-word case, replicate it
        in all words in the structure */
     for (i=0; i < words_per_bus; i++) {
         val.x[i] = onecmd;
     }
 
     return val;
}
 
/*
 * Sends a CFI command to a bank of flash for the given geometry.
 *
 * Returns the offset in flash where the command was written.
 * If prev_val is non-null, it will be set to the value at the command address,
 * before the command was written.
 */
uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
                   struct map_info *map, struct cfi_private *cfi,
                   int type, map_word *prev_val)
{
     map_word val;
     uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type);
 
     val = cfi_build_cmd(cmd, map, cfi);
 
     if (prev_val)
         *prev_val = map_read(map, addr);
 
     map_write(map, val, addr);
 
     return addr - base;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值