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

  • 相关阅读:
    HDU4628+状态压缩DP
    Javascript 去掉字符串前后空格的五种方法
    Javascript 数组之判断取值和数组取值
    ASP.NET MVC 出现错误 “The view 'XXX' or its master was not found or no view engine support”
    ASP.NET MVC 页面调整并传递参数
    ASP.NET MV3 部署网站 报"Could not load file or assembly ' System.Web.Helpers “ 错的解决方法
    ASP.NET MVC 控制器向View传值的三种方法
    CSharp 如何通过拼接XML调用存储过程来查询数据
    SQLServer : EXEC和sp_executesql的区别
    关于SQLServer2005的学习笔记—异常捕获及处理
  • 原文地址:https://www.cnblogs.com/linux-xin/p/8125988.html
Copyright © 2011-2022 走看看