TX2440 ARM开发板Uboot移植(二、让u-boot从nandFlash动起来)

2024-06-04 09:32

本文主要是介绍TX2440 ARM开发板Uboot移植(二、让u-boot从nandFlash动起来),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接上:让u-boot从norFlash动起来


完成上面工作后,u-boot中还没有对2440上Nand Flash的支持,以及u-boot从Nand Flash上启动,这些得我们一步步去实现了。

1、修改配置文件 include/configs/smdk2440.h :

1.1、新增宏 CONFIG_CMD_NAND (大概在95行)
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_NAND
#define CONFIG_CMD_ENV

1.2、在文件的最后面增加3个宏:

//NAND flash settings
#define NAND_CTL_BASE     0x4E000000  //NAND Flash的地址
#define CFG_MAX_NAND_DEVICE  1         //NAND Flash设备数目为1
#define NAND_MAX_CHIPS      1                 //每个NAND设备由1个NADN芯片组成

2、  修改 include/s3c24x0.h 文件,增加S3C2440_NAND数据结构(168行)

/* NAND FLASH (see S3C2440 manual chapter 6) */
typedef struct {
    S3C24X0_REG32 NFCONF;
    S3C24X0_REG32 NFCONT;
    S3C24X0_REG32 NFCMD;
    S3C24X0_REG32 NFADDR;
    S3C24X0_REG32 NFDATA;
    S3C24X0_REG32 NFMECCD0;
    S3C24X0_REG32 NFMECCD1;
    S3C24X0_REG32 NFSECCD;
    S3C24X0_REG32 NFSTAT;
    S3C24X0_REG32 NFESTAT0;
    S3C24X0_REG32 NFESTAT1;
    S3C24X0_REG32 NFMECC0;
    S3C24X0_REG32 NFMECC1;
    S3C24X0_REG32 NFSECC;
    S3C24X0_REG32 NFSBLK;
    S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;

3、u-boot默认是从Nor Flash启动的。修改文件 cpu/arm920t/start.S ,使u-boot可以从Nand Flash启动:

对文件改动较大,仔细对比源代码,主要的修改是将栈的初始化放到前面,用于后面调用C函数的需要;
判断u-boot不是从内存启动后,调用CopyCode2Ram函数,实现把启动代码拷贝到内存

/*
  * we do sys-critical inits only at reboot,
  * not when booting from ram!
  */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 adr r0, _start    /* r0 <- current position of code   */
 ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
 cmp     r0, r1        /* don't reloc during debug         */
 blne cpu_init_crit
#endif

stack_setup:      //将栈的初始化放到前面
 ldr r0, _TEXT_BASE     /* upper 128 KiB: relocated uboot   */
 sub r0, r0, #CFG_MALLOC_LEN  /* malloc area                   */
 sub r0, r0, #CFG_GBL_DATA_SIZE  /* bdinfo              */
#ifdef CONFIG_USE_IRQ
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */

relocate:      /* relocate U-Boot to RAM     */
 adr r0, _start  /* r0 <- current position of code   */
 ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
 cmp     r0, r1                  /* don't reloc during debug         */
 beq     clear_bss

 ldr r2, _armboot_start
 ldr r3, _bss_start
 sub r2, r3, r2  /* r2 <- size of armboot            */
 bl CopyCode2Ram   
// 调用board/smdk2440/boot_Init.c里的CopyCode2Ram函数,把启动代码拷贝到内存

clear_bss:
 ldr r0, _bss_start  /* find start of bss segment        */
 ldr r1, _bss_end  /* stop here                        */
 mov r2, #0x00000000  /* clear                            */
clbss_l:str r2, [r0]  /* clear loop...                    */
 add r0, r0, #4
 cmp r0, r1
 ble clbss_l

 ldr pc, _start_armboot

_start_armboot: .word start_armboot

4、新建 board/smdk2440/boot_Init.c 文件,实现从NandFlsh读取字节;判断启动方式,并拷贝启动代码到内存。代码如下:

#include <common.h>
#include <s3c2440.h>

#define BUSY            1

#ifdef NAND_LARGEPAGE
#define NAND_SECTOR_SIZE 2048
#else
#define NAND_SECTOR_SIZE 512
#endif
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

/* 供外部调用的函数 */
void nand_init_ll(void);
void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);

/* S3C2440的NAND Flash处理函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);
/* S3C2440的NAND Flash操作函数 */
/* 复位 */

static void nand_reset(void)
{
    nand_select_chip();
    write_cmd(0xff);  // 复位命令
    wait_idle();
    nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void wait_idle(void)
{
  int i;
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
 volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

 while(!(*p & BUSY))
 for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void nand_select_chip(void)
{
 int i;
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

 s3c2440nand->NFCONT &= ~(1<<1);
 for(i=0; i<10; i++);    
}

/* 取消片选信号 */
static void nand_deselect_chip(void)
{
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void write_cmd(int cmd)
{
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *p = cmd;
}

/* 发出地址 Nand进行寻址的部分*/
static void write_addr(unsigned int addr)
{
  int i;
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
 volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
#ifndef NAND_LARGEPAGE    
 *p = addr & 0xff;
 for(i=0; i<10; i++);
 *p = (addr >> 9) & 0xff;
 for(i=0; i<10; i++);
 *p = (addr >> 17) & 0xff;
 for(i=0; i<10; i++);
 *p = (addr >> 25) & 0xff;
 for(i=0; i<10; i++);
#else
 int col, page;
 col = addr & NAND_BLOCK_MASK;
 page = addr / NAND_SECTOR_SIZE;
 *p = col & 0xff;   /* Column Address A0~A7 */
 for(i=0; i<10; i++);  
 *p = (col >> 8) & 0x0f;  /* Column Address A8~A11 */
 for(i=0; i<10; i++);
 *p = page & 0xff;   /* Row Address A12~A19 */
 for(i=0; i<10; i++);
 *p = (page >> 8) & 0xff; /* Row Address A20~A27 */
 for(i=0; i<10; i++);
 *p = (page >> 16) & 0x03; /* Row Address A28~A29 */
 for(i=0; i<10; i++);
#endif
}

/* 读取数据 */
static unsigned char read_data(void)
{
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
 volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
 return *p;
}

/* 初始化NAND Flash */
void nand_init_ll(void)
{
 S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

#define TACLS   0
#define TWRPH0  3
#define TWRPH1  0
 /* 设置时序 */
 s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
 /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
 s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
 /* 复位NAND Flash */
 nand_reset();
}

/* 读函数 */
void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
        return ;    /* 地址或长度不对齐 */
    }
    /* 选中芯片 */
    nand_select_chip();
    for(i=start_addr; i < (start_addr + size);) {
      /* 发出READ0命令 */
      write_cmd(0);
      /* Write Address */
      write_addr(i);
#ifdef NAND_LARGEPAGE
 write_cmd(0x30);
#endif
      wait_idle();
      for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
          *buf = read_data();
          buf++;
      }
    }
    /* 取消片选信号 */
    nand_deselect_chip();
    return ;
}

int bBootFrmNORFlash(void)   /* 取OM0、1的值,判断开发板是从NorFlash还是NandFlash启动 */
{
  volatile unsigned int *bwsCON = (volatile unsigned int *)0x48000000;
  unsigned int bwsVal;
  bwsVal = *bwsCON;
  bwsVal &= 0x06;
  if (bwsVal==0){
   return 0;
  }
  else {
   return 1;
  }
}

int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
    unsigned int *pdwDest;
    unsigned int *pdwSrc;
    int i;

    if (bBootFrmNORFlash())
    {
      pdwDest = (unsigned int *)buf;
      pdwSrc  = (unsigned int *)start_addr;
      /* 从 NOR Flash启动 */
      for (i = 0; i < size / 4; i++)
      {
        pdwDest[i] = pdwSrc[i];
      }
    }
    else
    {
      /* 初始化NAND Flash */
   nand_init_ll();
      /* 从 NAND Flash启动 */
      nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
    }
 return 0;
}

注意:上面这段代码中对Nand进行寻址的部分,这跟具体的Nand Flash的寻址方式有关。根据开发板上的Nand Flash(K9F1208U0C)数据手册得知,片内寻址是采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行传送,并进行片内寻址。具体含义和结构图如下(相关概念参考Nand数据手册):
TX2440 ARM开发板Uboot移植(二、让u-boot从nandFlash动起来) - xiesnap - 谢烨

5、在 board/smdk2440/Makefile 中添加 boot_Init.c 的编译选项,使他编译到u-boot中:

COBJS    := my2440.o flash.o boot_Init.o

6、还有一个重要的地方要修改,在 cpu/arm920t/u-boot.lds 中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码,主要目的是防止编译器把CopyCode2Ram的子函数放到4K之后,否则是无法启动的。如下:

.text :
{
      cpu/arm920t/start.o    (.text)
      board/smdk2440/boot_Init.o (.text)
      board/smdk2440/lowlevel_init.o (.text)    
      *(.text)
}

这篇关于TX2440 ARM开发板Uboot移植(二、让u-boot从nandFlash动起来)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1029700

相关文章

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

Spring Boot配置和使用两个数据源的实现步骤

《SpringBoot配置和使用两个数据源的实现步骤》本文详解SpringBoot配置双数据源方法,包含配置文件设置、Bean创建、事务管理器配置及@Qualifier注解使用,强调主数据源标记、代... 目录Spring Boot配置和使用两个数据源技术背景实现步骤1. 配置数据源信息2. 创建数据源Be

Spring Boot 3.x 中 WebClient 示例详解析

《SpringBoot3.x中WebClient示例详解析》SpringBoot3.x中WebClient是响应式HTTP客户端,替代RestTemplate,支持异步非阻塞请求,涵盖GET... 目录Spring Boot 3.x 中 WebClient 全面详解及示例1. WebClient 简介2.

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1

Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)

《SpringBoot从main方法到内嵌Tomcat的全过程(自动化流程)》SpringBoot启动始于main方法,创建SpringApplication实例,初始化上下文,准备环境,刷新容器并... 目录1. 入口:main方法2. SpringApplication初始化2.1 构造阶段3. 运行阶

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三