移植三星官方的uboot到x210

2023-05-16

1、移植前的准备工作

1.1、三星移植过的uboot源代码准备

(1)三星对于S5PV210的官方开发板为SMDKV210,对应移植的_uboot_smdkv210.tar.bz2

1.2、SourceInsight准备

(1)移植的时候最重要的工作就是看代码、改代码然后编译运行测试。
(2)编译代码必须在linux中(不能在windows共享文件夹下配置uboot,因为windows没有符号链接,而配置过程中需要生成符号链接),那么看代码和改代码可以在linux中(vim、gedit)也可以在windows中(Sourceinsight)。
(4)那么如果看代码和改代码在windows中,而编译代码又必须在linux中,怎么实现windows中的代码和linux中的代码同步?
1)通过共享文件夹在linux中进行复制(cp /mnt/hgfs/winshare/xxx.c .);
2)通过一些专用工具,譬如sshsecureshell、filezilla。

1.3、便捷的文件传输工具sshsecureshell

(1)windows中安装sshsecureshell客户端。
(2)虚拟机上网。不同的ubuntu版本中网卡重启的命令不同,
在ubuntu10.04中网卡重启使用:/etc/init.d/networking restart 或者 service network restart;
在ubuntu14.04中以上两个都不行了,要重启网卡需要使用:ifdown eth0 然后ifup eth0。

2、ubuntu14.04上网及安装openssh

2.1、ubuntu14.04上网问题

(1)虚拟机上网有2种模式,NAT和桥接。
(2)虚拟机上网配置要注意这几个地方:
第一个要注意选择NAT还是桥接模式;
第二个如果是桥接模式要注意桥接到哪个网卡上(一般笔记本都有2个网卡,一个是有线网卡一个是无线网卡),如果是NAT模式则不用考虑这一点;
第三个要注意ubuntu中网络配置文件/etc/network/interfaces,这个文件中是配置网卡信息的(譬如静态ip还是dhcp(动态ip),静态ip地址是多少等);

(3)ubuntu14.04中重启网卡的命令变了。
(4)两种方式上网的配置过程:
NAT方式下上网配置过程:
前提是主机windows通过无线wifi上网了(或者windows通过有线网卡上网也可以)。
然后在虚拟机中配置2点:
第一选择NAT方式;
第二配置/etc/network/inerfaces文件中使用dhcp方式;
然后重启网卡,确认ip地址得到后即可上网。

桥接方式上网配置过程:
前提是主机windows通过无线wifi上网了(主机通过有线网卡上网的配置方式一点不同)。
然后在虚拟机中配置3点:
第一选择桥接方式;
第二配置桥接到无线网卡(如果主机windows是通过有线上网的,则桥接到有线网卡);
无线网卡关键词:wireless
有线网卡关键词:ethernet
第三配置/etc/network/inerfaces文件中使用dhcp方式;
然后重启网卡,确认ip地址得到后即可上网。

(5)虚拟机要ping通开发板的配置过程。
前提是开发板和电脑之间通过网线连接好。
然后在虚拟机中配置3点:
第一选择桥接方式;
第二配置桥接到有线网卡(如果配置为自动或者配置桥接到无线网卡则肯定无法ping通开发板);
第三配置/etc/network/inerfaces文件中使用static方式,ip地址配置保证和主机windows、开发板三者处于同一网段;
然后重启网卡,确认ip地址得到后即可ping通开发板。

(6)老版的windows系统中有一个bug,如果windows没有检测到有线网卡连接了外部网络则windows中本地连接是不工作的,即网卡不工作。解决方案是用网线随便连接一个有联网能力的东西即可,譬如网线连接你的电脑到旁边的电脑、开发板(开发板中运行了linux系统)、路由器端口等。

2.2、搭建openssh环境

(1)安装ssh-server。(sudo apt-get install openssh-server)如果报错提示依赖错误,可以参考:http://www.cnblogs.com/mliudong/p/4094519.html
(2)securecrt登录
(3)sshsecureshell登录
sshsecureshell登录不上,要修改/etc/ssh/sshd_config,参考:http://blog.sina.com.cn/s/blog_5f435c130102v6pv.html。
修改完重启时如果/etc/init.d/ssh restart不起作用,可以使用:ps -e | grep ssh,看sshd的进程号,然后kill -9 进程号杀死ssh进程以达到重启的目的,或者直接重启ubuntu系统

3、移植初体验

3.1、直接编译三星移植版的uboot尝试运行

(1)复制到linux的源生目录下,然后解压开。
cp /mnt/hgfs/share/s5pv210/android_uboot_smdkv210.tar.bz2 .
tar -jxvf android_uboot_smdkv210.tar.bz2
(2)检查Makefile中的交叉编译工具链(和自己安装的是否一致)在这里插入图片描述
(3)三星版本的Makefile中没有x210_sd_config,因此不能用make x210_sd_config进行配置,x210_sd_config是九鼎移植版uboot中才有的;这款开发板来自三星官方出版的smdkv210,在Makefile中搜索smdkv210,找到如下:在这里插入图片描述
发现smdkv210还有不同的版本,任选其中一个使用,这里使用smdkv210single_config,
因此配置时使用:make smdkv210single_config,对应include/configs/smdkv210single.h头文件。

(4)配置完成后直接make编译,编译完成后就进入烧录步骤。
(5)uboot/sd_fusing目录下有sd_fusing.sh脚本,用来烧录。
但由于三星官方是通过64位的Linux系统编译生成了mkbl1和sd_fdisk(使用file命令查看),因此不能使用,而我的ubuntu系统yes64位的,所以我自己移植了一份32位的,在~/porting_x210/uboot_samsung/u-boot-samsung-dev/uboot_sd_fusing目录在这里插入图片描述

3.2、代码分析&问题查找

运行结果是:第一,串口无输出;第二,开发板供电锁存成功。在这里插入图片描述
分析运行结果:uboot中串口最早的输出在"OK",在lowlevel_init.S中初始化串口时打印出来的;串口无输出"O"说明在打印"O"之前代码已经死掉了;开发板供电锁也存在lowlevel_init.S中,开发板供电锁存成功说明这个代码之前的部分是没问题的。两个结合起来得到结论:错误发生在开发板供电锁存代码和串口初始化打印"O"代码之间。
(1)Windows下建立SourceInsight工程,将所有文件加进工程
(2)顺藤摸瓜去找可能出问题的地方
整个程序运行是从start.S开始的,看代码也从这里开始。
在lowlevel_init.S中发现只要屏蔽掉bl PMIC_InitIp 这一行代码,然后重新编译,整个uboot就启动起来了。在这里插入图片描述
但是很多配置信息是有问题的,并且很多功能应该也是不能用的,都要去一一查验。

4、时钟和DDR的配置移植

4.1、更改 smdkv210single.h中的宏

宏CONFIG_IDENT_STRING改为" for CHM210",然后同步到ubuntu,
然后 make distclean; make smdkv210single_config,然后make,然后烧录运行,
检查打印出来的banner信息是否如我们改动的那样。在这里插入图片描述

4.2、确认时钟部分的配置

(1)前面可以看到,时钟部分的运行结果本来就是对的,时钟部分的代码在lowlevel_init.S中的bl system_clock_init调用的这个函数中。函数的代码部分是没任何问题的,根本不需要改动,如果需要更改时钟设置,那么就要改动寄存器写入的值,而这些值都在配置头文件(smdkv210single.h)中用宏定义定义出来了。如果时钟部分要更改,关键是去更改头文件中的宏定义。
(2)三星移植时已经把210常用的各种时钟配置全都计算好用宏开关来控制了。只要打开相应的宏开关就能将系统配置为相应的时钟频率。

//#define CONFIG_CLK_667_166_166_133
//#define CONFIG_CLK_533_133_100_100
//#define CONFIG_CLK_800_200_166_133
#define CONFIG_CLK_800_100_166_133
        //修改值
//#define CONFIG_CLK_1000_200_166_133    //原始值
//#define CONFIG_CLK_400_200_166_133
//#define CONFIG_CLK_400_100_166_133

在这里插入图片描述
但是这里还是出现了一些问题,应该是uboot中一些跟时钟密切相关的设备的配置并没有采用宏开关的方式(只要我们更改这个宏,那么就会进行不同的时钟配置,但是那里并没有更改),而是采用硬编码的方式,
譬如说串口的配置被写死成了跟#define CONFIG_CLK_1000_200_166_133这个宏相关。

4.3、DDR配置信息的更改

(1)从运行信息看到的结果,显示DRAM bank0和1的size长度值都设置错了。
(2)DRAM bank0和1的长度的软件配置在uboot的第二阶段的dram_init中
在这里插入图片描述
这些宏实际是smdkv210single.h中设置的配置值
修改配置值:

#define CONFIG_NR_DRAM_BANKS    2          /* we have 2 bank of DRAM */
//#define SDRAM_BANK_SIZE         0x20000000    /* 512 MB */
#define SDRAM_BANK_SIZE         0x10000000    /* 512 MB */

#define PHYS_SDRAM_1            MEMORY_BASE_ADDRESS /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE       SDRAM_BANK_SIZE
//#define PHYS_SDRAM_2            (MEMORY_BASE_ADDRESS + SDRAM_BANK_SIZE) /* SDRAM Bank #2 */
#define PHYS_SDRAM_2            0x40000000/* SDRAM Bank #2 *

然后同步到linux,重新编译烧录运行在这里插入图片描述

5、DDR地址的更改

5.1、目标:将DDR端口0地址配置为30000000开头

(1)更改的目的:将DRAM0的地址设置为30000000开头,这样就和DRAM1连接起来了,构成一片连续的内存,
原先的内存设置 DRAM0的地址范围:0200000000x2FFFFFFF,DRAM1的地址范围:0x400000000x4FFFFFFF
这样的内存是断续的。

5.2、DDR初始化参数更改

(1)DDR的初始化代码在lowlevel_init.S中。代码部分就是对相应寄存器进行初始化;使用宏进行初始化,因此代码部分是不用修改的,要修改的是宏定义的值,而uboot为了具有可移植性把这些宏定义都在include/configs/xxx.h中了。因此我们只需要去这个配置文件中修改配置值即可。
(2)更改内容是:
#define DMC0_MEMCONFIG_0 0x20E01323 改为:
#define DMC0_MEMCONFIG_0 0x30E01323 注意20改为30了。

5.3、smdkv210single.h中相关宏定义修改

(1)上面将寄存器的值改了后相当于是对硬件配置部分做了更改。但是uboot中DDR相关的一些软件配置值还没更改,还在原来位置,所以要去更改。
(2)
#define MEMORY_BASE_ADDRESS 0x20000000改为:
#define MEMORY_BASE_ADDRESS 0x30000000

5.4、虚拟地址映射表中相应修改

(1)由于uboot中开启了MMU对内存进行了虚拟地址映射,因此还要考虑这个地址映射后的物理地址是否是我们想要的,
比如说Makefile中指定链接地址是0xc3e00000,这个虚拟地址最终是将我们的uboot放在了哪里,
uboot在开启MMU前构建了一张TLB(页表),里面是内存映射关系。

.globl mmu_table
mmu_table:
    .set __base,0
    // Access for iRAM
    .rept 0x100
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr

    // Not Allowed
    .rept 0x200 - 0x100
    .word 0x00000000
    .endr

    .set __base,0x200
    // should be accessed
    .rept 0x600 - 0x200
    FL_SECTION_ENTRY __base,3,0,1,1
    .set __base,__base+1
    .endr

    .rept 0x800 - 0x600
    .word 0x00000000
    .endr

    .set __base,0x800
    // should be accessed
    .rept 0xb00 - 0x800
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr

/*    .rept 0xc00 - 0xb00
    .word 0x00000000
    .endr */

    .set __base,0xB00
    .rept 0xc00 - 0xb00
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr
//下面这一段是将c000 0000~d000 0000的虚拟地址映射到2000 0000~3000 0000的地址范围
    //.set __base,0x200
    .set __base,0x300
    // 256MB for SDRAM with cacheable
    .rept 0xD00 - 0xC00
    FL_SECTION_ENTRY __base,3,0,1,1
    .set __base,__base+1
    .endr

    // access is not allowed.
    @.rept 0xD00 - 0xC80
    @.word 0x00000000
    @.endr

    .set __base,0xD00
    // 1:1 mapping for debugging with non-cacheable
    .rept 0x1000 - 0xD00
    FL_SECTION_ENTRY __base,3,0,0,0
    .set __base,__base+1
    .endr    

(2)经过实际分析,发现这个内存映射只是把20000000开始的256MB映射到C0000000开头的256MB。其它地方都是原样映射,我们更改方法是将2改成3.
.set __base,0x200 改为
.set __base,0x300
(3)重新配置编译,烧录运行查看结果。在这里插入图片描述
发现只打印了OK,说明我们第一阶段内存初始化出问题了,导致不能重定位到内存,所以没有进入uboot的第二阶段

6、DDR初始化参数更改2

6.1、修改DMC0的配置参数

(1)修改DDR中DMC0的memconfig_0寄存器的配置值,将
#define DMC0_MEMCONFIG_0 0x30E01323 改为:
#define DMC0_MEMCONFIG_0 0x30F01323
(2)然后重新同步、编译烧写运行,发现uboot第二阶段运行了,即内存能工作了,但是SD卡的初始化出问题了,内存能工作,说明前面DDR的硬件寄存器配置没问题,出问题的只可能是修改DDR地址的过程中某个步骤影响到了SD卡的初始化。在这里插入图片描述
(3)分析问题,寻找解决方案。分析方法有2种:
第一种:靠自身经验积累;
第二种:就是在整个代码中先基本定位错误地方,然后通过在源代码中添加打印信息来精确定位出错的代码,然后找到精确的出错位置后再去分析错误原因,从而找到解决方案。

6.2、修改虚拟地址到物理地址的映射函数

(1)修改uboot/board/samsung/smdkc110/smdkc110.c中的virt_to_phy_smdkc110,将其中的20000000改为30000000即可。

#ifdef CONFIG_ENABLE_MMU

#ifdef CONFIG_MCP_SINGLE
ulong virt_to_phy_smdkc110(ulong addr)
{
    if ((0xc0000000 <= addr) && (addr < 0xd0000000))
        //return (addr - 0xc0000000 + 0x20000000);
                  return (addr - 0xc0000000 + 0x30000000);
    else
        printf("The input address don't need "\
            "a virtual-to-physical translation : %08lx\n", addr);

    return addr;
}
#else
ulong virt_to_phy_smdkc110(ulong addr)
{
    if ((0xc0000000 <= addr) && (addr < 0xd0000000))
        return (addr - 0xc0000000 + 0x30000000);
    else if ((0x30000000 <= addr) && (addr < 0x50000000))
        return addr;
    else
        printf("The input address don't need "\
            "a virtual-to-physical translation : %08lx\n", addr);

    return addr;
}
#endif

#endif

(2)同步代码,然后重新编译烧录运行。
在这里插入图片描述

6.3、总结:uboot代码牵一发而动全身

7、inand驱动问题的解决

7.1、先从现象出发定位问题

(1)解决问题的第一步,是定位问题。定位到出问题的代码处。通过搜索关键字EXT_CSD将问题定位在drivers/mmc/mmc.c的818行。
(2)找到出问题的代码之后,实际修改程序不一定改的是这一句代码。但是肯定和这一句代码有关联,我们要通过自己分析来找到这种关联。找到真正需要修改的地方。

7.2、网络搜索解决方案

/*
 * Read and decode extended CSD.(读取和解码扩展CSD)
 * CSD是SD内的一个寄存器,存着卡特有的信息
 */
 //这个函数就是用来读取高版本SD卡里的扩展型CSD寄存器的
static int mmc_read_ext_csd(struct mmc *host){
    int err;
    u8 *ext_csd;
    unsigned int ext_csd_struct;
    //host->version表示SD卡控制器的版本,如果SD卡控制器的版本比较低,则就不用读了
    if (host->version < (MMC_VERSION_4 | MMC_VERSION_MMC))
        return 0;

    /*
     * As the ext_csd is so large and mostly unused, we don't store the
     * raw block in mmc_card.
     */
    ext_csd = malloc(512);
    if (!ext_csd) {
        printf("could not allocate a buffer to "
            "receive the ext_csd.\n");
        return -1;
    }

    err = mmc_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 0);
    if (err)
        return err;

    err = mmc_switch(host, EXT_CSD_CMD_SET_NORMAL,
                EXT_CSD_BUS_WIDTH,
                EXT_CSD_BUS_WIDTH_1);
    if (err)
        return err;
    //主控制器向SD卡发命令来读ext_csd寄存器
    err = mmc_send_ext_csd(host, ext_csd);
    if (err) {
        /*
         * High capacity cards should have this "magic" size
         * stored in their CSD.
         */
        if (host->capacity == (4096 * 512)) {
            printf("unable to read EXT_CSD "
                "on a possible high capacity card. "
                "Card will be ignored.\n");
        } else {
            printf("unable to read "
                "EXT_CSD, performance might suffer.\n");
            err = 0;
        }

        goto out;
    }

    ext_csd_struct = ext_csd[EXT_CSD_REV];
    //if (ext_csd_struct > 5) { // find_mmc_device(2);
    if (ext_csd_struct > 8) {    // find_mmc_device(0);
        printf("unrecognised EXT_CSD structure "
            "version %d\n", ext_csd_struct);
        err = -1;
        goto out;
    }

    if (ext_csd_struct >= 2) {
        host->ext_csd.sectors =
            ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
            ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
            ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
            ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
        if (host->ext_csd.sectors) {
            host->high_capacity = ((host->ocr & OCR_HCS) == OCR_HCS);
            /* common host->read_bl_len=512 */
            host->capacity = host->ext_csd.sectors;
        }
    }

    switch (ext_csd[EXT_CSD_CARD_TYPE] & 0x3) {
    case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
        host->ext_csd.hs_max_dtr = 52000000;
        host->clock = 52000000;
        break;
    case EXT_CSD_CARD_TYPE_26:
        host->ext_csd.hs_max_dtr = 26000000;
        host->clock = 26000000;
        break;
    default:
        /* MMC v4 spec says this cannot happen */
        printf("card is mmc v4 but doesn't "
            "support any high-speed modes.\n");
        goto out;
    }

out:
    free(ext_csd);

    return err;
}

(1)初步的解决方案是自己先浏览一遍这个问题点周边代码上下文。通过浏览代码上下文,发现mmc_read_ext_csd这个函数是在读取SD/iNand的ext_csd寄存器的值。通过浏览代码结合出错地方,可以判断出:从卡端读取ext_csd寄存器是成功的,并且从读取结果中拿到了卡的版本号信息。然后代码对版本号进行了判断,发现版本号大于5所以报错。这就是问题所在。我们使用的iNand卡的版本号太高,大于5,而uboot代码本身不能处理版本号大于5的mmc卡,因此出错了。
(2)怎么解决?第一:更换iNand;第二:软件更改。
(3)网络搜索错误提示信息,然后逐个去查阅,看看哪个可以给我们提供解决问题的思路和方法。http://blog.csdn.net/wang_shuai_ww/article/details/22308853

7.3、尝试修改代码解决问题

(1)解决方法就是修改uboot中的代码,把判断的5改成更大的数字。譬如8,然后跳过这个错误。在这里插入图片描述

7.4、推测和实验验证(SD卡和iNand的区别)

(1)当前板子上有一个iNand接在SD0上,有一个外置SD卡接在SD2上。那uboot中初始化的这个是iNand而不是SD卡。也就是说uboot中实际用的是SD0而不是SD2.
(2)通过实验发现,uboot使用外置SD卡时,这个版本号的问题不会出现。从这里可以推测出SD卡和iNand的区别,至少从一个角度可以看出:SD卡版本低,iNand的版本比较高。

board.c 496~500行改为,即可除掉Nand的初始化

#undef CONFIG_CMD_NAND
#if defined(CONFIG_CMD_NAND)
    puts("NAND:    ");
    nand_init();
#endif

然后重新配置编译烧录即可进入命令行底下在这里插入图片描述

8、一些小问题的修补

8.1、控制台串口更换为串口0

(1)三星的uboot中默认使用串口2来做控制台输入输出的。
(2)SOC中一共有4个串口(串口0、1、2、3),开发板X210上用DB9接口引出了2个串口,分别是串口2和串口0.(靠边的是串口2,靠里那个是串口0)。
(3)如果要更换串口0作为uboot控制台的输入输出,肯定是要更改硬件寄存器的;uboot中真正去硬件初始化串口控制器的代码在lowlevel_init.S中的uart_asm_init中,其中初始化串口的寄存器用ELFIN_UART_CONSOLE_BASE宏作为寄存器的基地址,然后结合偏移量对寄存器进行寻址初始化。所以uart_asm_init中到底初始化的是串口几(从0到3)?取决于ELFIN_UART_CONSOLE_BASE宏的值。这个宏的值又由CONFIG_SERIALn(n是从1到4)来决定,对应串口0~3;因此要更换串口0为串口2,只要在smdkv210single.h中定义CONFIG_SERIA3,然后屏蔽其它的宏就可以了。
(4)同步代码、配置编译烧录运行,发现串口线插在串口2上,console上只打印:SD checksum error.(这个是内部iROM中的代码打印出来的iNand校验失败的信息);然后将串口线改插到串口0上,启动,所有的信息出现。实验成功。

8.2、修改默认网络地址设置

(1)修改配置头文件smdkv210single.h中的CONFIG_IPADDR等宏,则可以修改uboot代码自带的跟网络相关的环境变量。

/*#define CONFIG_BOOTARGS        "root=ramfs devfs=mount console=ttySA0,9600" */
#define CONFIG_ETHADDR        00:40:5c:26:0a:5b
#define CONFIG_NETMASK          255.255.255.0
#define CONFIG_IPADDR        192.168.1.20
#define CONFIG_SERVERIP        192.168.1.30
#define CONFIG_GATEWAYIP    192.168.1.1

(2)更改完成后如果环境变量还是原来的,是正常的。因为原来之前在uboot执行过saveenv,因此环境变量已经被保存到iNand中的ENV分区中去了。uboot启动后校验时iNand的ENV分区中的环境变量是正确的,因此会优先加载。我们在uboot源代码中修改的不过只是默认的环境变量,iNand中没有才会使用这份默认环境变量。

解决方案是擦除掉iNand中的那一份环境变量,然后迫使uboot启动时使用uboot代码中自带的这一份环境变量,就可以看到我们的更改值了。可以使用mmc write 0 30000000 11# 32(表示将DDR的0x30000000开头的一段内存中的内容写入iNand中的第17个扇区开始的32个扇区内,写入长度是32个扇区长度(16KB))来擦除iNand中的环境变量。

8.3、修改行提示符

#define CFG_PROMPT              "CHM210 $ "   /* Monitor Command Prompt       */

在这里插入图片描述

8.4、总结

(1)uboot移植关键在于对uboot的整体结构和过程的了解,了解之后修改移植就非常简单。

9、网卡驱动移植1

9.1、网卡芯片与开发板的连接方式

(1)SoC的SROM bank CSn1和网卡芯片的CS#引脚相连(SROM就是SRAM/ROM)。SoC的SROMController其实就是SoC提供的对外总线式连接SRAM/ROM的接口。如果SoC要外部外接一些SRAM/ROM类的存储芯片(或者伪装成SROM接口的芯片,譬如网卡芯片)就要通过SROM Controller来连接。网卡接在SROM中好处就是网卡芯片好像一个存储芯片一样被扩展在SoC的一个地址空间中,主机SoC可以直接使用一个地址来访问网卡芯片内部寄存器。
(2)网卡芯片内部寄存器使用相对地址访问。网卡芯片内部很多寄存器都有一个地址,这些地址从00H开始,但是实际上我们SoC不能用0地址去访问这个网卡的芯片内部寄存器。SoC访问网卡芯片00H寄存器时要使用的地址应该是:起始地址+00H,这里的起始地址就是网卡芯片接在SROM bankn中的bankn对应的基地址。在这里插入图片描述
在这里插入图片描述
(3)主机SoC上网,其实就是通过操控网卡芯片内部的寄存器、缓冲区等资源来上网的。也就是说其实SoC是不具有上网能力的,SoC是通过网卡芯片来间接上网的。
(4)总结:实际上也是一种总线式连接方式。优势是SoC内部不需要内置网卡控制器,所有的SFR全都在外部网卡芯片中,而且还可以通过地址直接访问(IO与内存统一编址),不用像Nand/SD接口一样使用时序来访问。
(5)从逻辑上来看,网卡更像是串口,而不像是SD/Nand,但跟串口还是有一些区别的。

9.2、原理图浏览

(1)210的SROM控制器允许8/16bit的接口,我们实际使用的是16位接口。在这里插入图片描述
(2)网线有8根线,但是实际只有4根有效通信线,另外4根都是GND,用来抗干扰的。4根通信线中管发送的有2根(Tx-和Tx+),管接收的有2根(Rx+和Rx-)。因为网线上传输的是差分信号。在这里插入图片描述
(3)网卡芯片有个CS#引脚,(CS就是chip select,片选信号,主机向CS发送有效信号则从机芯片工作,主机向CS发送无效信号则从机芯片不工作。),这个引脚要接主机SoC的片选信号引脚CSn1,主机S5PV210的每一个SROM bank中有一个片选信号CSn(n=0-5),从原理图可以看出,X210将DM9000的CS引脚接到了CSn1上,对应SROM bank1(推断出DM9000的总线地址基地址是0x88000000)。
(4)DM9000的CMD引脚接到了S5PV210的ADDR2引脚上。DM9000为了减少芯片引脚数,数据线和地址线是复用的(DATA0到DATA15这16根线是有时候做数据线传输数据,有时候做地址线传输地址的。什么时候做什么用就由CMD引脚决定。)通过查询数据手册知道:当CMD为高电平时对应传输是DATA,当CMD为低电平时对应传输为INDEX(offset,寄存器地址)。在这里插入图片描述
注明:这些引脚上的电平变化都是控制器自动的,不需要程序员手工干预。程序员所需要做的就是在配置寄存器值时充分考虑到硬件电路的接法,然后将正确的数值配置到正确的寄存器。

10、网卡驱动移植2

10.1、网卡驱动文件介绍

(1)uboot中本来就提供了很多网卡芯片的驱动程序,dm9000对应的驱动是uboot/drivers/net/下的dm9000x.c和dm9000x.h。这个驱动来自于linux kernel源代码。所以我们uboot中是移植而不是编写。
(2)这个驱动是linux内核中做好的,根本不用改动,可以在uboot中直接使用的。而且因为linux驱动设计的很合理(数据和代码是分开的,这里驱动主要是代码,数据是硬件寄存器的值,取决于我们芯片的接法。),所以驱动本身具有可移植性。这个就决定了我们移植DM9000驱动时这个驱动文件dm9000x.c和h不用动,要动的是寄存器的值,将寄存器的值配置好,然后将来在驱动中会使用到这些寄存器。

10.2、网卡移植的关键:初始化

(1)uboot在第二阶段的init_sequences中进行了一系列的初始化,其中就有网卡芯片的初始化。这个初始化就是关键,在这里只要将网卡芯片正确的初始化了,则网卡芯片就能工作(意思是网卡驱动dm9000x.c和dm9000x.h依赖于这里的初始化而工作)。
(2)网卡初始化代码地方在:

start_armboot
	init_sequence
		board_init
			dm9000_pre_init        这个函数就是驱动移植的关键

(3)dm9000_pre_init函数主要功能就是初始化DM9000网卡。这个初始化过程和我们开发板上DM9000网卡芯片的硬件连接方式有关。必须要结合开发板原理图来分析,从原理图分析信息,然后决定这个函数怎么编写。
(4)原来的代码是三星的工程师根据三星的开发板SMDKV210的硬件接法来写的程序,我们要根据自己的开发板的硬件接法去修改这个程序,让网卡在自己开发板上能工作。
(5)#define DM9000_16BIT_DATA这个宏用来表示DM9000工作在16位总线模式下。根据分析原理图,可以看到开发板上DM9000确实工作在16位模式下。
在这里插入图片描述
在这里插入图片描述
(6)从三星版本的代码中可以看出,它操作的是bit20-bit23,对照数据手册中寄存器定义,可以看出三星的开发板DM9000是接在Bank5上的。而我们接在bank1上的,因此我们需要操作的bit位是bit4-bit7在这里插入图片描述
在这里插入图片描述
(7)总结:三个寄存器的修改。主要是三星的开发板DM9000接在bank5,我们接在了bank1上,因此要做一些修改。在这里插入图片描述

10.3、基地址的配置等

(1)之前说过,驱动分为2部分:代码和数据。代码不用动,数据要修改。
(2)CONFIG_DM9000_BASE是DM9000网卡通过SROM bank映射到SoC中地址空间中的地址。这个地址的值取决于硬件接到了哪个bank,这个bank的基地址是SoC自己定义好的。譬如我们这里接到了bank1上,bank1的基地址是0x88000000,因此要将这个宏修改过来。在这里插入图片描述
(3) 访问DM9000的寄存器的途径主要是由CMD和CS#这两个引脚的连接方式来确定的,CS#是DM9000的片选引脚,CMD引脚在芯片手册中描述如下:
CMD pin :
Command Type
When high, the access of this command cycle is DATA port
When low, the access of this command cycle is INDEX port
DM9000的CS#引脚接的是SoC的SROM Bank1(物理地址为0x88000000~0x8FFFFFFF)的片选引脚CSn1,CMD引脚则接的是SoC地址总线的ADDR2位。DM9000_IO表示DM9000的INDEX端口地址,直接就是CONFIG_DM9000_BASE;DM9000_DATA表示DM9000的DATA端口地址,因为DM9000芯片的CMD引脚接到了ADDR2,因此这里要+4(0b100,对应ADDR2)在这里插入图片描述
确定了DM9000的INDEX和DATA端口地址,我们就有了访问网卡的途径。读网卡寄存器的方法是:先向INDEX端口写入寄存器的地址,再从DATA端口读出该寄存器的值。写寄存器的方法与之对应:先向INDEX端口写入寄存器的地址,再向DATA端口写入值。#通过I/O端口读写网卡寄存器的方法在驱动中由ior()、iow()这来两个函数实现。
(4)本来这样配置就完了,重新编译运行网卡就应该工作了。但是实际测试发现不工作,要怎么样修改呢?修改方式是将CONFIG_DM9000_BASE改成0x88000300就工作了。
问题:这个0x300从哪里来的?我得出的感觉最靠谱的解释是:跟DM9000网卡芯片型号版本有关,我认为这个0x300是DM9000网卡本身的问题,他本身的内部寄存器是以0x300开始,而非从0地址开始。

11、网卡驱动如何工作

11.1、网卡移植代码实践

(1)经过上述实践,网卡驱动移植成功。在这里插入图片描述

11.2、linux系统中网卡驱动的典型工作方式

(1)在linux系统中,网卡算是一个设备,这个设备驱动工作后会生成一个设备名叫ethn(n是0、1、2、····)(无线网卡名字一般叫wlan0、wlan1····)。然后linux系统用一些专用命令来操作网卡,譬如ifconfig命令。
(2)linux下的应用程序如何使用网卡驱动来进行网络通信?最通用的方法就是socket接口。linux系统中有一系列的API和库函数,提供了一个socket编程接口,linux下的应用程序都是通过socket来实现上网的,socket内部就是间接调用的网卡驱动实现网络通信的。
(3)linux设计是非常完备的,应用层和驱动层是严格分离的。写网络编程应用层的人根本不用管驱动,只要会用socket接口即可;写底层驱动的人根本不用管应用层,只要面向linux的网络驱动框架模型即可。

11.3、uboot中网卡驱动的工作方式

(1)uboot本身是一个裸机程序,是一个整体,没有分为应用层和驱动层。
(2)按照逻辑来说,ping这样的命令实现的代码就是网络API实现的应用程序,像dm9000x.c和dm9000x.h这样的代码属于驱动程序。所以在uboot中这些东西是揉在一起的,应用是直接调用驱动实现的。也就是说ping命令内部是直接调用了dm9000的网卡驱动中的函数来实现自己的。

11.4、以ping命令为例查找代码验证分析

(1)ping命令是uboot的众多命令之一,ping命令实现的函数叫do_ping
(2)函数的调用关系:

do_ping
	NetLoop
		PingStart
			PingSend
				ArpRequest
					eth_send(dm9000x.c中)

(3)验证了11.3中说的uboot中应用程序(ping)调用驱动程序(dm9000x.c)的方式。这就是一种直接调用的方式。

12、使用自己移植的uboot启动内核

12.1、解决问题:当前uboot不能启动内核

(1)用同样的方法(使用tftp 0x30008000 zImage-qt;将内核下载到0x30008000, 然后bootm 0x30008000启动内核),分别使用自己移植的uboot和使用九鼎移植版本的uboot去启动内核,发现九鼎移植版本的可以启动,但是自己移植的不可以启动。到此就可以断定内核是没有问题的,自己移植的uboot有问题,不能启动内核。
(2)做基本检查:首先怀疑是机器码不对。命令行输入bdinfo查看命令码,结果和九鼎移植版本的uboot对比发现machid都是0x998(2456),而且九鼎的uboot是能启动内核的,说明机器码就是2456没错。
(3)后来发现,之前实验时将串口2改为了串口0,而内核zImage-qt的串口输出在串口2,所以在串口0看不到内核的启动信息,所以只要将串口0改回串口2,在smdkv210single.h中修改串口编号就可以了。如果内核还不能启动,说明可能是传参的问题,需要到smdkv210single.h中查看有没有定义bootm传参需要的那几个宏。

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

移植三星官方的uboot到x210 的相关文章

  • iOS APP测试方法和测试工具 大揭秘

    随着移动互联网的发展 xff0c 以及智能手机的普及 xff0c 各种各样的 APP 层出不穷 xff0c 大家可以数一数自己手机上安装的 APP xff0c 随随便便几十个 xff0c 上百个 xff0c 所以现在 APP 测试的需求也越
  • oracle sql loader命令与ctl写法

    xfeff xfeff sql loader 的特点 oracle自己带了很多的工具可以用来进行数据的迁移 备份和恢复等工作 但是每个工具都有自己的特点 比如说exp和imp可以对数据库中的数据进行导出和导出的工作 xff0c 是一种很好的
  • 史上最全的字符串格式化方法,学这些就够用了

    一 思考 1 什么是字符串格式化 将变量 xff08 对象 xff09 的值填充到字符串中 在字符串中解析Python表达式 对字符串进行格式化显示 左对齐 右对齐 居中对齐保留数字有效位数 2 你学过的字符串格式化方式有哪些 字符串格式化
  • Linux实现黑客帝国效果,超级简单

    MATRIX是Linux的环境下黑客帝国风格的屏保 xff0c 绿色的字母在屏幕上刷刷如雨水落下 xff0c 偶尔看看能回忆起程序猿的黑客梦 首先要在网上找到CMATRIX安装包 xff0c 然后安装 xff0c 需要的话找柠檬班小米 xf
  • 10年互联网职场过来人给测试专业大学生的学习建议

    改进学习方法 xff0c 就如改进你的测试方法一样 不管你面临的是什么环境和挑战 xff0c 值得期许的 就值得去尝试 1 关于学习 在学校期间以专业课为主 xff0c 专业理论知识越扎实 xff0c 后期实践才越容易深入理解且上手更快 对
  • 使用 GitHub Copilot 自动化测试

    代码完成并不是什么新鲜事 像 IntelliSense 这样的工具已经允许开发人员通过尝试自动完成他们正在编写的函数或语句的名称来提高工作效率 xff0c 但是可用的工具只有一定程度的实际 智能 可用 随着 GitHub 的 Copilot
  • 想让你的接口自动化测试更加有效? 这个统计方法必须掌握

    覆盖率概念 接口自动化测试是现代软件开发中不可或缺的一环 xff0c 它能够帮助开发团队自动化执行测试用例 xff0c 以快速而准确地发现并修复软件缺陷 而覆盖率统计则是在测试执行完成后 xff0c 帮助测试团队了解哪些代码路径被覆盖了 x
  • 大小端字节序详解

    目录 引文 大小端介绍 xff08 1 xff09 什么是大端小端 xff08 2 xff09 为什么有大端和小端 xff08 3 xff09 笔试题讲解 引文 在开始正文之前 xff0c 我想先问一下大家 xff0c 内存中是怎样存放一个
  • 【C库函数】strcat函数详解

    目录 strcat 函数原型 参数讲解 返回值详解 函数讲解 xff08 1 xff09 源字符串和目标字符串都必须以 39 0 39 结束 xff08 2 xff09 目标空间必须足够大 xff0c 能容纳下源字符串的内容 xff08 3
  • CAN协议

    CAN xff08 Controller Area Network xff09 是一种常见的串行总线通信协议 xff0c 用于在汽车 工业控制和其他应用中传输数据 它是一种高效 可靠 安全的通信协议 xff0c 具有广泛的应用 下面是CAN
  • 串口协议简介

    串口协议是一种基于串行通信的数据传输协议 它通过串口接口将数据以串行的方式传输 串口协议通常包括物理层 数据链路层和应用层三个部分 xff0c 其中物理层主要定义了串口接口的电气特性 xff0c 数据链路层定义了数据的传输方式和错误检测机制
  • CAN协议总线仲裁原理:数据发送权争夺

    CAN总线仲裁原理是指在多个CAN节点同时发送数据时 xff0c 如何避免冲突 并选择一个节点作为发送者 CAN总线的仲裁原理基于一个分布式仲裁机制 xff0c 它可以快速而可靠地确定哪个节点可以获得总线控制权 xff0c 从而发送数据 C
  • Spring整合JMS(一)——基于ActiveMQ实现

    1 1 JMS简介 JMS的全称是Java Message Service xff0c 即Java消息服务 它主要用于在生产者和消费者之间进行消息传递 xff0c 生产者负责产生消息 xff0c 而消费者负责接收消息 把它应用到实际的业务需
  • getopt函数详解

    getopt 函数是C语言中一个常用的命令行参数解析函数 xff0c 它可以方便地解析命令行输入的参数 xff0c 以便程序对不同参数进行不同的处理 本文将详细讲解getopt 函数的使用方法和注意事项 xff0c 分点阐述如下 xff1a
  • UCOSIII

    UCOSIII简介 xff1a UCOSIII是MicroC OS III的改编版本 xff0c 主要是用于实时系统中的任务调度 xff0c 它是嵌入式系统中应用最广泛的操作系统之一 用函数说明 xff1a 1 OSInit 用于初始化UC
  • UCOSIII-任务创建-库函数

    创建任务 xff1a OSTaskCreate OS TCB amp StartTaskTCB 任务控制块 xff08 amp 传地址 xff09 CPU CHAR 34 start task 34 任务名字 xff08 可以随便写 xff
  • ucosiii-常用api

    uC OS III 提供了许多 API 函数 xff0c 可以根据需要选择使用 以下是一些常用的 uC OS III API 函数 xff1a 任务管理 API OSTaskCreate xff1a 创建一个新任务 xff1b OSTask
  • windows 清除 .git 文件夹

    有时我们需要将 git 管理项目中的 git文件夹删除 xff0c 但是如果项目太多 xff0c 一个一个手动删除太麻烦 xff0c 这时候可以用 bat 批处理文件删除 xff0c 具体操作如下 桌面 右击 新建文本文档 xff0c 此时
  • Your anti-virus program might be impacting your build performance.解决方案

    Your anti virus program might be impacting your build performance 解决方案 在使用 AndroidStudio 时 xff0c 经常会弹出框提示 xff1a Your ant
  • init.rc 启动 shell 脚本 开机执行脚本 init.rc执行shell脚本

    Android 重启时执行 shell 脚本 init rc 执行 shell 脚本 最近有个需求 xff0c 需要生成系统的默认配置 xff0c 使得在系统开机后 xff0c 直接读取已经配置好的文件 当时想的解决方案是 xff0c 在编

随机推荐

  • android 10 自定义系统服务接口给app调用

    Android 安卓自定义系统服务 最近有个需求 xff0c 要增加系统服务 xff0c 生成第三方 jar 包提供给第三方应用调用 xff0c 而且 jar 包必须用特定的包名 xff0c 最后生成的 jar 包不能包含 framewor
  • Android java.lang.NoSuchMethodError: No virtual method ;or its super classes (declaration of

    修改 AOSP 源码后调用错误 java lang NoSuchMethodError No virtual method in class or its super classes declaration of appears in sy
  • 谷歌使用技巧 20 招

    第一招 xff1a 使用搜索栏下方的 Tab 栏 xff0c 可以快速搜索 视频 图片 新闻第二招 xff1a 使用引号 xff0c 默认搜索会去搜索包含输入关键字的结果 xff0c 用 34 holy shit 34 会去进行整句搜索第三
  • 索引算法原理解析(B-tree以及磁盘存储原理)

    刚开始学习的时候 xff0c 百度去查 xff0c 但发现好多说得太复杂不好理解 xff0c 结合各个文章总结一下 xff08 建议大概看文字 xff0c 不理解不要紧 xff0c 然后再看图的执行步骤然后在结合文字 xff0c 这样一切就
  • C语言-----结构体内存对齐

    结构体内存对齐规则 xff1a 第一个成员在结构体变量偏移量为0 的地址处 其他成员变量要对齐到某个数字 xff08 对齐数 xff09 的整数倍的地址处 对齐数 61 编译器默认的一个对齐数与该成员大小中的较小值 vs中默认值是8 Lin
  • dpi计算 density 取值范围

    PPI DPI计算公式 Density 61 sqrt span class token punctuation span span class token punctuation span span class token car wp
  • Repo 流程

    First repo init creates the repo directory clones the git repository https android googlesource com tools repo to repo r
  • *** buffer overflow detected ***: terminatedAborted (core dumped)解决

    在执行一个程序的时候出现了下面的这个错误 xff0c 明明在Ubuntu下面已经编译好了 xff0c 执行的时候除了问题 xff0c 于是换了台电脑尝试还是一样 buffer overflow detected terminated Abo
  • 虚拟机Ubuntu远程启动Jetson nano RVIZ图形界面失败

    INFO 1644470251 178517 Rosapi started map manager 6 process has finished cleanly log file home jetson ros log fb3115c6 8
  • YOLOv5训练自己的数据集实现视频的识别

    写在前面 我本来是使用这个模型进行手写签名的定位 xff0c 但是因为比赛的主办方原因 xff0c 数据不允许公开 xff0c 所以我使用动物世界的一段开头视屏来制作我的数据集 这整个模型跑通的过程中 xff0c 我参考了很多不错的博客 x
  • stm32---OLED(SSD1306)

    OLED模块优缺点 优点 xff1a 尺寸小 xff0c 分辨率高 xff0c 低压3 3V就可工作 xff0c 支持多种接口方式 xff0c 该模块提供了总共4种接口包括 xff1a 6800 8080两种并行接口方式 4线的穿行SPI接
  • stm32---ADC模数转换

    ADC xff1a 模数转换器 xff0c 将模拟信号 xff08 0v xff0c 3v xff0c 6v等 xff09 转换为表示一定比例电压值的数字信号 xff08 1 xff0c 2 xff0c 3等 xff09 STM32F10x
  • stm32---DMA

    DMA 全称Direct Memory Access xff08 直接存储器访问 xff09 xff0c 把一个地址空间的值 复制 到另一个地址空间 xff0c 使用DMA传输方式无需CPU直接控制传输 xff0c 通过硬件为RAM和IO设
  • STM32通信---CAN

    一 CAN是什么 xff1f CAN xff0c 全称为 Controller Area Network xff0c 即控制器局域网 xff0c 是一种多主方式的串行通讯总线 xff0c 是国际上应用最广泛的现场总线之一 二 CAN的起源
  • 计算机网络学习笔记3-抓包工具的使用

    Wireshark win64 2 6 2的使用 安装一路next 在发送数据之前 运行抓包工具 当数据发送之后 记得停止抓包
  • linux运行java项目的shell脚本

    bin bash WORKDIR 61 home xiaohong Baowen cd WORKDIR WEB INF classes for file in 96 ls WORKDIR WEB INF lib jar 96 do CLAS
  • 基于STM32F103的智能门禁系统

    0 前言 本人大二软工菜鸟一枚 xff0c 大神不喜勿喷 1 功能演示 点这里功能演示 2 硬件选型 序号名称备注1STM32F103C8T6开发板用于主控2AS608指纹模块指纹解锁3RFID RC522射频模块刷卡解锁40 96寸四针O
  • uboot的环境变量相关源码分析

    一 uboot的环境变量基础 1 1 环境变量的作用 1 让我们可以不用修改uboot的源代码 xff0c 而是通过修改环境变量就可以影响uboot运行时的一些特性 譬如说修改bootdelay环境变量就可以更改系统开机自动启动时倒计时的秒
  • uboot移植Linux-SD驱动代码解析

    一 uboot与linux驱动 1 1 uboot本身是裸机程序 1 狭义的驱动概念是指 xff1a 操作系统中用来具体操控硬件的代码叫驱动 广义的驱动概念是指 xff1a 凡是操控硬件的代码都叫驱动 2 裸机程序中是直接使用寄存器的物理地
  • 移植三星官方的uboot到x210

    1 移植前的准备工作 1 1 三星移植过的uboot源代码准备 1 三星对于S5PV210的官方开发板为SMDKV210 xff0c 对应移植的 uboot smdkv210 tar bz2 1 2 SourceInsight准备 1 移植