14.1 norflash 原理

  

  在烧写进去的u-boot 中 Flash 并没有显示实际大小,意味着 norflash 没有识别。

14.1.1 norflash 硬件连接

  

NOR 的接口与内存的接口是一样的,而 NAND(数据线只有 7 条,发地址又发命令和数据等)。
NOR 可以像内存一样的来读,但不能像内存一样的去写。
NOR 的烧写要发出某些特定的命令,在某地址上写某个值就称为命令。
NOR 存放关键性的代码,如 bootload、内核或文件系统;而 NADN 有位反转的缺点,如存一些海量数据如视频监控文件等。
用 NOR 启动时,CPU 看到的“0”地址是“NOR” FLASH。若为 NAND 启动,则 CPU 看到的“0”地址是 2440 片的 4K 内存。用 NAND 启动时 CPU 完全看不到 NOR,只有用 NOR 启动时, CPU 看到的“0”地址才是 NOR。

  • 芯片启动:

    • 代码可以直接在 NOR 上运行,在 NAND 上不行。
    • CPU 可以直接从 NOR 上取到指令来运行。
    • 用 NAND 启动,2440 是有将 NAND 的前 4K 数据自动拷贝到 2440 的 4K 片内内存里,这时 CPU 再从片内 4K 内存中取指令运行。

14.1.2 norflash 命令

  

norflash 的读写共分6个周期,这里面第一横行的就是命令,比如说 reset mode 命令,意思就是在第一个周期向任意地址写入 0xF0 就可以进入复位。

读厂家ID(manifacture ID),在第一个周期向 0x555 地址写入 0xaa,在第二个周期向 0x2AA 写入 0x55,在第三个周期向  0x555 写入 0x90,第四个周期从 x00 地址读取到厂家 ID C2H

下图是芯片的厂家 ID 和设备 ID:

  

要注意 word 和 byte,word 表示是16位位宽操作,byte 表示是 8位位宽操作,位宽是寻址方式,根据原理图来确定,我们接了16根地址总线,所以是16位位宽。

  

14.1.3 norflash 规范

NOR 有两种规范, jedec 和 cfi(common flash interface)
jedec 规范,就包含了“COMMAND DEFINITIONS”中的命令,如发命令可以识别 ID,擦除芯片、擦除“扇区”或“烧写数据” 等。
老式的 NORFLASH 会支持“jedec”规范。要知道容量有多大,就要读出 ID,与数组比较。
以前老式的 NORFLASH 规范就必须读 ID 后,与这个uboot 或 内核中的 "jedec_table[]"结构数组比较,若是此数据中没有你的 NORFLASH 的信息,就得来修改此数组。

新的 NORFLASH 要支持“cfi”通用 flash 接口。就是说 NORFLASH 里面本身就带了这些属性信息(如容量、电压)。往相关地址发相关命令好可以得这些属性信息。

14.2 flash 初始化流程

14.2.1 flash 结构体

在梳理流程之前,先来看看 flash 的结构体定义:

 typedef struct {
ulong size; ///< flash 的总容量(单位是字节(byte))
ushort sector_count; ///< 扇区数量
ulong flash_id; ///< flash ID 组合了 device 和 manufacturer 编码
ulong start[CONFIG_SYS_MAX_FLASH_SECT]; ///< 虚拟扇区起始地址
uchar protect[CONFIG_SYS_MAX_FLASH_SECT]; ///< 扇区保护状态
#ifdef CONFIG_SYS_FLASH_CFI ///< 支持 CFI 模式才会定义如下的参数
uchar portwidth; ///< 端口位宽
uchar chipwidth; ///< 芯片位宽
ushort buffer_size; ///< 写入缓冲区字节数
ulong erase_blk_tout; ///< 最大块擦除超时
ulong write_tout; ///< 最大写入超时
ulong buffer_write_tout; ///< 最大缓冲区写入超时
ushort vendor; ///< 主要供应商id
ushort cmd_reset; ///< 特定于供应商的重置命令
uchar cmd_erase_sector; ///< 特定于供应商的扇区擦除命令
ushort interface; ///< 用于 x8/x16 适配
ushort legacy_unlock; ///< 支持Intel 旧式锁定或解锁
ushort manufacturer_id; ///< 厂家 ID
ushort device_id; ///< 设备 ID
ushort device_id2; ///< 扩展的 设备 ID
ushort ext_addr; ///< 扩展的查询表地址
ushort cfi_version; ///< cfi 版本
ushort cfi_offset; ///< cfi查询的偏移量
ulong addr_unlock1; ///< 解锁 AMD 闪存 ROM 的地址 1
ulong addr_unlock2; ///< 解锁 AMD 闪存 ROM 的地址 2
const char *name; ///< 可读名称
#endif
#ifdef CONFIG_MTD /** 支持磁盘才会用到 */
struct mtd_info *mtd;
#endif
} flash_info_t;

14.2.2 总的流程

通过搜索关键字 " flash " 可以知道打印信息在 initr_flash 函数中,此函数位于重定向之后的初始化函数内。看看这个函数主要做了些什么:

 static int initr_flash(void)
{
ulong flash_size = ; ///< 定义存储 flash 大小的变量
bd_t *bd = gd->bd; ///< 定义板信息结构体 puts("Flash: "); ///< 输出字符串 Flash:

if (board_flash_wp_on()) ///< __weak 开头的函数, 没有相应的复写函数, 直接返回 0
printf("Uninitialized - Write Protect On\n");
else
flash_size = flash_init(); ///< flash 初始化

print_size(flash_size, ""); ///< 打印 flash 的大小

/** 进行 flash 校验, 未定义宏 CONFIG_SYS_FLASH_CHECKSUM */
#ifdef CONFIG_SYS_FLASH_CHECKSUM
/*
* Compute and print flash CRC if flashchecksum is set to 'y'
*
* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
*/
if (getenv_yesno("flashchecksum") == )
{
printf(" CRC: %08X", crc32(, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size));
}
#endif /* CONFIG_SYS_FLASH_CHECKSUM */
putc('\n'); /* update start of FLASH memory, 更新 flash 内存的起始地址 */
#ifdef CONFIG_SYS_FLASH_BASE
bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; ///< bd->bi_flashstart = 0 设定板的 flash 起始地址
#endif
/* size of FLASH memory (final value) */
bd->bi_flashsize = flash_size; ///< 板上的 flash 的大小 /** 更新 flash 大小, 未定义宏 CONFIG_SYS_UPDATE_FLASH_SIZE */
#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
/* Make a update of the Memctrl. */
update_flash_size(flash_size);
#endif #if defined(CONFIG_OXC) || defined(CONFIG_RMU)
/* flash mapped at end of memory map */
bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
/** 执行此处的代码, 监视器预留区 */
bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
#endif
return ;
}

  这个函数总体就是初始化 flash,并将 flash 信息记录到全局结构体 gd->bd 中,bd 记录了开发板的所有硬件基本信息。

  红色字体部分代码已经很明显的显示了打印过程。

  首先是,flash_init 初始化flash ,然后调用 print_size 打印处 flash 的大小。flash_init 函数执行完后,会返回 flash_size 变量,即为 flash 的大小。

14.2.3 flash_init

  在来看看这个函数里面做了什么,此函数在 \drivers\mtd\cfi_flash.c 中:

 unsigned long flash_init(void)
{
unsigned long size = ;
int i; /** S3C2440 未配置,不执行 */
#ifdef CONFIG_SYS_FLASH_PROTECTION
/* read environment from EEPROM */
char s[];
getenv_f("unlock", s, sizeof(s));
#endif /* 用于驱动模型的,未配置 */
#ifdef CONFIG_CFI_FLASH
cfi_flash_init_dm();
#endif /* Init: no FLASHes known, CONFIG_SYS_MAX_FLASH_BANKS = 1, include/configs/jz2440.h中有定义,为 1 */
for(i = ; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i)
{
/** flash_id 设置为 未知 */
flash_info[i].flash_id = FLASH_UNKNOWN;

/* Optionally write flash configuration register */
/** 这里是 driver model 的初始化,无关代码 */
cfi_flash_set_config_reg(cfi_flash_bank_addr(i), cfi_flash_config_reg(i)); /** 检测 flash, flash_detect_legacy 是旧的检测策略 */
if(!flash_detect_legacy(cfi_flash_bank_addr(i), i))
flash_get_size(cfi_flash_bank_addr(i), i);

/** flash_info[i].size 这个值在上面那一步中被更改 */
size += flash_info[i].size;
if(flash_info[i].flash_id == FLASH_UNKNOWN)
{
#ifndef CONFIG_SYS_FLASH_QUIET_TEST
printf ("## Unknown flash on Bank %d - Size = 0x%08lx = %ld MB\n", i + , flash_info[i].size, flash_info[i].size >> );
#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
}
/** 不执行 */
#ifdef CONFIG_SYS_FLASH_PROTECTION
else if (strcmp(s, "yes") == )
{
/*
* Only the U-Boot image and it's environment is protected, all other sectors are unprotected (unlocked)
* if flash hardware protection is used (CONFIG_SYS_FLASH_PROTECTION) and
* the environment variable "unlock" is set to "yes".
*/
if (flash_info[i].legacy_unlock)
{
int k; /* Disable legacy_unlock temporarily, since flash_real_protect would relock all other sectors again otherwise. */
flash_info[i].legacy_unlock = ; /* Legacy unlocking (e.g. Intel J3) -> unlock only one sector. This will unlock all sectors. */
flash_real_protect (&flash_info[i], , ); flash_info[i].legacy_unlock = ; /* Manually mark other sectors as unlocked (unprotected) */
for (k = ; k < flash_info[i].sector_count; k++)
flash_info[i].protect[k] = ;
}
else
{
/* No legancy unlocking -> unlock all sectors */
flash_protect (FLAG_PROTECT_CLEAR,
flash_info[i].start[],
flash_info[i].start[] + flash_info[i].size - ,
&flash_info[i]);
}
}
#endif /* CONFIG_SYS_FLASH_PROTECTION */
} /** flash 对数据的一些保护操作 */
flash_protect_default();
#ifdef CONFIG_FLASH_CFI_MTD
cfi_mtd_init();
#endif return (size);
}

  分析到当前,已经可以看见一些端倪了,size 变量是在 检测到 flash 之后,才有正确的值,当前我们无法保证是否检测到了 flash。

14.2.4 flash_detect_legacy

  源码位置:Cfi_flash.c (drivers\mtd)

 static int flash_detect_legacy(phys_addr_t base, int banknum)
{
/** 全局的flash_info 与 局部 info 地址相同 */
flash_info_t *info = &flash_info[banknum]; /** flash 的赢编码设置:
portwidth = FLASH_CFI_16BIT
chipwidth = FLASH_CFI_BY16
interface = FLASH_CFI_X16 */
if (board_flash_get_legacy(base, banknum, info))
{
/* board code may have filled info completely. If not, we use JEDEC ID probing.
* info->vendor_id = 0 执行 if 语句里面代码
*/
if (!info->vendor)
{
int modes[] = {CFI_CMDSET_AMD_STANDARD, CFI_CMDSET_INTEL_STANDARD};
int i; for (i = ; i < ARRAY_SIZE(modes); i++)
{
info->vendor = modes[i];
/** 这里直接将 base 给返回了 */
info->start[] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE); if (info->portwidth == FLASH_CFI_8BIT && info->interface == FLASH_CFI_X8X16)
{
info->addr_unlock1 = 0x2AAA;
info->addr_unlock2 = 0x5555;
}
else
{
/** 根据上面的赋值,可知道执行这里,对 flash 进行解锁命令需要发送的地址 */
info->addr_unlock1 = 0x5555;
info->addr_unlock2 = 0x2AAA;
} /** 读取 jedec 规范的 flash 表,这里就是发送命令到 flash 中获取 flash 的信息进行匹配 */
flash_read_jedec_ids(info);
debug("JEDEC PROBE: ID %x %x %x\n", info->manufacturer_id, info->device_id, info->device_id2);
/** 匹配 jedec_table 表,查找相应型号的 flash*/
if (jedec_flash_match(info, info->start[]))
break;
else
unmap_physmem((void *)info->start[], info->portwidth);
}
} /** 根据 vendor 设置复位要发送的命令数据 */
switch(info->vendor)
{
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
info->cmd_reset = FLASH_CMD_RESET;
break;
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
case CFI_CMDSET_AMD_LEGACY:
info->cmd_reset = AMD_CMD_RESET;
break;
}
info->flash_id = FLASH_MAN_CFI;
return ;
}
return ; /* use CFI */
}

十三、u-boot 调试-- NOR FLASH 支持的更多相关文章

  1. Spring Boot中的缓存支持(一)注解配置与EhCache使用

    Spring Boot中的缓存支持(一)注解配置与EhCache使用 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决 ...

  2. Spring Boot项目如何同时支持HTTP和HTTPS协议

    如今,企业级应用程序的常见场景是同时支持HTTP和HTTPS两种协议,这篇文章考虑如何让Spring Boot应用程序同时支持HTTP和HTTPS两种协议. 准备 为了使用HTTPS连接器,需要生成一 ...

  3. java-cef系列视频第三集:添加flash支持

    上一集我们介绍了如何搭建java-cef调试环境. 本视频介绍如何给java-cef客户端添加flashplayer支持 第四集视频我们将介绍java-cef中的自定义协议. 本作品采用知识共享署名- ...

  4. Hi3531添加16GByte(128Gbit) NAND Flash支持

    0.板子上已有Nor Flash了,添加的Nand Flash型号为MT29F128G08CJABAWP,进系统挂接NAND作为一个分区 1.修改uboot u-boot-2010.06/driver ...

  5. Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

    概要 之前的两篇文章,讲述了Spring Security 结合 OAuth2 .JWT 的使用,这一节要求对 OAuth2.JWT 有了解,若不清楚,先移步到下面两篇提前了解下. Spring Bo ...

  6. nova boot添加volume_type参数支持

    早前由于添加了全SSD的高性能Ceph集群,区别于现有的HDD集群,在OpenStack端需要能够选择使用两种集群.Cinder配置多Ceph后端的文档早已整理,整理文件夹时发现这篇为nova boo ...

  7. Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  8. spring boot 加入mail邮件支持

    一.添加依赖 <!-- 邮件整合 --> <dependency> <groupId>org.springframework.boot</groupId> ...

  9. Spring boot之添加JSP支持

    大纲 (1) 创建Maven web project: (2) 在pom.xml文件添加依赖 (3) 配置application.properties支持jsp (4) 编写测试Controller ...

随机推荐

  1. [ZJOI2016]大森林(LCT)

    题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...

  2. [Vani有约会]雨天的尾巴(树上差分+线段树合并)

    首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所有的救济粮 ...

  3. 牛客练习赛43 Tachibana Kanade Loves Review C(最小生成树Kruskal)

    链接:https://ac.nowcoder.com/acm/contest/548/C来源:牛客网 题目描述 立华奏是一个刚刚开始学习 OI 的萌新. 最近,实力强大的 QingyuQingyu 当 ...

  4. SFTP多文件上传,删除

    公司项目中需要把项目的相关文件上传到服务器的tomcat中,需要在项目中进行以下几步操作: 1.添加项目信息,包括名称,描述,服务器ip,sftp的用户名,密码,端口号等,存在配置,部署,删除等操作 ...

  5. 浅析 @PathVariable 和 @RequestParam(转发,非原创)

    首先 上两个地址:地址①http://localhost:8989/SSSP/emps?pageNo=2地址②http://localhost:8989/SSSP/emp/7如果想获取地址①中的 pa ...

  6. agc031

    T1 题意:给你一个串,求所有子序列个数,满足没有相同字符.1e5,2s. 解:考虑一个合法的子序列.其中每个字母的出现位置都有(出现次数)种选择.还可以不选,要 + 1. 然后乘起来就做完了.如果变 ...

  7. [luogu1970][花匠]

    题目地址 https://www.luogu.org/problemnew/show/P1970 题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定 把这排中的一部 ...

  8. MVC之 自定义过滤器(ActionFilterAttribute)

    一.自定义Filter 自定义Filter需要继承ActionFilterAttribute抽象类,重写其中需要的方法,来看下ActionFilterAttribute类的方法签名. //表示所有操作 ...

  9. 被addPropertyChangeListener("...",this)差点搞崩溃

    以前常用的是addPropertyChangeListener(this)方法 记得有一天我发现还有另一种写法: addPropertyChangeListener(String propertyNa ...

  10. 2019阿里校招测评题,光明小学完全图最短路径问题(python实现)

    题目:光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?光明小学可以抽象成一张有N个节点的图,每两点间都有一条道路相连.光 ...