zoukankan      html  css  js  c++  java
  • 高通 MSM8K bootloader之一: SBL1

    MSM8K Boot Flow 

                                  图1:

    高通MSM8K平台bootloader启动流程基本类似,但具体各平台,比如MSM8974、MSM8916、MSM8994等,会有微小区别。

    从上图,可以看出高通8K平台的boot过程非常不一般啊。相比MTK平台,或者高通7K平台,复杂了非常多。 下图是高通文档对启动流程的说明,

    已经很清楚了,我这边就直接贴出来啦。

                                       图2:

    系统上电后从RPM PBL启动到 APPS PBL 然后SBL1 ,再启动APPSBL 等等,整个过程看似非常复杂,但其实很多代码OEM厂家是看不到,也修改不了的。

    那我们需要我们做什么? 能做点什么呢? 呵呵!不会没事情做的。 SBL1和appsbl高通是有开放代码。

    本章我重点关注SBL1,且主要描述我认为重点的几方面:

    1、    CDT : Platform ID和DDR参数 

    2、 debug log :

    3、 download : msm8K 新平台软件download支持两种协议,sahara和firehose

    4、 ramdump :死机异常信息dump

    好的,下面将SBL1我比较关注的点调用流程总结成如下图,后面再针对关注点展开,逐个分析。

                               图3:

    二、CDT:Platform ID和DDR参数 

    1、CDT(Configuration Data Table ) 里到底有什么内容?

       参考下图,可知CDT包含CDB0: platform info信息和CDB1: DDR配置参数。
     
                    图4:
     
       platform info 包含平台id,主板的版本号,项目号等信息
              图5:
     
    CDB0: platform info 如下结构体表现:
    typedef PACKED struct
    {
      uint8                 nVersion;
      uint8                 nPlatform;      //这个是平台id,用于高通不同平台类型。我们不能去修改。
      uint8                 nHWVersionMajor;   //硬件版本号暂时没有使用,默认为0
      uint8                 nHWVersionMinor;
      uint8                 nSubtype;    // 默认为0没有用。我们可以用它来做项目区分   
      uint8                 nNumKVPS;
      PlatformInfoKVPSCDTType  aKVPS[];
    } PlatformInfoCDTType;
     

    参考如下文档和code:
    80-N3411-1_B_EEPROM_SW_CDT.pdf
    boot_images/core/boot/secboot3/hw/msm8916/boot_cdt_array.c

    boot_images/core/systemdrivers/platforminfo/src/PlatformInfo.c

    boot_images/core/boot/secboot3/scripts/cdt_generator.py

    boot_images/core/boot/secboot3/scripts/jedec_lpddr3_single_channel.xml

    2、CDB0: platform info信息有什么用处?

     上图3可以看到CDB0: platform info相关的代码调用有如下二函数:

    voidboot_config_data_table_init(bl_shared_data_type* bl_shared_data)
    {
      boot_log_message("boot_config_data_table_init, Start");
      boot_log_start_timer();
      
      /*populate configuration data table's info*/
      config_data_table_info.size = config_data_table_size;
      config_data_table_info.cdt_ptr = config_data_table;
       //get default config_data_table array from boot_cdt_array.c

      boot_update_config_data_table(&config_data_table_info);
      //read the cdt from eMMC and update the default config_data_table array


      /*put a pointer to the table info into sbl shared data so next sbl can access it*/
      bl_shared_data->sbl_shared_data->config_data_table_info = &config_data_table_info;
      
      boot_log_stop_timer("boot_config_data_table_init, Delta");
    }  //该函数获取到cdt,并存放在config_data_table_info


    void sbl1_hw_platform_smem(bl_shared_data_type* bl_shared_data)
    {
        .......

        if (eResult == DAL_SUCCESS) 
        {
          /*call the following API to store the platform id to DAL and SMEM*/
          boot_DalPlatformInfo_CDTConfigPostDDR(phPlatform, platform_id_cdb_ptr);

          //调用 PlatformInfo.c 中的PlatformInfo_InitSMem保存platform info 到smem.
          boot_DAL_DeviceDetach(phPlatform);
        }
      }
      
    }/* sbl1_hw_platform_smem() */

    //好了

    static DALResultPlatformInfo_InitSMem
    (
      PlatformInfoDrvCtxt *pDrvCtxt
    )
    {
       //申请共享内存区:SMEM_HW_SW_BUILD_ID
      pSMem = (DalPlatformInfoSMemType *)
        smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(DalPlatformInfoSMemType));
       ...............

     //保存platform info到共享内存
      pSMem->ePlatformType = pDrvCtxt->PlatformInfo.platform;
      pSMem->nPlatformVersion = pDrvCtxt->PlatformInfo.version;
      pSMem->nPlatformSubtype = pDrvCtxt->PlatformInfo.subtype;
      pSMem->bFusion = pDrvCtxt->PlatformInfo.fusion;
       .................

      return DAL_SUCCESS;

    } /* END PlatformInfo_InitSMem */

    花了这么多精力谈如何存platform info,得用啊?这些platform info在lk和kernel有何用呢?

    lk 根据platform id及subtype id匹配正确的dts,这样后面kernel也可以利用dts里的

    platform info。

    注:msm8916-mtp.dts 包含如下platform id & subtype id信息。

    {
    model = "Qualcomm Technologies, Inc. MSM 8916 MTP xxx";
    compatible = "qcom,msm8916-mtp", "qcom,msm8916", "qcom,mtp", "qcom,xxxx";
    qcom,board-id = <8 0x21>;   //platform id & subtype id
    };

    lk请参考这些函数,后面专门研究lk,再详细描述。

    platform_detect   //board.c , smem.h : enum platform_subtype 

    board_hardware_subtype //board.c , smem.h : enum platform_subtype 

    board_hardware_id   //board.c , smem.h : enum platform_subtype 

    dev_tree_get_entry_info  //dev_tree.c

    kernel请参考setup.c

    从上面CDT格式及代码分析,可以看出,如果不同项目cdt的nPlatform和nSubtype项配置成不同的值, 与dts 包含的platform id & subtype id信息进行匹配。就可以用来区分不同的项目。

    即:我们在项目开发过程中,同一个分支代码要进行多项目开发时,

    sbl、lk、kernel可以利用这些信息来区分不同项目,实现一套代码多项目配置目标。如下图:

       图6:

    总结:通过修改cdt和dts,sbl、lk、kernel阶段使用如下接口,可以将同一个branch代码中多项目区分出来!

    sbl_board_subtype      // sbl高通没有,自己开发一个接口

    board_hardware_subtype   // lk接口

    of_board_is_xxx     // kernel 接口

    3、CDB1:DDR参数的配置流程?

    cdt中还有一项重要内容是CDB1: DDR参数,下面看看如何利用这些参数进行ddr初始化的。

    ddr初始化涉及如下重要三函数:

    boot_procedure_func_type load_qsee_pre_procs[] = 
    {
      .......
      /* Copy the configure data table from eeprom */
      boot_config_data_table_init
      .......
      /* Configure ddr parameters based on eeprom CDT table data. */
      sbl1_ddr_set_params,   //  保存cdt ddr 参数到底层
      /* Initialize DDR */
      (boot_procedure_func_type)sbl1_ddr_init,    //初始化ddr
       .......

      /* Last entry in the table. */
      NULL 
    };

    下面重点介绍这三个函数:

         图7:

     cdt数据 config_data_table保存到config_data_table_info.cdt_ptr

          图8:

    sbl1_ddr_set_params调用ddr_set_params,将ddr参数保存到ddr_device_table。

    获取num_of_device保存到ddr_device_table_entry_num 。

     

       图9:

    sbl1_ddr_init 通过 HAL_SDRAM_Init调用到如下函数,

    HAL_SDRAM_Ram_Rank_Detection,========》cs auto detect 

    HAL_SDRAM_Ram_Size_Detection, =========> ram size auto detect by :row、col、bank、width , manufacture_id

    ddr_params_detection , ========》 two DDR chips auto detect 

    HAL_SDRAM_DPE_Update_AC_Paramenters  =========> update ddr timing with new DDR timing

     上图说明,通过ddr_params_detection 实现一个项目自动支持多种ddr timing的方法。

    好了,ddr timing就不再多说了,详细请阅读代码及参考文档:

    80-NJ172-1_A_LPDDR2_CUSTOMIZATION_FOR_MSM8x26_DEVICES.pdf

    三、Debug log

    坑跌的高通,MSM6K/7K平台,包括旧的MSM8K平台bootloader都不支持uart。
    需要自己添加uart debug log,否则只能连接jtag接口,使用Trace32调试。
    哎,Trace32那价钱,咱这贫民企,都调试不起啦。
     
    高通也赚了够多的,总算有良心,在MSM8916平台默认支持uart啦!
     
    好了,不骂高通了,看下面代码。
     
    void sbl1_main_ctl(boot_pbl_shared_data_type *pbl_shared)
    {
     
     。。。。。。。。。
     //sbl入口足够早的地方就开始log初始化。再前面就没法打印log了,就当作前面的代码不出错吧。
      
      /* Initialize boot logger and start the log timer */
      sbl1_boot_logger_init(&boot_log_data,
                            pbl_shared);
     
      。。。。。。。。。
    }
    sbl1_boot_logger_init调用boot_log_init进行ram log , timer ,uart 初始化。
    void boot_log_init(boot_log_init_data *init_data)
    {
      /*we must first set meta info becasue boot_log_init_ram and
       * boot_log_init_timer will use the meta info structure*/
      boot_log_set_meta_info(init_data->meta_info_start);
      boot_log_init_ram(init_data);  //初始化ram log
      boot_init_timer(init_data);        //初始化timer ,可用于打印sbl各阶段的启动时间
      boot_log_init_uart();                //初始化uart
    }
    /* boot_log_init */
     
    做完初始化的工作后,就可直接使用boot_log_message将log打印到ram和uart啦!
    使用方法参考:
      static char error_message[BOOT_ERROR_MSG_LEN];
      //自己将打印的信息格式化到自定义的buffer:error_message
          snprintf(error_message, BOOT_ERROR_MSG_LEN, 
                 "Error code %lx at %s Line %lu", err_code, filename_ptr, line);
          //打印log       
          boot_log_message(error_message);
     
    参考代码:
    boot_logger.c
    boot_logger_uart.c
    boot_logger_ram.c
    boot_logger_timer.c


    四、SW download

     待续:《高通 MSM8K bootloader之二: SBL1》

    五、Crash ramdump

     待续:《高通 MSM8K bootloader之二: SBL1》

    参考资料:

    80_NA157_7_C_MSM8974_Boot_Architecture_Overview.pdf

    80-NL239-1_A_MSM8916_Boot_Architecture_Overview.pdf

    80-N3411-1_B_EEPROM_SW_CDT.pdf

    80-NJ172-1_A_LPDDR2_CUSTOMIZATION_FOR_MSM8x26_DEVICES.pdf

  • 相关阅读:
    STM32中GPIO的8种工作模式
    robots.txt与搜索引擎
    关于《腾讯工具类APP的千年老二》的读后感
    PCB布线的操作步骤
    c语言数据库编程ODBC
    锂电池相关结构优势特点及其保护电路解析方案
    C语言中的#与##字符的作用
    PADS中Layer的描述说明
    吃了单片机GPIO端口工作模式的大亏——关于强推挽输出和准双向口(弱上拉)的实际应用
    Protel与PADS之间相关文件的转换
  • 原文地址:https://www.cnblogs.com/linux-xin/p/8125988.html
Copyright © 2011-2022 走看看