美文网首页BB-black开发板[Linux arm-v8]
TQ2440成功移植uboot2016.11解决Using dm

TQ2440成功移植uboot2016.11解决Using dm

作者: applecai | 来源:发表于2020-12-29 21:00 被阅读0次

    一,前言

    为什么我要把10年前买的TQ2440翻出来玩,原因很简单,因为上次am335上使用st7735s OLED芯片的不顺利,我把它归功于硬件环境。为了资源充分利用,TQ2440上面有原配的LCD屏幕,虽然屏幕FPC接头坏了,还有有50PIN引出脚,我去买个灰排连接线即可。另外TQ2440有摄像头接口,之后考虑引出线来玩吧。
    另外,最主要的吸引我的地方是TQ2440用新的uboot及5.4内核的网上不多。主要我猜测2440芯片内核架构arm920已经淘汰了,芯片也不生产了,所以没有什么人用。这样到能达到另外一个学习效果,可以理解为当有新的芯片研发出来,我应该如何移植。虽然2410内核已经有了,我基于它修改下即可。反正关于内核移植也算是基础,需要花费些时间的,主要是我喜欢从无到有的感觉,bring up对我来说是一件很有成就感的事情。学习过程中一切都很顺利按步骤操作就完成的,基本上学不到东东的。之前了解到openEuler说是为了避免不同arm芯片的适配而做的OS,这样像我这样DIY者,不是少了从0到1的乐趣吗?所以若要尝鲜的话,我情愿选择鸿蒙os来玩。

    二,选方案

    言归正传,我本次就拿现有资源TQ2440开发板来建立平台。
    uboot选2016年11月的,因为太新的uboot2440相关内容都删除了。
    kernel就选5.4保持内核一致性。
    文件系统就用之前的buildroot。

    三,计划

    先bring up起来,完成uboot,要有串口,有网络能挂载内核,nandflash能正常使用即可。然后就是kernel和启动文件系统,最后是我比较关注的LCD和Camera驱动了。
    移植方法主要就是参考2410来添加2440。当然网上先查了下2410和2440的区别主要是时钟不同。我没有去仔细看spec,方法是遇到问题再解决。另外我的目的不是熟悉某款外设或2440芯片,所以我不会去仔细看spec,会先从网上找修改寄存器的方案。我的目的是掌握一套移植的方法论。这样将来其它芯片我顶多是花费些时间看看spec这个说明书而已。另外一个目的就是满足我的好奇心,我要玩一下,基本的nandflash或norflash的驱动协议我顺便也复习下,但是我了解到现在flash貌似都是spi驱动了,哈哈~

    四,第一步初版uboot移植

    有了计划,就开始执行了呗!

    1. \board\samsung中将如下几个文件都简单看下,然后将2410关键字替换为2440。我还修改了维护者,哈哈~
    SMDK2440 BOARD
    M:  Apple Cai <xxx@xxx.com.cn>
    S:  Maintained
    F:  board/samsung/smdk2440/
    F:  include/configs/smdk2440.h
    F:  configs/smdk2440_defconfig
    

    看到上面的文档了吗?那么按此文档修改\include\configs里面从smdk2410.h复制一份命名为smd2440.h,然后我从头到尾看了下,先修改了默认ip地址。然后flash在TQ2440用的是EON的EN29LV160AB。是32Mbit,共35个扇区。说有h文件修改后,flash的初始化和读写扇区函数也要修改。头文件中的CONFIG_SYS_FLASH_CFI宏定义就可以让我搜索到drivers/mtd/cfi_flash.c因为一开始要读取厂商号及芯片id,我参考源码中其它的flash的思路自己也添加了。主要是jedec_table里面添加如下,我看了下其他版本的flash相关c代码都是很多switch case,用数组设计真的比较好。我现在的代码风格基本也倾向于通过数组来填充了。逻辑与数据分离嘛!把能公用的都抽象出来,是一种很好的设计。

    #ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16  // by apple
        {
            .mfr_id     = (u16)EON_ALT_MANU,
            .dev_id     = EON29LV160AB,
            .name       = "EON 29LV160AB",
            .uaddr      = {
                [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
            },
            .DevSize    = SIZE_2MiB,
            .CmdSet     = P_ID_AMD_STD,
            .NumEraseRegions= 4,
            .regions    = {
                ERASEINFO(0x2000,1),  /* 6  blocks */
                ERASEINFO(0x1000,2), /* 10 blocks */
                ERASEINFO(0x4000,1), /* 15 blocks */
                ERASEINFO(0x8000,31),  /* 1  blocks */
            }
        },
    #endif
    

    网络修改

    #if 0
    #define CONFIG_CS8900       /* we have a CS8900 on-board */
    #define CONFIG_CS8900_BASE  0x19000300
    #define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */
    #else  // by apple
    #define CONFIG_DRIVER_DM9000
    #define CONFIG_DM9000_BASE    0x20000000
    #define DM9000_IO      CONFIG_DM9000_BASE           
    #define DM9000_DATA  (CONFIG_DM9000_BASE+4)
    #endif
    

    board/samsung/smdk2440/smdk2440.c修改时钟

    #elif (FCLK_SPEED == 1)     /* Fout = 400MHz */ 
    #define M_MDIV  0x5c//0xA1
    #define M_PDIV  0x1//0x3
    #define M_SDIV  0x1//0x1
    #endif
    

    然后就是board_early_init_f中串口波特率修改。网上找的。这个找点,那个找到。还有很多步骤我没有写出来,因为在网上搜索下,原来蛮多参考资料的。然后基本上频率,串口,nandflahs,norflash,dram都完成了。dm9000也可以正常识别。我的第一步目标就是制作一个uboot能通过jlink下载到norflash后正常启动。

    五,遇到的难搞的问题

    就剩下最后一个网卡问题ping不通,会卡在Using dm9000 device
    然后我通过万能的printf进行跟踪,发现set_icmp_header中变量赋值也会不通过,于是网上我觉得很可能和我的时钟配置有关,因为网上说若频率不对也ping不通的。然后我把start.s的时钟相关重新找个blog进行了参考,原来在start.s设置过了时钟,board_early_init_f的前3行设置时钟相关则需要删除的。此时我还添加了很多printf调试信息,于是发现ping通了。简单的测试了下setenv也都可以保存到nandflash或norflash中。因为我一开始设置的是nor-flash,后来配置改成了nand-flash来保存环境变量。
    但是后来发现一个问题,我把自己加的打印的调试信息删除后,又卡在了Using dm9000 device难道是printf添加后导致时序中添加了延时,时钟不正确导致的卡住,又难道是重定向导致的。还需要继续研究下。另外,我也了解了dm9000的时序,dram的时序配置在low_level_init.S里面我基本上copy了TQ原来1.1.6版本的配置,所以时序应该是对的,除非HCLK源头不对。开发板上已经找到了clockout1和clockout0可以用来测试clock的设置,但是我先不想测试,引脚连线很麻烦,我先假设HCLK没有问题的。那么剩下唯一让我怀疑的就是重定向问题,所以我准备从dram下载代码来运行准备对比下。
    修改了system base地址为0x32000000,#define CONFIG_SKIP_LOWLEVEL_INIT配置下,norflash烧录了原版的boot后,通过tftp 0x32000000 u-boot.bin;go 0x32000000来启动我的uboot。发现初始化阶段就卡住了

    WARNING: Caches not enabled
    initcall: 3200ed08 (relocated to 33f33d08)
    initcall: 3200ee58 (relocated to 33f33e58)
    initcall: 3200ee24 (relocated to 33f33e24)
    using memory 0x33b25000-0x33f25000 for malloc()
    

    搜索源码,估计就是malloc_bin_reloc();导致的问题,我修改宏定义关闭CONFIG_SYS_MALLOC_CLEAR_ON_INIT后解决。

    void mem_malloc_init(ulong start, ulong size)
    {
        mem_malloc_start = start;
        mem_malloc_end = start + size;
        mem_malloc_brk = start;
    
        debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
              mem_malloc_end);
    #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT
        memset((void *)mem_malloc_start, 0x0, size);
    #endif
        malloc_bin_reloc();
    }
    

    成功初始化到控制台后,我继续测试ping服务器,出现了data abort。

    --- net_loop Entry
    --- net_loop UDP handler set (00000000)
    --- net_loop ARP handler set (00000000)
    --- net_loop timeout handler cancelled
    Trying dm9000
    dm9000 i/o: 0x20000300, id: 0x90000a46 
    DM9000: running in 16 bit mode
    MAC: 00:11:22:33:44:aa
    --- NetState set to 0
    --- net_loop Init
    Using dm9000 device
    --- net_loop timeout handler set (33f85be4)
    sending ARP for 192.168.0.110
    data abort
    pc : [<33f84174>]    lr : [<33f85c80>]
    sp : 33b24d38  ip : 000000aa  fp : 33f2d69c
    r10: 33fed360  r9 : 33b24ef0  r8 : 33fed360
    r7 : 00000000  r6 : 33fefa84  r5 : 0000000e  r4 : 33fed3ae
    r3 : 14000045  r2 : 1100a8c0  r1 : 6e00a8c0  r0 : 33fed3ae
    Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
    Resetting CPU ...
    

    乍一看,我理解是访问了非法地址。在ubuntu中进行uboot反汇编。
    arm-linux-gnueabihf-objdump -D u-boot > u-boot.s
    然后从调试信息也可以看到reloc offset的地址,我直接bdinfo看起来漂亮些。

    SMDK2440 # bdinfo
    arch_number = 0x000000A8
    boot_params = 0x30000100
    DRAM bank   = 0x00000000
    -> start    = 0x30000000
    -> size     = 0x04000000
    eth0name    = dm9000
    ethaddr     = 00:11:22:33:44:aa
    current eth = dm9000
    ip_addr     = 192.168.0.17
    baudrate    = 115200 bps
    TLB addr    = 0x33FF0000
    relocaddr   = 0x33F25000
    reloc off   = 0x01F25000
    irq_sp      = 0x33B24EE0
    sp start    = 0x33B24ED0
    SMDK2440 # 
    

    0x33f84174-0x01F25000=3205f174找到如下3205f174: e58d2000 str r2, [sp]就是把r2的值写入到sp中。但是想起来pc指向的地址-8才是当前正在执行的命令,因为3级流水线,取指令,翻译指令,执行指令。需要3个步骤。所以我理解应该是str r3, [r0]导致了跑飞,也就是r3的值写入r0的值为地址的存储空间出错。33fed3ae也是在uboot正常范围内的地址呀,为什么会报错呢?后来在源码的doc帮助文件夹搜索了下data abort关键字,发现地址未对齐则会产生data abort错误,原来不是写到非法地址导致的跑飞,而是写到未对齐的地址导致的跑飞。我就找下源码,看看地址从哪里来的,看了ping_send函数,uchar *net_tx_packet作为bss段的全局指针,他就是地址的来源,然后再加上eth_hdr_size。所以我先打印出来,看看size是多少,若size是对齐的,那么就是*net_tx_packet没对齐。后来百度搜索了下居然也有人遇到这样的问题,他找到的是cpu_init_crit中对SCTLR(System Control Register)进行了设置,就是要检查对齐。至此,我预估我的问题也解决了。

    3205f164 <net_set_ip_header>:
    3205f164:   e92d4013    push    {r0, r1, r4, lr}
    3205f168:   e59f3070    ldr r3, [pc, #112]  ; 3205f1e0 <net_set_ip_header+0x7c>
    3205f16c:   e5803000    str r3, [r0]
    3205f170:   e59f306c    ldr r3, [pc, #108]  ; 3205f1e4 <net_set_ip_header+0x80>
    3205f174:   e58d2000    str r2, [sp]
    
    static int ping_send(void)
    {
        uchar *pkt;
        int eth_hdr_size;
    
        /* XXX always send arp request */
    
        debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &net_ping_ip);
    
        net_arp_wait_packet_ip = net_ping_ip;
    
        eth_hdr_size = net_set_ether(net_tx_packet, net_null_ethaddr, PROT_IP);
        pkt = (uchar *)net_tx_packet + eth_hdr_size;
    
        set_icmp_header(pkt, net_ping_ip);
    ......
    }
    

    分析完问题有了调试思路后,我先将net_tx_packet地址和eth_hdr_size打印出来,size是14,不是按16对齐。

    ending ARP for 192.168.0.110
    net_tx_packet=0x33fed3a0,eth_hdr_size=14,pkt=0x33fed3aenet_set_ip_header 1
    data abort
    pc : [<33f840c4>]    lr : [<33f840b8>]
    sp : 33b24d48  ip : 00000065  fp : 33f2d628
    r10: 33fed360  r9 : 33b24f08  r8 : 33fed360
    r7 : 00000000  r6 : 33fefa84  r5 : 0000000e  r4 : 33fed3ae
    r3 : 14000045  r2 : 00000001  r1 : 00014000  r0 : 00000014
    Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
    Resetting CPU ...
    

    那么我就在14个字节的结构体中添加了2个dummy字节,结果都是len bad,我猜测应该是解析要用到这些结构体,所以我不能破坏结构体对象的结构。不能随意添加。
    sending ARP for 192.168.0.110
    net_tx_packet=0x33fed3a0,eth_hdr_size=16,pkt=0x33fed3b0net_set_ip_header 1
    net_set_ip_header 3
    net_set_ip_header 4
    ARP broadcast 1
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x800
    Got IP
    len=0, v=00
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x800
    Got IP
    len bad 75 < 51446
    packet received
    Receive from protocol 0x800

    于是ping_send中添加`net_tx_packet = (uchar *)net_tx_packet+2;`,反正目的就是补2个字节,让最后pkt是16的整数倍。原来xxx+14字节后=33fed3ae,再加2个字节不就是33fed3b0了。反正我不管在nandflash启动还是norflash启动,这个pkt的地址总是33fed3ae。所以我理解,我固定的加了个字节应该每次ptk都会变成33fed3b0。如下,从0x32000000的sdram运行成功啦!
    ```c
    SMDK2440 # ping 192.168.0.110
    --- net_loop Entry
    --- net_loop UDP handler set (00000000)
    --- net_loop ARP handler set (00000000)
    --- net_loop timeout handler cancelled
    Trying dm9000
    dm9000 i/o: 0x20000300, id: 0x90000a46 
    DM9000: running in 16 bit mode
    MAC: 00:11:22:33:44:aa
    --- NetState set to 0
    --- net_loop Init
    Using dm9000 device
    --- net_loop timeout handler set (33f85b44)
    sending ARP for 192.168.0.110
    net_tx_packet=0x33fed3a2,eth_hdr_size=14,pkt=0x33fed3b0net_set_ip_header 1
    net_set_ip_header 3
    net_set_ip_header 4
    ARP broadcast 1
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x800
    Got IP
    len=40, v=46
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x800
    Got IP
    len=73, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=332, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=149, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=332, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=332, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=40, v=46
    packet received
    Receive from protocol 0x800
    Got IP
    len=308, v=45
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x800
    Got IP
    len=73, v=45
    packet received
    Receive from protocol 0x800
    Got IP
    len=237, v=45
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x800
    Got IP
    len=308, v=45
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x800
    Got IP
    len=73, v=45
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x800
    Got IP
    len=237, v=45
    packet received
    Receive from protocol 0x806
    Got ARP
    packet received
    Receive from protocol 0x86dd
    packet received
    Receive from protocol 0x800
    Got IP
    len=308, v=45
    packet received
    Receive from protocol 0x86dd
    ARP broadcast 2
    packet received
    Receive from protocol 0x806
    Got ARP
    Got ARP REPLY, set eth addr (c4:34:6b:01:04:10)
    packet received
    Receive from protocol 0x800
    Got IP
    len=28, v=45
    --- NetState set to 2
    --- net_loop UDP handler set (00000000)
    --- net_loop ARP handler set (00000000)
    --- net_loop timeout handler cancelled
    --- net_loop Success!
    host 192.168.0.110 is alive
    

    好了,我把自己加的注释和#define DEBUG全部删除后也能成功ping通。然后我又改成直接jlink烧录到到norflash启动也成功了,第一步uboot的5大基本项完成咯!这说明norflash中它不会报错data abort,但是其实他也发生了数据没对齐,但是他发生了为什么不会跳入那个data abort中断打印log呢?这个问题之后我再研究,我先要研究下重定向,说不定点有关系。
    如下是从norflash启动的信息,能ping通。

     U-Boot 2016.11 (Dec 29 2020 - 19:47:29 +0800)
    
    CPUID: 32440001
    FCLK:      400 MHz
    HCLK:      100 MHz
    PCLK:       50 MHz
    DRAM:  64 MiB
    WARNING: Caches not enabled
    initr_malloc end
    Flash: 1 MiB
    NAND:  256 MiB
    In:    serial
    Out:   serial
    Err:   serial
    Net:   dm9000
    Hit any key to stop autoboot:  0 
    SMDK2440 # ping 192.168.0.110
    dm9000 i/o: 0x20000300, id: 0x90000a46 
    DM9000: running in 16 bit mode
    MAC: 00:11:22:33:44:aa
    Using dm9000 device
    host 192.168.0.110 is alive
    SMDK2440 # 
    

    六,源码工程

    我先备份在本地我自己建设的svn上,路径为G:\TQ2440\ubootu-boot-2016.11_v1.tar.gz,之后都完成了再上传到我的gitee。

    相关文章

      网友评论

        本文标题:TQ2440成功移植uboot2016.11解决Using dm

        本文链接:https://www.haomeiwen.com/subject/xcmqoktx.html