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. luogu1983 车站分级 (拓扑排序)

    对每趟车建一个虚点p,对于不停车的x,连边(x,p,1):对于停车的y,连边(p,y,0)有一条边(a,b,l)就是说b-a>=l由于题目保证一定能走,直接拓扑序dp算最大的就行了 #inclu ...

  2. 【php】php位运算及其高级应用

    我们之前学过逻辑与(&&)      条件1 && 条件2 当两边条件同时成立时候返回1 逻辑或(||)         条件1 || 条件2    当两边条件只要有一 ...

  3. centos7安装较高版本python3.5/3.6

    应用环境: Centos7或者RHEL7下默认安装的python版本为2.7.x,更新不够及时,现在很多时候需要额外安装较高版本的python环境, 网上搜罗一圈总结记录一下常用两种方式: ① 源码编 ...

  4. 2019 校内赛 RPG的地牢猎手(bfs+优先队列)

    Problem Description Luke最近沉迷一款RPG游戏,游戏中角色可以进入地牢关卡,只要顺利走出地牢就可以获得奖励.地牢表示为n行m列的块矩阵,其中每个块只可以是障碍块.入口.出口或数 ...

  5. 分页技术 -servlet

    一.思路: 定义四个分页变量. pagenow 表示第几页,该变量由用户决定的,是变化的. pageSize 每页显示几条记录,由程序定义,也可以由程序定制. pageCount 表示共有多少页,(该 ...

  6. Nginx简易编译安装

    1.下载Nginx: http://nginx.org/download/nginx-1.6.3.tar.gz 2.安装Pcre.Zlib.Openssl等相关组件: [root@track ngin ...

  7. css 选择其父元素下的某个元素

    一,选择器 :first-child   p:first-child(first第一个 child子元素)(找第一个子元素为p) :last-child    p:last-child(last倒数 ...

  8. Arch Linux下韩文重叠显示

    解决方法 sudo pacman -S wqy-microhei-kr-patched

  9. python 当前时间获取方法

    1.先导入库:import datetime 2.获取当前日期和时间:now_time = datetime.datetime.now() 3.格式化成我们想要的日期:strftime() 比如:“2 ...

  10. Java实现二叉树的前序、中序、后序、层序遍历(递归方法)

      在数据结构中,二叉树是树中我们见得最多的,二叉查找树可以加速我们查找的效率,那么输出一个二叉树也变得尤为重要了.   二叉树的遍历方法分为四种,分别为前序遍历.中序遍历.后序.层序遍历.下图即为一 ...