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. pandas to_excel

    报错:IllegalCharacterError 其原因是字段中包含了unicode字符. 解决方案: # 首先,安装python包xlsxwriter pip install xlsxwriter ...

  2. Python3 与 C# 扩展之~模块专栏

      代码裤子:https://github.com/lotapp/BaseCode/tree/maste 在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode ...

  3. VSCode and NoteBook for JavaScript | NodeJS

    VSCode调试HTML环境配置 | Jupyter NoteBook IJavaScript 配置 VSCode调试HTML环境配置 先安装两个插件:Debugger for Chrome(调试) ...

  4. 【翻译】七个习惯提高Python程序的性能

    原文链接:https://www.tutorialdocs.com/article/7-habits-to-improve-python-programs.html 掌握一些技巧,可尽量提高Pytho ...

  5. js 打开标签

    JS打开新标签的2种方式 1.超链接<a href="http://www.jb51.net" title="脚本之家">Welcome</a ...

  6. jquery 追加元素/jquery文档处理,插入、修改、移动、删除指定的DOM元素.

    jquery 追加元素 $("#content").append("..."); // 添加到元素内部最后面 $("#content").p ...

  7. 洛谷P1072 Hankson的趣味题

    这是个NOIP原题... 题意: 给定 a b c d 求 gcd(a, x) = b && lcm(c, x) = d 的x的个数. 可以发现一个朴素算法是从b到d枚举,期望得分50 ...

  8. 洛谷P1880 石子合并

    经典水题....... 断环为链长度乘二,求前缀和区间DP. #include <cstdio> #include <cstring> #include <algorit ...

  9. python enumarate方法的使用

    '''enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中.'''

  10. SpringBoot文件上传

    先建工程 只勾选web和freemarker模板 最后 先看一下最终目录结构 先修改pom文件,加入common-io依赖 然后修改Application.yml文件 spring: freemark ...