jz2440开发板修改UBOOT支持NAND FLASH

很多天没有看嵌入式的东西了,今天来看一下,继续之前移植uboot到jz2440开发板。今天我们来实现Uboot支持NAND FLASH。

在之前的文章里(点击连接查看之前的记录),我们为了编译通过把NAND FLASH 给屏蔽掉了,现在把它加回来。
将:include/configs/smdk2440.h: 中的#define CONFIG_CMD_NAND取消注释,重新编译,看一下编译的结果错误是什么?错误如下:
这里写图片描述
,遇到错误要按照从第一个错误开始解决的办法,因为有时候第一个错误解决了,后面的错误可能就没有了。我们这里第一个错误是:
s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
显示大概的意思是不完整的类型,我们去s3c2410_nand.c中72行去寻找,是如下代码:

if (ctrl & NAND_NCE)
72行:            writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,&nand->nfconf);

调用了一个nand结构体:

struct s3c2410_nand *nand = s3c2410_get_base_nand();

结构体如下:

#ifdef CONFIG_S3C2410
/* NAND FLASH (see S3C2410 manual chapter 6) */
struct s3c2410_nand {u32 nfconf;u32 nfcmd;u32 nfaddr;u32 nfdata;u32 nfstat;u32 nfecc;
};
#endif

我们应该是没有定义CONFIG_S3C2410,因为之前是我们在smdk2440.h中注释掉了2410的定义,换成了2440:

//#define CONFIG_S3C2410        /* specifically a SAMSUNG S3C2410 SoC */
#define CONFIG_S3C2440      /* specifically a SAMSUNG S3C2440 SoC */

那我们只能修改代码支持2440的部分了(想要更加了解代码如何修改,需要了解nand flash的操作,详细可以去看韦东山视频第二期的关于nand flash的操作)。

操作步骤:
1.把drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c
该目录下的Makefile里面关于2410的配置为:
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
去smdk2440.h中搜索CONFIG_NAND_S3C2410,发现有如下两行代码:

#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC

将这两行代码修改为:

#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#endif

修改上面的Makefile:
添加一行:
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
这代表如果配置文件里面定义了CONFIG_NAND_S3C2440,则执行这一行的编译。

2.首先我们去看一下板级初始化相关函数board.c里面关于nand初始化的函数,在board.c中board_init_r函数中有:

void board_init_r(gd_t *id, ulong dest_addr)
{
......
......
nand_init();        /* go init the NAND */
......
......
}

跳转到如下代码(nand.c中):

void nand_init(void)
{
#ifdef CONFIG_SYS_NAND_SELF_INIT /* 没有执行 */board_nand_init();
#else                           /* 执行这里 */int i;for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)nand_init_chip(i);
#endifprintf("%lu MiB\n", total_nand_size / 1024);#ifdef CONFIG_SYS_NAND_SELECT_DEVICE/** Select the chip in the board/cpu specific driver*/board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}

先跳转到nand_init_chip这里执行:

static void nand_init_chip(int i)
{struct mtd_info *mtd = &nand_info[i];struct nand_chip *nand = &nand_chip[i];ulong base_addr = base_address[i];int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;if (maxchips < 1)maxchips = 1;mtd->priv = nand;nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;if (board_nand_init(nand))return;if (nand_scan(mtd, maxchips))return;nand_register(i);
}#endif

我们关心的是板级初始化board_nand_init:

int board_nand_init(struct nand_chip *nand)
{u_int32_t cfg;u_int8_t tacls, twrph0, twrph1;struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();debug("board_nand_init()\n");writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);/* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)tacls  = CONFIG_S3C24XX_TACLS;twrph0 = CONFIG_S3C24XX_TWRPH0;twrph1 =  CONFIG_S3C24XX_TWRPH1;
#elsetacls  = 4;twrph0 = 8;twrph1 = 8;
#endifcfg = S3C2410_NFCONF_EN;cfg |= S3C2410_NFCONF_TACLS(tacls - 1);cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);writel(cfg, &nand_reg->nfconf);/* initialize nand_chip data structure */nand->IO_ADDR_R = (void *)&nand_reg->nfdata;nand->IO_ADDR_W = (void *)&nand_reg->nfdata;nand->select_chip = NULL;/* read_buf and write_buf are default *//* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPLnand->read_buf = nand_read_buf;
#endif/* hwcontrol always must be implemented */nand->cmd_ctrl = s3c2410_hwcontrol;nand->dev_ready = s3c2410_dev_ready;#ifdef CONFIG_S3C2410_NAND_HWECCnand->ecc.hwctl = s3c2410_nand_enable_hwecc;nand->ecc.calculate = s3c2410_nand_calculate_ecc;nand->ecc.correct = s3c2410_nand_correct_data;nand->ecc.mode = NAND_ECC_HW;nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#elsenand->ecc.mode = NAND_ECC_SOFT;
#endif#ifdef CONFIG_S3C2410_NAND_BBTnand->options = NAND_USE_FLASH_BBT;
#elsenand->options = 0;
#endifdebug("end of nand_init\n");return 0;
}

将以上的这句话:
struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
改为:
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
然后往下看代码,看到设置时序的时候,与2440手册对比发现,发现时序设置不对,它是适用于2410的,并不适用于2440,将以下代码:

cfg = S3C2410_NFCONF_EN;cfg |= S3C2410_NFCONF_TACLS(tacls - 1);cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

修改为:

/* 设置时序 lyy*/cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);

然后我们先来做一件事,把这个程序中的关于ECC的代码全部删掉,这一部分太复杂,但是对我们的程序又没有影响太大。删掉下面的代码:

#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{struct s3c2410_nand *nand = s3c2410_get_base_nand();debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
}static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,u_char *ecc_code)
{struct s3c2410_nand *nand = s3c2410_get_base_nand();ecc_code[0] = readb(&nand->nfecc);ecc_code[1] = readb(&nand->nfecc + 1);ecc_code[2] = readb(&nand->nfecc + 2);debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",mtd , ecc_code[0], ecc_code[1], ecc_code[2]);return 0;
}static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,u_char *read_ecc, u_char *calc_ecc)
{if (read_ecc[0] == calc_ecc[0] &&read_ecc[1] == calc_ecc[1] &&read_ecc[2] == calc_ecc[2])return 0;printf("s3c2410_nand_correct_data: not implemented\n");return -1;
}
#endif

然后我们用source insight里面的替代功能,将s3c2410_hwcontrol,s3c2410_dev_ready,s3c2440_nand,s3c2440_get_base_nand,这几个函数全部替换成…2440….

再来分析:s3c2440_hwcontrol函数,它最后面有这样几行代码:

if (ctrl & NAND_NCE)   /* 使能选中 */writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,&nand->nfconf);else                    /* 取消选中 */writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,&nand->nfconf);

这个是控制寄存器的片选的配置,这是2410的配置,我们是2440的配置,需要查看2440手册查看相关寄存器,我们的2440需要配置的是NFCONT寄存器。查看寄存器配置后,将上面的代码修改为:

if (ctrl & NAND_NCE)   /* 使能选中 */writel(readl(&nand->nfcont) & ~(1<<1),&nand->nfcont);else                    /* 取消选中 */writel(readl(&nand->nfcont) | (1<<1),&nand->nfcont);

突然想到上面有一个地方还行需要设置一下nfcont寄存器,在s3c2440_nand.c中的board_nand_init函数中加入一段话(下面两行):

/* 设置时序 lyy*/cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);writel(cfg, &nand_reg->nfconf);/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */      /*加入的*/writel((1<<4)|(1<<1)|(1<<0),&nand_reg->nfcont);  /*加入的*/

通过分析,发现还需要在s3c2440_nand.c中的board_nand_init函数里加上nand->select_chip = s3c2440_nand_select;这个函数,将以下代码修改为:nand->select_chip = s3c2440_nand_select;

nand->select_chip = NULL;
修改为:
nand->select_chip = s3c2440_nand_select;

编写s3c2440_nand_select函数,放在board_nand_init上面。

static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{struct s3c2440_nand *nand = s3c2440_get_base_nand();switch (chipnr) {case -1:    /* 取消选中 */nand->nfcont |= (1<<1);break;case 0:     /* 选中 */nand->nfcont &= ~(1<<1);break;default:BUG();}
}

通过分析知道,需要修改s3c2440_hwcontrol函数重新全部修改为下面得函数:

static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
{struct nand_chip *chip = mtd->priv;struct s3c2440_nand *nand = s3c2440_get_base_nand();if (ctrl & NAND_CLE){/* 发命令 */   writeb(dat, &nand->nfcmd);}if (ctrl & NAND_ALE){/* 发地址 */writeb(dat, &nand->nfaddr);}}

上面的分析过于复杂,对于我来说还是有一定难度,我也无法用文字描述清楚,下面给出函数调用的大致流程,等以后水平高了,再回头来看年轻的时候做过的记录。
分析过程:

nand_initnand_init_chipboard_nand_init设置nand_chip结构体, 提供底层的操作函数nand_scannand_scan_identnand_set_defaultschip->select_chip = nand_select_chip;chip->cmdfunc = nand_command;chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;nand_get_flash_typechip->select_chipchip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);nand_command()  // 即可以用来发命令,也可以用来发列地址(页内地址)、行地址(哪一页)chip->cmd_ctrls3c2440_hwcontrolchip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);*maf_id = chip->read_byte(mtd);*dev_id = chip->read_byte(mtd);

修改的文件一共涉及三个文件:s3c2440_nand.c,smdk2440.h,Makefile,这三个文件。
重新编译烧写到开发板(烧写步骤会单独写一篇文章记录):
这里写图片描述

很奇怪,又出现了这个错误:
Flash: ERROR: too many flash sectors
记得在之前修改代码支持NOR FLASH中也出现过一样的错误(点击查看之前的文章)。我们将CONFIG_SYS_MAX_FLASH_SECT这个值改大一些试一下,改为128(我记得之前改过,怎么又变回去了?奇怪!!!)
然后重新烧写启动:
这里写图片描述
从中可以看出已经识别出了nand:256MiB.那么说明我们的uboot已经支持nand flash。
下面从NAND 启动看一下,首先我们从NOR直接把uboot拷贝到NAND。输入以下命令:
nand erase 0 80000
nand write 0 0 80000
然后测试烧写到NNAD FLASH中的uboot是否正常
nand read 30000000 0 80000
cmp.b 0 30000000 80000 (比较拷贝的代码是否全部一样)
然后切换到NAND重启。显示:
这里写图片描述
这样的话,就说明我们的nand启动也是正常的!!!!
写了很久,真的很累也很难,但是我相信付出一定有回报的~

想获得各种学习资源以及交流学习的加我:
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

i.MX6网卡驱动程序fec.c的分析(AR8035网卡驱动程序的详细分析)之二

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天接着分析上次没有分析完的i.MX6网卡驱动程序。上一篇分析了iMX6网卡驱动程序的driver与device的加载过程&#xff08;点击可以查看上一篇文章&…

阅读ethercat官方文档关于ethercat网卡驱动程序的一些内容

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 改造iMX6&#xff08;fec&#xff09;网卡驱动程序前期工作之&#xff1a;阅读ethercat-1.5.2.pdf文档的第四章内容。 ethercat-1.5.2.pdf文档链接&a…

jz2440开发板移植U-boot之修改代码支持DM9000网卡

今天我们来移植U-boot到jz2440开发板&#xff0c;修改代码支持DM9000网卡。查看之前写的移植记录请点击链接&#xff1a;点击查看之前的移植记录 现在大多数开发板都支持DM9000网卡。我们的U-boot源码里面也是有DM9000网卡的驱动程序的。文件为Dm9000x.c&#xff08;drivers\n…

移植U-BOOT之裁剪和修改默认参数(易用性)启动内核,以及对uboot进行分区

今天我们来裁剪U-BOOT&#xff0c;使其更加易用&#xff0c;修改默认参数&#xff0c;以及制作最终修改好得补丁文件方便以后的快速移植。 那么如果想看之前的关于网卡以及flash等的移植&#xff0c;请点击链接查看&#xff1a;点击链接查看 在裁剪修改之前呢&#xff0c;我们…

移植U-BOOT之支持烧写YAFFS文件系统以及制作U-BOOT补丁

今天&#xff0c;我们来移植U-BOOT让其支持YAFFS文件系统映像的烧写&#xff0c;以及最后的终极目标&#xff0c;制作Uboot补丁&#xff0c;因为我们信心苦苦移植好了Uboot&#xff0c;如果换一个地方的或者换一台电脑之类的&#xff0c;我们也不想再浪费时间从头开始移植&…

【数据结构学习之完全从零实现所有数据结构的代码编写之一】泛型编程简介

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天开始系统性学习数据结构内容&#xff0c;之前也看过大话数据结构这本书&#xff0c;对大多数概念以及数据结构都有一定的了解&#xff0c;但是就是…

zookeeper 安装和使用

1.Windows安装和使用zookeeper 之前整理过一篇文章《zookeeper 分布式锁服务》&#xff0c;本文介绍的 Zookeeper 是以 3.4.5 这个稳定版本为基础&#xff0c;最新的版本可以通过官网 http://hadoop.apache.org/zookeeper/来获取&#xff0c;Zookeeper 的安装非常简单&#xf…

【移植Linux 3.4.2内核第一步】之简单修改

前一阵子已经将U-boot移植好了&#xff0c;从今天开始&#xff0c;我们开始移植linux内核。移植的内核为3.4.2&#xff0c;移植的开发板为&#xff1a;jz2440开发板。 想看之前移植U-boot的记录&#xff0c;可以查看我的博客专栏&#xff0c;点击链接&#xff1a;点击查看U-bo…

前端学习(77):css中常见margin塌陷问题之解决办法

塌陷问题 当两个盒子在垂直方向上设置margin值时&#xff0c;会出现一个有趣的塌陷现象。 ①垂直并列 首先设置两个DIV,并为其制定宽高 1 1 /*HTML部分*/2 <body>3 <div class"box1">box1</div>4 <div class"box2">box2…

HBase2.0 vs HBase1.x 延时比较

hbase2.0已经正式发布&#xff0c;对比之前1.x版本&#xff0c;2.0在读写链路上做了完善的优化&#xff0c;offheap、netty rpc等&#xff0c;这里做个小测试实验对比1.x和2.0在读写上的延时情况。本测试基于特定测试环境与软件版本得到的结果&#xff0c;仅供参考。 测试介绍 …

【数据结构学习之完全从零实现所有数据结构的代码编写之二】智能指针

今天我们依然暂时不讲解数据结构里面的内容&#xff0c;我们来复习一下昨天学的模板技术用于数据结构编程的思想&#xff0c;给出一个模板技术的实例&#xff1a;智能指针的应用。喜欢看我分享的加我q:1126137994 加我共同学习交流各种技术。 为什么会引入智能指针呢&#xff…

职责链模式(Chain of Responsibility)

重要概念 1. 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 2.请求是沿着链条传递到有一个处理点对象负责处理这个请求为止。请求者无需…

mootools

$();// 选择ID为”body_wrap“的元素$(body_wrap);.getElement();// 选择ID为”body_wrap“的元素下面的第一个链接$(body_wrap).getElement(a); or #xxx or .xxx.getElements();// 选择ID为”body_wrap“的元素下面的所有链接$(body_wrap).getElements(a); $(body_wrap).getE…

图形化界面客户端连接phoenix操作hbase

下载客户端软件 DBeaver https://dbeaver.io/download/ 选择对应系统的版本&#xff0c;我这里选择解压版windows64位 创建连接 注意&#xff1a;URL模板就不要一般是默认 选择合适的版本&#xff08;跟你服务器的版本一致&#xff09;&#xff0c;下载jar包 点击测试或完成即…

【C++深度剖析教程12】数组操作符的重载

之前写的C学习记录忘记打编号了&#xff0c;从今天开始&#xff0c;所有内容&#xff0c;记录编号&#xff0c;方便以后的查阅复习。今天学习的是C中&#xff0c;数组操作符的重载。 上一篇博文写的是介绍C中的字符串类&#xff0c;我们知道&#xff0c;C标准库中通过string类…

前端学习(80):按类型划分标签(inline)

解决font-size中间有间隙 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compat…

HBase shell 命令介绍

HBase shell是HBase的一套命令行工具&#xff0c;类似传统数据中的sql概念&#xff0c;可以使用shell命令来查询HBase中数据的详细情况。安装完HBase之后&#xff0c;如果配置了HBase的环境变量&#xff0c;只要在shell中执行hbase shell就可以进入命令行界面&#xff0c;HBase…

【C++深度剖析教程13】函数对象的分析

今天来学习函数对象。什么是函数对象呢&#xff1f;下面我们以一个例子来引出函数对象的概念。 假设我们需要编写一个函数&#xff0c;实现下面这些功能&#xff1a; -函数可以获得斐波那契数列每一项的值 -每调用一次返回一个值 -函数可根据需要重复用使用 实现上面的几个…

IE图标消失 HTML文件图标变为未知图标的解决方法

有时候保存在硬盘里的HTM和HTML文件图标会突然变为未知的图标&#xff0c;而且它们往往还是与IE关联&#xff0c;也没有发现病毒。原因我怎么也弄不明白&#xff0c;但可以通过对注册表做些修改来恢复&#xff0c;详细步骤如下: 1.首先打开注册表编辑器&#xff0c;定位到HKEY_…

(SQuirreL SQL Client 客户端 )使用Apache Phoenix 实现 SQL 操作HBase

Apache Phoenix 相信大家并不陌生&#xff0c;它是HBase的SQL驱动&#xff0c;Phoenix 使得Hbase 支持通过JDBC的方式进行访问&#xff0c;并将你的SQL查询转换成Hbase的扫描和相应的动作。 兼容性&#xff1a; Phoenix 2.x - HBase 0.94.x Phoenix 3.x - HBase 0.94.x Phoen…