TQ2440移植u-boot2016.11全过程记录-【7】NAND FLASH方式启动U-BOOT

2023-11-16

TQ2440移植u-boot2016.11-NAND FLASH方式启动U-BOOT


S3C2440 U-BOOT启动方式说明:

         ~~~~~~~~         NOR FLASH启动: S3C2440会直接在NOR上运行程序,在NOR上中的代码需要初始化芯片时钟、初始化SDRAM。

         ~~~~~~~~         NAND FLASH启动: S3C2440上电后其内部的NAND FLASH控制器会自动把NAND FLASH中的前4K的代码拷贝到S3C2440芯片自带的RAM中,然后开始运行程序,因为片上RAM只有4K的容量,所以这部分的代码就负责初始化芯片时钟、初始化SDRAM、初始化NAND,然后将u-boot的代码拷贝到SDRAM中并跳转运行。

         ~~~~~~~~         目前主流的启动方式为NAND FLAHS或者SD卡启动,NOR FLASH用的越来越少了,上二章节已经实现了NOR FLASH的启动,本章节实现NAND FLASH的启动。


         ~~~~~~~~         u-boot在编译时候开启了-pie选项,该选项的作用是编译出来的程序是位置无关的,什么意思呢,就像是动态库库一样,代码每次启动可以自由加载到内存的任意合适位置执行。如果我们开启了该功能,那么NAND前4K的代码中有一些变量等代码就可能不在这4K中,而是在一些特殊的段或者位置处,这样的话S3C2440上电自动拷贝NAND前4K的内容并运行就会出错,解决该办法的方式有两种:

  1. 修改u-boot执行的主流程,取消掉uboot重定位,在4K代码中实现复制代码到内存的操作。
  2. 设置为SPL启动,SPL启动简单的说就是编译u-boot的时候会生成u-boot.bin和u-boot-spl.bin文件,通过宏CONFIG_SPL_BUILD控制是编译u-boot.bin还是u-boot-spl.bin,spl代码只是对时钟的初始化、SDRAM初始化、NAND初始化并将u-boot从NAND中拷贝到内存并跳转运行的操作,所以这段代码肯定是小于4K的。

本例程使用SPL方式进行引导uboot。

(一)修改配置头文件:

gedit include/configs/tq2440.h

1、由于SPL的代码已经初始化了内存,所以SPL将uboot拷贝到内存并运行后,不需要再次初始化内存了,将宏CONFIG_SKIP_LOWLEVEL_INIT的编译条件由CONFIG_SPL_BUILD控制,改为如下代码:

/* 该宏是在文件arch/arm/cpu/arm920t/start.S中跳过SDRAM初始化代码 */
#ifndef CONFIG_SPL_BUILD
#define CONFIG_SKIP_LOWLEVEL_INIT
#endif

2、修改链接地址也由宏CONFIG_SPL_BUILD控制,如果是SPL那么链接到0地址处,如果是uboot那么链接到内存0x30008000地址处,将宏CONFIG_SYS_TEXT_BASE改为:

#ifdef CONFIG_SPL_BUILD
#define CONFIG_SYS_TEXT_BASE	0
#else
#define CONFIG_SYS_TEXT_BASE	0x30008000
#endif

在这里插入图片描述

(二)添加SPL编译项

gedit arch/arm/Kconfig

找到config TARGET_TQ2440的配置项,在该配置项结尾加入一行:select SUPPORT_SPL,效果:
在这里插入图片描述

(三)添加拷贝u-boot到内存的代码

新建一个init.c文件:

gedit board/samsung/tq2440/init.c

粘贴进如下代码:

/*
 * init.c
 *
 *  Created on: 2020/03/28
 *      Author: AnKun
 */

#define NFCONF (*(volatile unsigned int *)0x4E000000)
#define NFCONT (*(volatile unsigned int *)0x4E000004)
#define NFCMD  (*(volatile unsigned char *)0x4E000008)
#define NFADDR (*(volatile unsigned char *)0x4E00000C)
#define NFDATA (*(volatile unsigned char *)0x4E000010)
#define NFSTAT (*(volatile unsigned char *)0x4E000020)

#define GPBCON (*(volatile unsigned int *)0x56000010)
#define GPBDAT (*(volatile unsigned int *)0x56000014)
#define GPBUP  (*(volatile unsigned int *)0x56000018)

#define tq2440_nand_select()    do{NFCONT &= ~(1 << 1);}while(0);
#define tq2440_nand_deselect()  do{NFCONT |= 1 << 1;}while(0);

static int is_boot_from_nor_flash(void)
{
	int tmp = 0;
	volatile int* p = (volatile int *)0;

	tmp = *p;
	*p = 0xAAAAAAAA;

	if (*p == 0xAAAAAAAA)   /* boot from nand */
	{
		*p = tmp;
		return 0;
	}
	else                    /* boot from nor */
	{
		return 1;
	}
}

void tq2440_nand_init(void)
{
#define TACLS   0
#define TWRPH0  1
#define TWRPH1  0

	NFCONF = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4);
	NFCONT = (1 << 4) | (1 << 1) | (1 << 0);
}

void tq2440_nand_delay(void)
{
	int delay = 0;
	for (delay = 0; delay < 10; delay++);
}

void tq2440_nand_write_cmd(unsigned char cmd)
{
	NFCMD = cmd;
	tq2440_nand_delay();
}

void tq2440_nand_write_addr(unsigned int addr)
{
	unsigned int col  = addr % 2048;
	unsigned int page = addr / 2048;

	NFADDR = col & 0xFF;
	tq2440_nand_delay();

	NFADDR = (col >> 8) & 0xFF;
	tq2440_nand_delay();

	NFADDR = page & 0xFF;
	tq2440_nand_delay();

	NFADDR = (page >> 8) & 0xFF;
	tq2440_nand_delay();

	NFADDR = (page >> 16) & 0xFF;
	tq2440_nand_delay();
}

void tq2440_nand_wait_ready(void)
{
	while (!(NFSTAT & 0x1)) {};
}

void tq2440_nand_read(unsigned int addr, void* buf, unsigned int len)
{
	int i = 0;
	int col = addr % 2048;
	unsigned char* p = (unsigned char *)buf;
	tq2440_nand_select();

	while (i < len)
	{
		tq2440_nand_write_cmd(0x00);
		tq2440_nand_write_addr(addr);
		tq2440_nand_write_cmd(0x30);
		tq2440_nand_wait_ready();
		for (; (col < 2048) && (i < len); col++)
		{
			*p++ = (NFDATA & 0xFF);
			i++;
			addr++;
		}
		col = 0;
	}
	tq2440_nand_deselect();
}

int mymemcmp(const void* addr1, const void* addr2, unsigned int len)
{
	char* p1 = (char *)addr1;
	char* p2 = (char *)addr2;

	while (len--)
	{
		if (*p1 != *p2)
			return 1;
		p1++;
		p2++;
	}
	return 0;
}

#define TQ2440_UBOOT_COPYTO  0x30008000    /* 拷贝到内存中的地址,此值与CONFIG_SYS_TEXT_BASE一致 */
#define TQ2440_UBOOT_OFFSET  0x20000       /* u-boot在NAND中的偏移地址(NAND中的前128K存放的是u-boot-spl.bin) */
#define TQ2440_UBOOT_SIZE    0xE0000       /* u-boot的大小896K,多拷贝点没关系 */

void copy_uboot_to_sdram(void)
{
	void (*jump)(void) = (void *)TQ2440_UBOOT_COPYTO;

	GPBDAT &= ~(1 << 5);

	if (is_boot_from_nor_flash())
	{
		int len = TQ2440_UBOOT_SIZE;
		char* s = (char *)TQ2440_UBOOT_OFFSET;
		char* d = (char *)TQ2440_UBOOT_COPYTO;
		GPBDAT &= ~(1 << 6);
		while (len--)    *d++ = *s++;
		GPBDAT &= ~(1 << 7);
		GPBDAT &= ~(1 << 8);
	}
	else
	{
		tq2440_nand_init();
		GPBDAT &= ~(1 << 6);
		tq2440_nand_read(TQ2440_UBOOT_OFFSET, (void *)TQ2440_UBOOT_COPYTO, TQ2440_UBOOT_SIZE);
		GPBDAT &= ~(1 << 7);
		GPBDAT &= ~(1 << 8);
	}

	jump();
}

void tq2440_led_init(void)
{
	GPBCON = 0x002956A9;
	GPBUP  = 0x000007FF;
	GPBDAT = 0x000001E0;  /* led off */
}

void clsbss(void)
{
	extern int __bss_start;
	extern int __bss_end;
	int* p = &__bss_start;
	while (p < &__bss_end)    *p++ = 0;
}

void tq2440_board_init_f(void)
{
	clsbss();
	tq2440_led_init();
	copy_uboot_to_sdram();
}


(四)修改汇编启动文件crt0.S:

gedit arch/arm/lib/crt0.S

找到:

	mov	r0, #0
	bl	board_init_f

替换为:

#ifndef CONFIG_SPL_BUILD
	mov	r0, #0
	bl	board_init_f
#else
	bl tq2440_board_init_f
#endif

(五)将init.c添加进编译项:

gedit board/samsung/tq2440/Makefile

添加一行:

obj-$(CONFIG_SPL_BUILD) += init.o

(六)编译
1、首先make一下编译出u-boot.bin
2、然后打开SPL的编译项:

  • make menuconfig ---> SPL / TPL ---> 选中
    在这里插入图片描述 在这里插入图片描述
    保存退出后,make一下,在spl目录下就编译出了u-boot-spl.bin文件。

将u-boot-spl.bin烧写到NAND中的0地址处,将u-boot.bin烧写到NAND的128K地址处,TQ2440开发板拨到NAND启动,重新上电即可成功启动。

注意:NAND启动无法识别NOR FLASH,此处问题先保留,回头解决。


【附加】:分别烧写u-boot-spl.bin和u-boot.bin很麻烦,所以我写了个小程序将这两个文件合并为一个文件。新建文件ubootmeger.c文件,粘贴进如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

uint8_t buffer[0x200000];

#define UBOOT_SPL_SIZE (128*1024)

int main(int argc, char* argv[])
{
	int nread  = 0;
	int nwrite = 0;
	FILE* fp1;
	FILE* fp2;
	FILE* fp3;

	if(argc < 3)
	{
		printf("\r\nUsage:\r\n\tubootmerge [u-boot-spl.bin] [u-boot.bin] [output filename]\r\n");
		printf("e.g.\r\n\tubootmerge u-boot-spl.bin u-boot.bin tq2440-uboot-2016.11.bin\r\n");
		return 0;
	}

	fp1 = fopen(argv[1], "rb");
	fp2 = fopen(argv[2], "rb");
	fp3 = fopen(argv[3], "wb+");
	if(!fp1 || !fp2 || !fp1)
	{
		fprintf(stderr, "Can not open file, please again!\r\n");
		goto __exit;
	}

	memset(buffer, 0xFF, sizeof(buffer));

	nread = fread(buffer, 1, UBOOT_SPL_SIZE, fp1);
	if(nread < 0)
	{
		fprintf(stderr, "Can not read file %s, please again!\r\n", argv[1]);
		goto __exit;
	}
	nwrite += UBOOT_SPL_SIZE;

	nread = fread(buffer + nwrite, 1, 0x100000, fp2);
	if(nread < 0)
	{
		fprintf(stderr, "Can not read file %s, please again!\r\n", argv[2]);
		goto __exit;
	}

	nwrite += nread;
	if(fwrite(buffer, 1, nwrite, fp3) != nwrite)
	{
		fprintf(stderr, "Can not write file %s, please again!\r\n", argv[3]);
		goto __exit;
	}

	printf("---==> done !\r\n");
	goto __exit;

__exit:
	fclose(fp1);
	fclose(fp2);
	fclose(fp3);
	return 0;
}

使用gcc编译一下即可:

gcc -o ubootmeger ubootmeger.c

使用方法:ubootmeger接收三个参数,第一个参数为spl文件名,第二个参数为uboot的文件名,第三个参数为合并新uboot的文件名,例:
./ubootmeger u-boot-spl.bin u-boot.bin tq2440-u-boot-v201611.bin

文件tq2440-u-boot-v201611.bin即为最终版的u-boot,将该u-boot烧写进nor或者nand中0地址处即可。


ends…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TQ2440移植u-boot2016.11全过程记录-【7】NAND FLASH方式启动U-BOOT 的相关文章

随机推荐

  • Nginx配置https的wordpress站点,wp-content目录下资源404解决方案

    Nginx配置https的wordpress站点 wp content目录下资源404解决方案 参考文章 1 Nginx配置https的wordpress站点 wp content目录下资源404解决方案 2 https www cnblo
  • pandas DataFrame数据的合并与拼接

    转发 Python pandas DataFrame数据的合并与拼接 merge join concat 总结得很全面 比如将一个文件夹下所有文件合并 merge import os import pandas as pd file lis
  • 数据结构——图解求单链表的长度及插入操作C语言

    单链表的插入属于单链表的基本操作之一 关于单链表的初始化的解释在我的上篇文章中已经详细说明过了 一 求单链表长度 求单链表长度的操作很简单 其实在初始化赋值或遍历那块就可以实现 但是为了让结构层次独立清楚 我还是把求长度写成了一个函数 单链
  • 在GCP上创建Cloud SQL的三种方式(Console,gcloud,Terraform)

    1 简介 Cloud SQL 是GCP上的关系型数据库 常用的有三种方式来创建 1 界面操作 2 命令行 gcloud 3 Terraform 在开始之前 可以查看 初始化一个GCP项目并用gcloud访问操作 2 GCP 操作界面 登陆G
  • git 删除右键菜单

    首先 我表示git默认的右键菜单很烦 太多项了 而我们平时用的最多的无非是一个Git Bash 删除msGit右键菜单 如果是windows 64位系统 cmd进入 C Program Files x86 Git git cheetah 目
  • 恢复U盘分区:windows自带工具diskpart

    步骤 如下图 cmd命令行处执行diskpart命令 运行该工具 然后list disk 列出所有磁盘 然后select disk xxx 选中自己的磁盘 比如下图的是磁盘2 然后clean 清空分区 然后creat partition p
  • 我们这个年龄应该要做的事

    大家好 我是一名入门的菜鸟 如果你不经意间翻开了我的文章 谢谢您 您的支持是我前进的动力 让我们一起加油 由于不是名牌大学 只是一个普普通通的专科生 所以 我想通过自己的努力来获得我想要的 我不会放弃我的梦想 我也曾幻想着我成功的时候在朋友
  • MQ如何保证消息不丢失

    如何保证消息不丢失 哪些环节会造成消息丢失 其实主要就是跨网络的环境中需要考虑消息的丢失 主要是有以下几个方面 生产者往MQ发送消息 MQ的Broker是集群有主从的 主节点把消息同步到从节点时也需要考虑消息丢失问题 消息从内存持久化到硬盘
  • Java 3D 开发

    OPENGL VRML DIRECT3D JAVA3D的比较 Java3D建立在JAVA基础之上 JAVA语言的简单性使JAVA3D的推广有了可能 它实现了以下三维显示能够用到的功能 生成简单或复杂的形体 也可以调用现有的三维形体 使形体具
  • 错误AttributeError: module ‘onnx‘ has no attribute ‘load‘的解决方式

    错误出现 在使用torch导出onnx后 使用 onnx load xxx onnx 出现 AttributeError module onnx has no attribute load 错误原因 详见https github com p
  • 隐马尔可夫模型介绍

    http blog csdn net gumpeng article details 51648259 关于隐马尔可夫的理论介绍 请参见李航博士的 统计学习方法 介绍的很详尽 下面主要通过网上查到的例子来把隐马的相关问题说清楚 以下内容都非
  • 【C语言进阶】自定义类型详解(结构体、枚举、联合)

    博客主页 小王又困了 系列专栏 C语言 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 结构体 1 1结构体的认识 1 2结构体的声明 1 先声明结构体类型 再定义该类型的变量 2 在声明类型的同时定义 1 3结构体的特殊声明
  • Leetcode 5544: 执行操作后字典序最笑的字符串

    题目描述 给你一个字符串 s 以及两个整数 a 和 b 其中 字符串 s 的长度为偶数 且仅由数字 0 到 9 组成 你可以在 s 上按任意顺序多次执行下面两个操作之一 累加 将 a 加到 s 中所有下标为奇数的元素上 下标从 0 开始 数
  • win10修改默认安装路径

    win10修改默认安装路径 win10修改默认安装路径 1 以Win10系统为例 首先我们鼠标右键点击 开始 菜单 弹出菜单之后 点击 运行 如下图所示 2 在运行的输入框输入 regedit 并点击确定进入注册表编辑器 如下图所示 3 在
  • layui时间选择器---去除秒列

    layui时间选择器 去除秒列 前言 layui开发文档中介绍的时间选择器包含了时 分 秒的选择 在实际开发过程中 我们选择时间可能不需要精确到秒 原始结构 1 HTML页面引入layui js文件 2 HTML文件中添加如下代码 3 在j
  • 大数据分析 开源数据集_什么是大数据分析? 来自各种数据集的快速答案

    大数据分析 开源数据集 有数据 然后有大数据 那么 有什么区别呢 大数据定义 一个清晰的大数据定义可能很难确定 因为大数据可以涵盖许多用例 但是总的来说 该术语指的是数据量如此之大 如此复杂以至于传统的数据处理软件产品无法在合理的时间内捕获
  • 只需一个提示词解除GPT-4的字符限制!

    ChatGPT的内存有限 GPT 3 5 turbo的限制为4897个令牌 而GPT 4的最大限制为8192 如果您在使用GPT 4进行聊天时超过8192个令牌 约6827个单词 它就会开始遗忘 我想出了一种新的技巧 可以轻松将对话扩展10
  • Linux项目实战C++轻量级Web服务器源码分析TinyWebServer

    目录 文章简介 一 先跑起来项目 二 再看项目结构 三 逐个击破 立下flag 文章简介 TinyWebServer是Linux下C 轻量级Web服务器 助力初学者快速实践网络编程 搭建属于自己的服务器 作为新手拿它练手入门再好不过的不二之
  • 蓝桥杯 试题 算法训练 拿金币

    问题描述 有一个N x N的方格 每一个格子都有一些金币 只要站在格子里就能拿到里面的金币 你站在最左上角的格子里 每次可以从一个格子走到它右边或下边的格子里 请问如何走才能拿到最多的金币 输入格式 第一行输入一个正整数n 以下n行描述该方
  • TQ2440移植u-boot2016.11全过程记录-【7】NAND FLASH方式启动U-BOOT

    TQ2440移植u boot2016 11 NAND FLASH方式启动U BOOT S3C2440 U BOOT启动方式说明 NOR FLASH启动 S3C2440会直接在NOR上运行程序 在NOR上中的代码需要初始化芯片时钟 初始化SD