BeagleBone Black QNX6.6 BSP中IPL的完善

QNX提供的BBB BSP有6.5和6.6两个版本。6.5使用uboot引导,6.6提供了IPL引导程序。下载地址如下
http://community.qnx.com/sf/wiki/do/viewPage/projects.bsp/wiki/TiAm335Beaglebone

6.6这个IPL引导程序有问题,编译后将images目录的IPL重命名为MLO放置到SD卡中,引导后串口无任何信息。。
研究后发现这个IPL是不完整的,他至少缺失了串口引脚复用的配置,所以串口肯定没任何信息……
而且他的IPL是不支持emmc引导的。。
不知道qnx发布这个bsp的时候,这个ipl究竟做没做过测试?!引脚复用都没有就放?

通过参考uboot程序代码,研究下来,终于完善了这个IPL。主要补充的有:
1.串口可以正常打印信息
2.原ipl只支持sd卡引导,现在可以从EMMC引导
3.修复了timer没初始化的bug。
4.可以自动识别当前启动介质。

尤其是第3个,简直是挫!连timer都没初始化就用delay函数,导致的后果就是引导emmc的时候卡死。
这个BSP真的是漏洞百出,看来qnx对开源硬件是不怎么上心。。
下面给出代码修改的具体内容吧

位置src\hardware\ipl\board\am335x

1.新增am335x_pinmux.h,从bsp别的目录复制而来
2._start.s做如下修改
_start:
    mov     r1, r0  //<<<<<<<<<<<新增这行,将BOOT_PARAM传入main的第二参数 US.26.1.12.2
3.board.c做如下修改
新增 #include "am335x_pinmux.h"
powerdomain_clocks_en函数修改,添加了UART0和UART1,调整了顺序
static void powerdomain_clocks_en(void)
{
    /*
     * Power domain wake up transitions
     * Must make its interface clock run before using the peripheral
     */
    out32(AM335X_CM_WKUP_CLKSTCTRL,     2);
    out32(AM335X_CM_WKUP_UART0_CLKCTRL, 2);
    out32(AM335X_CM_PER_UART1_CLKCTRL,  2);
    out32(AM335X_CM_PER_L3_CLKSTCTRL,   2);
    out32(AM335X_CM_PER_L4LS_CLKSTCTRL, 2);
    out32(AM335X_CM_PER_L4FW_CLKSTCTRL, 2);
    out32(AM335X_CM_PER_L3S_CLKSTCTRL,  2);
}
peripheral_clocks_en修改,添加了TIMER3和MMC1
static void peripheral_clocks_en(void)
{
    /* Enable the module clock */
    out32(AM335X_CM_PER_TIMER2_CLKCTRL, 2);

/* Select the Master osc (19.2 MHz) as Timer2 clock source */
    out32(AM335X_CLKSEL_TIMER2_CLK, 0x1);

/* Enable the module clock */
    out32(AM335X_CM_PER_TIMER3_CLKCTRL, 2);

/* Select the Master osc (19.2 MHz) as Timer2 clock source */
    out32(AM335X_CLKSEL_TIMER3_CLK, 0x1);

/* UART0 */
    out32(AM335X_CM_WKUP_UART0_CLKCTRL, 2);

/* ELM */
    out32(AM335X_CM_PER_ELM_CLKCTRL, 2);

/* i2c0 */
    out32(AM335X_CM_WKUP_I2C0_CLKCTRL, 2);

/* MMC 0 */
    out32(AM335X_CM_PER_MMC0_CLKCTRL, 2);

/* MMC 1 */
    out32(AM335X_CM_PER_MMC1_CLKCTRL, 2);

/* Enable the control module though RBL would have done it*/
    out32(AM335X_CM_WKUP_CONTROL_CLKCTRL, 2);

while (in32(AM335X_CM_PER_TIMER2_CLKCTRL  ) != 2);
    while (in32(AM335X_CM_PER_TIMER3_CLKCTRL  ) != 2);
    while (in32(AM335X_CM_WKUP_UART0_CLKCTRL  ) != 2);
    while (in32(AM335X_CM_PER_ELM_CLKCTRL     ) != 2);
    while (in32(AM335X_CM_WKUP_I2C0_CLKCTRL   ) != 2);
    while (in32(AM335X_CM_WKUP_CONTROL_CLKCTRL) != 2);
}
添加函数init_pinmux
static void init_uart0_pin_mux(void)
{
    out32(conf_uart0_rxd        , (MODE(0) | PULLUP_EN | RXACTIVE));    /* UART0_RXD  */
    out32(conf_uart0_txd        , (MODE(0) | PULLUDEN ));                /* UART0_TXD  */
}

static void init_mmc1_pin_mux(void)
{                                                                        
    out32(conf_gpmc_ad7         , (MODE(1) | RXACTIVE));             /* [P8  4] MMC1_DAT7  */
    out32(conf_gpmc_ad6         , (MODE(1) | RXACTIVE));             /* [P8  3] MMC1_DAT6  */
    out32(conf_gpmc_ad5         , (MODE(1) | RXACTIVE));             /* [P8 22] MMC1_DAT5  */
    out32(conf_gpmc_ad4         , (MODE(1) | RXACTIVE));             /* [P8 23] MMC1_DAT4  */
    out32(conf_gpmc_ad3         , (MODE(1) | RXACTIVE));             /* [P8  6] MMC1_DAT3  */
    out32(conf_gpmc_ad2         , (MODE(1) | RXACTIVE));             /* [P8  5] MMC1_DAT2  */
    out32(conf_gpmc_ad1         , (MODE(1) | RXACTIVE));             /* [P8 24] MMC1_DAT1  */
    out32(conf_gpmc_ad0         , (MODE(1) | RXACTIVE));             /* [P8 25] MMC1_DAT0  */
    out32(conf_gpmc_csn1        , (MODE(2) | RXACTIVE));             /* [P8 21] MMC1_CLK   */
    out32(conf_gpmc_csn2        , (MODE(2) | RXACTIVE));             /* [P8 20] MMC1_CMD   */
}

void init_pinmux()
{
    init_uart0_pin_mux();
init_mmc1_pin_mux();
}
修改 init_am335x 函数,调用init_pinmux,并把powerdomain_clocks_en提前
void init_am335x( )
{
    int count = LDELAY;

/* WDT1 is already running when the bootloader gets control
     * Disable it to avoid "random" resets
     */
    wdt_disable();

init_pinmux();

powerdomain_clocks_en(); //enable_basic_clocks

/* Get Timer and UART out of reset */
    /* UART softreset */
    out32(UART_SYSCFG, in32(UART_SYSCFG) | 0x02);
    while(( (in32(UART_SYSSTS) & 0x1) != 0x1) && count--);

/* Disable smart idle */
    out32(UART_SYSCFG, in32(UART_SYSCFG) | (1<<3));

/* We use UART0 as debug output */
    init_seromap(AM335X_UART0_BASE, 115200, 48000000, 16);

init_timer(AM335X_TIMER2_BASE);
    init_am335x_ddr();

interface_clocks_en();
    peripheral_clocks_en();

init_edma();
}
4.main.c修改
添加外部引用如下,初始化timer3,给delay函数用的
extern void omap_timer_enable(unsigned long, unsigned long);

ipl_boot_menu函数修改,新增E选项,EMMC

IPL_BootOpt_t ipl_boot_menu()
{
    char    opt;

unsigned tmp_addr, tmp_val;

while (1) {
        ser_putstr("\nCommand: \n");
        ser_putstr("Press 'S' for SERIAL download, using the 'sendnto' utility to download file qnx-ifs .\n");
        ser_putstr("Press 'M' for SD CARD download, file qnx-ifs assumed.\n");
        ser_putstr("Press 'E' for EMMC download, file qnx-ifs assumed.\n");
        ser_putstr("Press 'r' followed by physical address to read memory\n");
        ser_putstr("Press 'w' followed by write address, followed by new value to write to memory\n");

opt = ser_getchar();

switch (opt) {
        case 'M':
        case 'm':
            return (IPL_BOOT_SD);
        case 'E':
        case 'e':
            return (IPL_BOOT_EMMC);
        case 's':
        case 'S':
            return (IPL_BOOT_SERIAL);
        case 'R': case 'r':
            ser_putstr((char *)"Enter physical address to read: 0x");
            tmp_addr = get_uint(AM335X_UART0_BASE);
            ser_putstr((char *)"\n Value of 0x");
            ser_puthex(tmp_addr);
            ser_putstr((char *)" is: ");
            ser_puthex(in32(tmp_addr));
            ser_putstr((char *)"\n");
            continue;
        case 'W': case 'w':
            ser_putstr("Enter physical address to write: 0x");
            tmp_addr = get_uint(AM335X_UART0_BASE);
            ser_putstr("\nEnter value (8-bits): 0x");
            tmp_val = get_uint(AM335X_UART0_BASE);
            *(unsigned char*)tmp_addr = (unsigned char)(tmp_val&0xff);
            continue;
        }

ser_putstr("Unrecognized option\n");
    }
    return 0;
}

sdmmc_load_file函数修改,新增参数devno用于选择mmc0或mmc1,两个设备的io基地址不一样,dma通道也不一样,还有就是初始化timer3作为delay定时器,否则sdmmc内部的delay函数会卡死。

static int sdmmc_load_file (unsigned devno, unsigned address, const char *fn){
    sdmmc_t            sdmmc;
    int                status;
    omap_edma_ext_t dma_ext0 = {
        .dma_pbase = AM335X_EDMA0_CC_BASE,
        .dma_chnl = 25
    };
    omap_edma_ext_t dma_ext1 = {
        .dma_pbase = AM335X_EDMA0_CC_BASE,
        .dma_chnl = 3
    };

if(devno == 0)
{
//sd card
omap_sdmmc_init_hc(&sdmmc, AM335X_MMCHS0_BASE, 192000, SDMMC_VERBOSE_LVL_0, OMAP_SDMMC_EDMA, &dma_ext0);
}
else
{
//emmc
omap_sdmmc_init_hc(&sdmmc, AM335X_MMC1_BASE, 192000, SDMMC_VERBOSE_LVL_0, OMAP_SDMMC_EDMA, &dma_ext1);
}

omap_timer_enable(AM335X_TIMER3_BASE, 19200000); //for omap_nano_delay
    if (sdmmc_init_sd(&sdmmc)) {
        ser_putstr("SD/MMC card init failed\n");
        status = SDMMC_ERROR;
        goto done;
    }

ser_putstr("Load QNX image ");
    ser_putstr(fn);
    ser_putstr(" from SDMMC...\n");

fat_sdmmc_t    fat = {
        .ext = &sdmmc,
        .buf1 = fat_buf1,
        .buf1_len = FAT_FS_INFO_BUF_SIZE,
        .buf2 = fat_buf2,
        .buf2_len = FAT_COMMON_BUF_SIZE,
        .verbose = 3
    };

if (fat_init(&fat)) {
        ser_putstr("Failed to init fat-fs\n");
        status = SDMMC_ERROR;
        goto done;
    }

status = fat_copy_named_file((unsigned char *)address, (char *)fn);

done:
    sdmmc_fini(&sdmmc);

#if defined (DEBUG_BOOT_TIMING)
    omap_timer_curr("IFS loading from SDMMC", TIMING_MILLI_SECOND);
#endif

return status;
}

main函数修改,新增了BOOT_PARAM参数,是从start.s传来的,用于判断当前的启动介质,然后继续启动qnxifs,判断失败再显示启动菜单。

typedef struct _BOOT_PARAM{
uint32_t Reserved;
uint32_t pMemBootDesc;
uint8_t CurrBootDevice;
uint8_t ResetReason;
uint8_t Reserved2;
}BOOT_PARAM, *PBOOT_PARAM;

char *GetBootDeviceStr(PBOOT_PARAM pBootParam)
{
switch(pBootParam->CurrBootDevice)
{
case 0:
return "VOID";

case 1:
return "XIP MUX1 Memory";

case 2:
return "XIPWAIT MUX 1";

case 3:
return "XIP MUX2 Memory";

case 4:
return "XIPWAIT MUX 2";

case 5:
return "NAND";

case 6:
return "NAND with I2C";

case 8:
return "SD CARD";

case 9:
return "EMMC";

case 0xB:
return "SPI";

case 0x41:
return "UART0";

case 0x44:
return "USB";

case 0x46:
return "CPGMAC0";
}
return "N/A";
}

int main(int argc, char *argv[])
{
PBOOT_PARAM pBootParam = (PBOOT_PARAM)argv;
    unsigned image;
    IPL_BootOpt_t bootOpt;

init_am335x();

ser_putstr((char *)"\n\n\033[41;37m-QNX Neutrino IPL for AM335x BeagleBone Black Board-\033[0m\n\n");
ser_putstr("Current Boot Device: ");
ser_putstr(GetBootDeviceStr(pBootParam));
ser_putstr("\n\n");

image = QNX_LOAD_ADDRESS;

if(pBootParam->CurrBootDevice == 8)
{
bootOpt = IPL_BOOT_SD;
}
else if (pBootParam->CurrBootDevice == 9)
{
bootOpt = IPL_BOOT_EMMC;
}
else
{
bootOpt = ipl_boot_menu();
}

while (1) {
        switch (bootOpt) {
            case IPL_BOOT_SD:
                ser_putstr("\nload image from SD CARD ...\n");

if (sdmmc_load_file(0, image, "QNX-IFS") != 0) {
                    ser_putstr("load QNX-IFS from SD CARD failed\n");
                    goto print_boot_menu;
                }
                break;

case IPL_BOOT_EMMC:
                ser_putstr("\nload image from EMMC ...\n");

if (sdmmc_load_file(1, image, "QNX-IFS") != 0) {
                    ser_putstr("load QNX-IFS from EMMC failed\n");
                    goto print_boot_menu;
                }
                break;

case IPL_BOOT_SERIAL:
                ser_putstr("Send IFS image through serial now...\n");

if (image_download_ser(image) != 0) {
                    ser_putstr("Download image failed\n");
                    goto print_boot_menu;
                }

ser_putstr("Download ok...\n");

/* get remaining bytes */
                while (ser_poll())
                    ser_getchar();

break;

default:
                goto print_boot_menu;
        }

if (bootOpt == IPL_BOOT_SERIAL) {
            image = image_scan_2(image, image + MAX_SCAN, 0);
        } else {
            image = image_scan_2(image, image + MAX_SCAN, 1);
        }

if (image != 0xffffffff) {
            ser_putstr((char *)"\nFound image @ 0x");
            ser_puthex(image);
            ser_putstr((char *)"\n");

image_setup_2(image);

ser_putstr((char *)"\nJumping to startup @ 0x");
            ser_puthex(startup_hdr.startup_vaddr);
            ser_putstr((char *)"\n\n");
            image_start_2(image);

/* Never reach here */
            return 0;
        } else {
            ser_putstr((char *)"Image_scan failed...\n");
        }

print_boot_menu:
       bootOpt = ipl_boot_menu();
    }

return 0;

}

用IPL启动比uboot稍微快一些,最后给个串口日志

-QNX Neutrino IPL for AM335x BeagleBone Black Board-

Current Boot Device: EMMC

load image from EMMC ...
Load QNX image QNX-IFS from SDMMC...
Partition entry 0:
        Boot Indicator: 0x00000080
        Partition type: 0x0000000E
        Begin C_H_S:    0 1 1
        END C_H_S:      63 32 96
        Start sector:   2048
        Partition size: 196608

Found image @ 0x84000008

Jumping to startup @ 0x81003718

DDR  DPLL in Lock mode:
  DDR  clock 400 Mhz [400/1]
Disp DPLL in Lock mode:
  Disp clock 200 Mhz [200/1]
MPU  DPLL in Lock mode:
  MPU  clock 500 Mhz [500/1]
PER  DPLL in Lock mode:
  PER  clock 192 Mhz [960/5]
CORE DPLL in Lock mode:
  M4 CORE clock 100 Mhz [1000/10]
  M5 CORE clock 125 Mhz [1000/8]
  M6 CORE clock 250 Mhz [1000/4]
Not a BeagleBone??
CPU0: L1 Icache: 512x64
CPU0: L1 Dcache: 512x64 WB
CPU0: L2 Dcache: 4096x64 WB
CPU0: VFP-d32 FPSID=410330c3
CPU0: NEON MVFR0=11110222 MVFR1=00011111
CPU0: 413fc082: Cortex A8 rev 2 720MHz
Loading IFS...done
Jumping to QNX

System page at phys:80011000 user:fc404000 kern:fc404000
Starting next program at vfe046d48
cpu_startnext: cpu0 -> fe046d48
VFPv3: fpsid=410330c3
coproc_attach(10): replacing fe076700 with fe075f8c
coproc_attach(11): replacing fe076700 with fe075f8c
Welcome to QNX Neutrino 6.5.0 SP1 on the Texas Instruments BeagleBone (ARMv7 Cortex-A8 core) - Board
Starting MMC/SD driver...
Path=0 - TI OMAP3 MMCHS
 target=0 lun=0     Direct-Access(0) - MMC:254 MMC04G Rev:
Path=0 - TI OMAP3 MMCHS
 target=0 lun=0     Direct-Access(0) - SD:3 SL16G Rev: 8.0
mount: Can't mount /fs/emmcp0 (type dos)
mount: Possible reason: Invalid argument
mount: Can't mount /fs/emmcp1 (type qnx6)
mount: Possible reason: Invalid argument
starting I2C driver...
starting WDT reset utility...
changing thread parameters
AM335X Watchdog: No timeout specified, using 2x kicktime = 30000 ms
phy_base=0x44e35000 size=0x00000064
starting Board ID driver...
stop timer
Setting OS Clock from on-board RTC
Starting USB OTG Host driver...
Starting SPI driver...
Starting network driver...
starting leds driver...
Starting inetd daemon
#

BeagleBone Black QNX6.6 BSP中IPL的完善相关推荐

  1. WINCE BSP中source文件中的宏定义

    在WinCE BSP中会看到很多sources文件,一般会和源代码放在同一个目录,当然不是绝对的.这些sources文件里面就是定义了一些宏,主要用于告诉Build.exe在编译源代码的时候应该如何编 ...

  2. WinCE BSP中的DAT文件介绍

    作者:ARM-WinCE DAT文件用于在WinCE启动的时候,定义文件系统的结构,也就是定义有哪些文件夹,哪些文件在什么位置等.每次冷启动的时候,Filesys模块会根据.dat文件中的内容来创建目 ...

  3. 简单介绍一下BSP中的dirs文件和sources文件(WinCE

    一.dir文件: DIRS=          \      drivers   \      kernel    \      gwe       \      eboot dir文件用来指定需要编 ...

  4. MES系统中如何构建完善的质量追溯管理?

    质量追溯管理是MES系统的一项核心业务,本文将为大家详细介绍:在MES系统中,是如何构建完善的质量追溯管理. 什么是追溯?为什么需要追溯管理? 追溯的原意是追踪溯源,根据某一线索去分析追踪事情发生的来 ...

  5. Android中apk加固完善篇之内存加载dex方案实现原理(不落地方式加载)

    一.前言 时隔半年,困扰的问题始终是需要解决的,之前也算是没时间弄,今天因为有人在此提起这个问题,那么就不能不解决了,这里写一篇文章记录一下吧.那么是什么问题呢? 就是关于之前的一个话题:Androi ...

  6. GAP4.7/4.10.2软件中尚不完善的有限环功能

    GAP4没有与IdGroup对应的IdRing命令: 例如: for j in [1..2] do for i in [1..11] do R:=DirectSum(SmallRing(4,i),Sm ...

  7. 《嵌入式系统 - RT-Thread开发笔记》手把手教你使用RT-Thread制作GD32 RISC-V系列BSP

    熟悉RT-Thread的朋友都知道,RT-Thread提供了许多BSP,但不是所有的板子都能找到相应的BSP,这时就需要移植新的BSP.RT-Thread的所有BSP中,最完善的BSP就是STM32系 ...

  8. 开发板移植RTOS操作系统,RTOS操作系统适配开发板整理大全

    文章目录 一.单片机/嵌入式有无操作系统的区别 二.操作系统时的分层架构图 三.移植FreeRTOS到小熊派开发板(STM32L431RC) 1. 硬件准备 2. 下载FreeRTOS源码 2.1. ...

  9. wince中的BSP工程的相关文件介绍

    一.pbcxml分析         每一个BSP都有一个工程文件,比如MyBSP.pbcxml,里面描述了BSP的信息.下面就来介绍一下BSP的pbcxml文件. 文件的大致格式应该是这样的: &l ...

最新文章

  1. 与Susan Fowler探讨生产就绪微服务之问答
  2. python打包和添加数据文件_python使用grpc,并打包成python模块
  3. Django Views(视图函数)
  4. [学习笔记] 单位根反演
  5. Linux上静态库和动态库的编译和使用
  6. 腾讯TAD Sim2.0领跑自动驾驶仿真市场 双擎驱动构建新一代仿真平台
  7. 三维数据平滑处理_关于CAD三维对象建模
  8. 设计模式之禅读书笔记
  9. drbd mysql mha_浅谈秒级故障切换!用MHA轻松实现MySQL高可用(三)
  10. 教孩子编程python 语言 nostarch 下载_教孩子学编程 Python语言版
  11. 饥荒联机版服务器重置,饥荒联机版服务器重置世界 | 手游网游页游攻略大全
  12. MEGA这个网盘你可以拥有,超级良心
  13. 使用JavaScript开发IE浏览器本地插件实例
  14. 母亲节祝福html源码,有创意的母亲节祝福语大全
  15. 电源线噪声:共模干扰、差模干扰
  16. 最新版本的Google Chrome浏览器如何设置网页编码?
  17. latex中的希腊字母
  18. 最优化方法:八、多目标优化
  19. matlab批量改名字0001 0002,Matlab批量修改文件夹名字
  20. python怎样使用各个日期赤纬_Python常用的日期时间处理方法示例

热门文章

  1. python怎么处理数据_python panda怎么处理数据
  2. matlab龙格库塔法求通解,基于matlab及龙格库塔法求解布拉修斯方程.doc
  3. 大数据实训记录(二)
  4. php赋值权重_php权重计算方法代码分享
  5. Python 操作 MySQL 的5种方式
  6. java 分布式sql引擎_分布式SQL查询引擎 Presto 性能调优的五大技巧
  7. 如何解决海康网盘下载大文件中断问题?(idm更新链接)(貌似更新链接还是有问题)(用谷歌浏览器下载)
  8. 标记语言 编程语言 脚本语言分别有哪些? 区别是什么?
  9. VMware ubuntu虚拟机怎么设置分辨率?(全屏显示、大屏显示)
  10. IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boo