高通Android UEFI中的LCD分析(2):關鍵的函數


# 高通Android UEFI中的LCD分析(2):關鍵的函數

背景

在啟動流程分析中,看到了幾個經常出現的函數,這里實際分析一下有關的實現。以搞清楚高通做了什么,以及我們能做什么。

重要函數

MDPPlatformConfigure

基本上,只要是涉及顯示配置的有關工作都是由這個函數完成的。這個函數會在顯示的流程中多次調用。

路徑:BOOT.XF.4.1\boot_images\QcomPkg\SocPkg\KamortaPkg\Library\MDPPlatformLib\MDPPlatformLib.c

/**********************************************************************************************
*
* FUNCTION: MDPPlatformConfigure()
*
* DESCRIPTION:
*   The function is used to configure display, control power and brightness etc.
*
***********************************************************************************************/
MDP_Status MDPPlatformConfigure(MDP_Display_IDType eDisplayId, MDPPlatformConfigType eConfig, MDPPlatformParams *pPlatformParams)
{
    MDP_Status               eStatus               = MDP_STATUS_OK;
    MDPPlatformConfigType    ePlatformConfig;

    /* Static information, initial once during the first call */
    static bool32                 bInitFlag        = FALSE;
    static bool32                 bDetectPanel     = FALSE;
    static bool32                 bPanelConfigDone = FALSE;
    static MDPPlatformInfo        sPlatformInfo;
    static Panel_PowerCtrlParams  sPanelPowerCtrl;
    static MDPPlatformPanelInfo   sPlatformPanel;

    if (FALSE == bInitFlag) // 如果沒有初始化,就初始化一次,將所有的參數全部設為 0(FALSE)
    {
        MDP_OSAL_MEMZERO(&sPlatformInfo,    sizeof(MDPPlatformInfo));
        MDP_OSAL_MEMZERO(&sPanelPowerCtrl,  sizeof(Panel_PowerCtrlParams));
        MDP_OSAL_MEMZERO(&sPlatformPanel,   sizeof(MDPPlatformPanelInfo));
        bInitFlag = TRUE;
    }

    // 針對一些配置進行特殊處理,Get remapped platform configuration enum
    /* 
    	如果是  MDPPLATFORM_CONFIG_POWERUP 、MDPPLATFORM_CONFIG_POWERDOWN、 MDPPLATFORM_CONFIG_POWERDOWN
            MDPPLATFORM_CONFIG_SETBACKLIGHT、MDPPLATFORM_CONFIG_RESETPANEL
         那么: 在待會的 switch 中, 認為是 MDPPLATFORM_CONFIG_BYPASS而不執行(看下面的switch)
    */
    ePlatformConfig = PlatformConfigRemap(&sPlatformInfo, eConfig);

    // 讀取平台ID(如果之前沒有讀過,就不解釋這塊的內容了,典型的static 變量的用法) Read the platform ID once
    if (FALSE == sPlatformInfo.bPlatformDetected)
    {
        if (MDP_STATUS_OK == ReadPlatformIDAndChipID(&sPlatformInfo.sEFIPlatformType, &sPlatformInfo.sEFIChipSetId, &sPlatformInfo.sEFIChipSetFamily))
        {
            // 修改 uPanelOverride 為 實際的ID ,可以實現 固定 Panel
            UINT32 uPanelOverride = 0;  

            sPlatformInfo.bPlatformDetected = TRUE;

            // Read the display panel ID override, it will be checked later during detection
            if ((MDP_STATUS_OK  == MDP_Display_GetVariable_Integer (PANEL_OVERRIDE_STRINGNAME, &uPanelOverride)) &&
                (uPanelOverride  > 0))
            {
                sPlatformInfo.uPanelIdOverride = (uint32) uPanelOverride;
            }
        }
    }

    // 由於這個函數支持了很多種配置類型,因此統一在這里進行處理。
    switch (ePlatformConfig)
    {
        case MDPPLATFORM_CONFIG_SW_RENDERER:    ... break;
        case MDPPLATFORM_CONFIG_GETPANELCONFIG: ... break;
        case MDPPLATFORM_CONFIG_POWERUP:        ... break;
        case MDPPLATFORM_CONFIG_GETPANELDTINFO: ... break;
        case MDPPLATFORM_CONFIG_GETPANELLIST:   ... break;
        case MDPPLATFORM_CONFIG_GETPANELSUPPORTFLAGS: ... break;
        case MDPPLATFORM_CONFIG_POWERDOWN:      ... break;
        case MDPPLATFORM_CONFIG_SETBACKLIGHT:   ... break;
        case MDPPLATFORM_CONFIG_GETPANELID:     ... break;
        case MDPPLATFORM_CONFIG_GETPLATFORMINFO:... break;
        case MDPPLATFORM_CONFIG_RESETPANEL:     ... break;
        case MDPPLATFORM_CONFIG_SETGPIOSTATE:   ... break;
        case MDPPLATFORM_CONFIG_GETPANELXMLINFO:... break;
        case MDPPLATFORM_CONFIG_BYPASS:         ... break;
        {
                eStatus = MDP_STATUS_OK;// SW Render Bypass mode
        }
        break; 

        default:
            eStatus = MDP_STATUS_BAD_PARAM;
            break;
    }

    return eStatus;
}

我們重點看看switch中的處理內容。

MDPPLATFORM_CONFIG_SW_RENDERER

軟件渲染

/* Setup display panel configurations according to CDT */
if (FALSE == bPanelConfigDone) // 如果之前沒有執行過,則執行
{
    // 這個函數很重要
    SetupPlatformPanelConfig(eDisplayId, &sPlatformPanel, &sPlatformInfo, &bDetectPanel);
    bPanelConfigDone = TRUE;
    // 這個函數也很重要
    if (MDP_STATUS_OK != FindPanelIndex(&sPlatformPanel))
    {
        DEBUG((EFI_D_ERROR, "DisplayDxe: FindPanelIndex: No Panel Id=%d found\n", sPlatformPanel.eSelectedPanel));
    }
}

if (TRUE == sPlatformInfo.bSWRender)
{
    // SW Render mode is enabled already, just return the status
    // 如果已經進行過軟件渲染了,就寫回參數中。不需要做什么
    pPlatformParams->sPlatformInfo.bSWRender = TRUE;
}
else if ((EFI_PLATFORMINFO_TYPE_UNKNOWN == sPlatformInfo.sEFIPlatformType.platform) ||
         (EFI_PLATFORMINFO_TYPE_VIRTIO  == sPlatformInfo.sEFIPlatformType.platform) ||
         (TRUE == pPlatformParams->sPlatformInfo.bSWRenderOverrride) ||
         (TRUE == PcdGetBool(PcdDisplayForceSwRenderer)))
{
    // 為模擬設備和未知平台進行軟件渲染。Force SW render mode for emulation and unknown platforms
    pPlatformParams->sPlatformInfo.bSWRender = TRUE;
    // 保存 被 調用者 的 重寫請求 Store that an override has been requested by the caller
    sPlatformInfo.bSWRenderOverrride         = pPlatformParams->sPlatformInfo.bSWRenderOverrride;
    // 設置軟件渲染 為 開啟狀態 Cache that SW Rendering is enabled
    sPlatformInfo.bSWRender                  = TRUE;
    DEBUG((EFI_D_ERROR, "DisplayDxe: SW renderer mode enabled!\n"));
}
else
{
    // Force SW render mode off
    sPlatformInfo.bSWRender                  = FALSE;      
    // Report SW render mode is disabled
    pPlatformParams->sPlatformInfo.bSWRender = FALSE;
}
SetupPlatformPanelConfig
/*
* List of supported panels. The ones with XML data have UEFI support and the rest are only supported by kernel.  
* These are applicable for fastboot overrides of the panel configuration. 
*/
const PanelDTInfoType fastBootPanelList[] =
{
  /*Supported Panels*/
  PANEL_CREATE_ENTRY("panel_ili9891p_720p_vid",    
                     MDPPLATFORM_PANEL_ILI9881P_720P_VIDEO,	      
                     "qcom,mdss_dsi_ili9881p_720p_vid:",         
                     DISP_INTF_DSI, DISP_TOPOLOGY_CONFIG_NONE,  
                     DISP_TIMING_CONFIG_NONE,PLL_OVERRIDE_NONE, 
                     DISP_MODE_SINGLE_DSI,						       
                     DISP_MODE_SINGLE_DSI,							     
                     DISP_MODE_SINGLE_DSI),
  
  /*End of Table, DO NOT ADD PANEL BELOW THIS*/
  PANEL_CREATE_ENTRY("",
                     MDPPLATFORM_PANEL_NONE,
                     "",
                     DISP_INTF_NONE,
                     DISP_TOPOLOGY_CONFIG_NONE,
                     DISP_TIMING_CONFIG_NONE,
                     PLL_OVERRIDE_NONE,
                     DISP_MODE_NONE,
                     DISP_MODE_DUAL_DSI   | DISP_MODE_SKIP_BOOTLOADER,
                     DISP_MODE_DUAL_DSI   | DISP_MODE_SKIP_BOOTLOADER),
};

/**********************************************************************************************
*
* FUNCTION: SetupPlatformPanelConfig()
*
* DESCRIPTION:
*   The function can get the display panel that is being used.
*
***********************************************************************************************/
static void SetupPlatformPanelConfig(MDP_Display_IDType    eDisplayId,
                                     MDPPlatformPanelInfo *pPlatformPanel,
                                     MDPPlatformInfo      *pPlatformInfo,
                                     bool32               *pDetectPanel)
{
    PlatformDSIDetectParams *pPanelList = NULL;
    uint32                   uPanelCnt  = 0;
    uint32                   uPanelID   = 0;
	// 判斷 用於 強制填充的Panelid 是否儲存於 已知的 Panel列表中(fastBootPanelList)。有則 使用這個參數
    /*
    	注:如果需要添加 新Panel, 則添加 到 fastBootPanelList 中即可
    */
    if (TRUE == Panel_CheckOverride(eDisplayId, pPlatformPanel, pPlatformInfo))
    {
        //Use configuration set by panel override
    }
    else if (TRUE == pPlatformInfo->bSWRender)
    {
        //use dummy panel for sw rendering
        pPlatformPanel->eSelectedPanel = MDPPLATFORM_PANEL_NONE;
    }
    else
    {
        // Parse sub-revision specific info to determine the platform type
        uint32 uHardwareVersionSubtype = pPlatformInfo->sEFIPlatformType.subtype;

        // Report the proper information depending on the display.
        switch (pPlatformInfo->sEFIPlatformType.platform)
        {
            case EFI_PLATFORMINFO_TYPE_CDP:
            case EFI_PLATFORMINFO_TYPE_MTP:
            case EFI_PLATFORMINFO_TYPE_IDP:
            case EFI_PLATFORMINFO_TYPE_QRD:
            case EFI_PLATFORMINFO_TYPE_ATP:
                pPanelList = &uefiPanelList[0]; // Panel #0 -  TD4330 single dsi video fhd
                uPanelCnt  = PANEL_LIST_LENGTH(uefiPanelList);

                // If the panel ID override is enabled and within range, force that panel configuration.
                if ((pPlatformInfo->uPanelIdOverride & PANEL_OVERRIDE_ENABLE_MASK) &&
                    (PANEL_OVERRIDE_PANELID(pPlatformInfo->uPanelIdOverride) < uPanelCnt))
                {
                    pPanelList                     = &uefiPanelList[PANEL_OVERRIDE_PANELID(pPlatformInfo->uPanelIdOverride)];
                    DEBUG((EFI_D_ERROR, "DisplayDxe: Panel override enabled (Index: %d ID:0x%x)\n", PANEL_OVERRIDE_PANELID(pPlatformInfo->uPanelIdOverride), uPanelID));
                }
                else if (uHardwareVersionSubtype == 0x03)  //#panel 2: nt36525 truly video panel
                {
                    pPanelList = &uefiPanelList[2]; 
                    uPanelCnt  = 1;
                }
                else
                {
                    // No override and it is not SW render - select default panel for power up and trigger dynamic detection
                    *pDetectPanel                  = TRUE;
                }

                pPlatformPanel->eSelectedPanel   = pPanelList->eSelectedPanel;
                uPanelID                         = ((pPanelList->panelIdCommands[1].expectedReadback[0] << 8) |
                                                    pPanelList->panelIdCommands[2].expectedReadback[0]);
                pPlatformPanel->uPanelId         = uPanelID;
                pPlatformInfo->uPrimaryPanelId   = uPanelID;
                break;

            case EFI_PLATFORMINFO_TYPE_RUMI:
            default:
                pPlatformPanel->eSelectedPanel = MDPPLATFORM_PANEL_NONE;
                break;
        }
    }
}
FindPanelIndex

選擇Panel時序,

// BOOT.XF.4.1/boot_images/QcomPkgSocPkg/KamortaPkg/Library/MDPPlatformLib/MDPPlatformLibPanelConfig.h
MDPPlatformPanelFunctionTable sMDPPlatformPanelFunction[MDPPLATFORM_PANEL_MAX] =
{
  {
    MDPPLATFORM_PANEL_NONE,                               // ePanelSelected
    NULL, NULL, NULL, NULL, NULL, NULL, NULL
  },
  { /* Kamorta Panel */
      /* 注:如果需要添加 新Panel, 則添加 到 sMDPPlatformPanelFunction 中即可 */
    MDPPLATFORM_PANEL_ILI9881P_720P_VIDEO, 		          // ePanelSelected
    "Panel_ili9881p_720p_vid.xml",				  		  // pPanelXmlConfig
    Panel_Default_PowerUp,					              // pPanel_PowerUp
    Panel_Default_PowerDown,					          // pPanel_PowerDown
    Panel_Default_Reset,					              // pPanel_Reset
    Panel_Default_Peripheral_Power,				          // pPanel_Peripheral_Power
    Panel_Default_Brightness_Enable,				      // pPanel_Brightness_Enable
    Panel_Default_Brightness_Level				          // pPanel_Brightness_Level
  },
};

/**********************************************************************************************
*
* FUNCTION: FindPanelIndex()
*
* DESCRIPTION:
*   The function convert panel id into Index to panel table index
*
***********************************************************************************************/
static MDP_Status FindPanelIndex(MDPPlatformPanelInfo *pPlatformPanel)
{
    MDP_Status eStatus                        = MDP_STATUS_NO_RESOURCES;
    MDPPlatformPanelFunctionTable *panelTable = sMDPPlatformPanelFunction;
    UINT32  uIndex                            = 0;
  
    for (uIndex = 0; uIndex < MDPPLATFORM_PANEL_MAX; uIndex++)
    {
        if (panelTable == NULL)
        {
             break;
        }
        else if (panelTable->ePanelSelected == pPlatformPanel->eSelectedPanel)
        {
             pPlatformPanel->uSelectedPanelIndex = uIndex;
             eStatus     = MDP_STATUS_OK;
             break;
        }
        panelTable++;
    }
    return eStatus;
}

MDPPLATFORM_CONFIG_GETPANELCONFIG

獲取Panel配置,在這里可以支持雙屏: MDP_DISPLAY_PRIMARY / MDP_DISPLAY_EXTERNAL

// BOOT.XF.4.1\boot_images\QcomPkg\Include\Library\MDPSystem.h
/* PCD values for the PCD entry  gQcomTokenSpaceGuid.PcdExtDisplayType
 */
typedef enum
{
  PCD_EXTERNAL_DISPLAY_NONE    = 0,
  PCD_EXTERNAL_DISPLAY_DP      = 1,
  PCD_EXTERNAL_DISPLAY_HDMI    = 2,
  PCD_EXTERNAL_DISPLAY_MAX,
  PCD_EXTERNAL_DISPLAY_FORCE_32BIT = 0x7FFFFFFF
} ExternalDisplayPCDType;

static PlatformDSIDetectParams uefiPanelList[] = { 
    /* Panel #0 - ILI9881P 720P dsi video  */
    {  
       0x06,                                                  // uCmdType
       0x05,                                                  // total number of retry on failures
       {
         {{0xDA, 0x00},                                       // address to read ID1
         {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}     // expected readback
       }, 
       {{0xDB, 0x00},                                       // address to read ID2
       {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}     // expected readback
       },
       {{0xDC, 0x00},                                       // address to read ID3
       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}     // expected readback
       }
     },
     0,                                                     // Lane remap order {0, 1, 2, 3}
     NULL,                                                  // psPanelCfg (panel configuration)
     0,                                                     // uPanelCfgSize
     MDPPLATFORM_PANEL_ILI9881P_720x1440_VIDEO,             // eSelectedPanel 
     0                                                      // uFlags
    },
};

// Retrieve panel configuration (could be dependent on the interface)
switch (eDisplayId)
{
    case MDP_DISPLAY_PRIMARY: // 主屏
        {
            uint32                    uPanelID   = 0;
            PlatformDSIDetectParams  *pPanelList = &uefiPanelList[0];
            uint32                    uPanelCnt  = PANEL_LIST_LENGTH(uefiPanelList);
			// 如果之前成功識別過屏幕,則使用識別的屏幕,否則嘗試用 DynamicDSIPanelDetection 識別屏幕。
            if ((TRUE          == bDetectPanel) &&
                (MDP_STATUS_OK == DynamicDSIPanelDetection(&sPlatformPanel, &uPanelID, pPanelList, uPanelCnt)))
                // 重要的函數
            {
                /* Detected */
                sPlatformPanel.uPanelId       = uPanelID;
                sPlatformInfo.uPrimaryPanelId = uPanelID;

                /*
                 * need redo mapping eSelectedPanle to uSelectedPanleIndex in case of newer
                 * eSelectedPanel detected 
                 */
                // 之前提到這個函數,這里就不說了,只是用來判斷識別到的屏幕是否在支持的清單中
                if (MDP_STATUS_OK != FindPanelIndex(&sPlatformPanel))
                {
                    DEBUG((EFI_D_ERROR, "DisplayDxe: FindPanelIndex: No Panel Id=%d found\n", sPlatformPanel.eSelectedPanel));
                }
            }

            // Get the panel xml configurations. 
            // 解析 Panel對應的 xml 文件 作為 Panel 屬性(實際上這塊我不知道是怎么實現的)
            if(MDP_STATUS_OK != GetPanelXmlConfig(&sPlatformPanel))
            {
                pPlatformParams->sPlatformPanel.pPanelXMLConfig = (int8 *)dummy_xmldata;
                pPlatformParams->sPlatformPanel.uConfigSize     = sizeof (dummy_xmldata);
            }
            else // 如果解析 xml 不成功,那么就 使用 上次的 Panel 屬性 
            {
                /* Copy the panel configurations to pPlatformParams->sPlatformPanel */
                MDP_OSAL_MEMCPY(&pPlatformParams->sPlatformPanel, &sPlatformPanel, sizeof(MDPPlatformPanelInfo));
            }
        }
        break;

    case MDP_DISPLAY_EXTERNAL: // 拓展屏
        /* 
        從 PCD 獲取一個 32位的值,這個值現在是 0 : PCD_EXTERNAL_DISPLAY_NONE
	        BOOT.XF.4.1/boot_images/QcomPkg/QcomPkg.dec:762:  
	        	gQcomTokenSpaceGuid.PcdExtDisplayType|0|UINT32|0x00000809
        */
        switch (PcdGet32(PcdExtDisplayType))
        {
            case PCD_EXTERNAL_DISPLAY_DP: // 如果拓展屏 是 DP(沒懂)
                pPlatformParams->sDPConfig.bInvertPlugPolarity = DP_USBPlugInvertedOrientation();

                // For Nazgul, DP Phy lane to pad connection is the reverse of DP alt mode over usb type-c spec defined mapping
                pPlatformParams->sDPConfig.bReversePhyDataPath = TRUE;
                break;

            default:
                break;
        }
        break;

    default:
        break;
}
DynamicDSIPanelDetection

在這個函數中實現了多屏識別,通過讀取Panel的軟件ID實現。

/**********************************************************************************************
*
* FUNCTION: DynamicDSIPanelDetection()
*
* DESCRIPTION:
*   Detect DSI panels by doing a DSI read specific to each panels.
*   This function could be used as sample for OEM to detect DSI panels, 
*   it is not a complete implementation of all possible combinations of read
*   commands that could be needed for this detection.
*   
*   Return success only if a DSI panel was correctly detected and the information 
*   is updated in pPlatformParams->sPlatformPanel
*
***********************************************************************************************/
static MDP_Status DynamicDSIPanelDetection(MDPPlatformPanelInfo *pPlatformPanel, uint32 *puPanelID, PlatformDSIDetectParams *pPanelList, uint32 uPanelCnt)
{
  MDP_Status             Status                = MDP_STATUS_NOT_SUPPORTED;
  bool32                 bDumpPanelId          = FALSE;

  if (MDP_STATUS_OK == DSIDriver_MinimalInit())          // do minimal DSI init
  {
    uint8       panelID[PLATFORM_PANEL_ID_MAX_COMMANDS];
    uint32      uPanelIndex;
    bool32      bMatch         = FALSE;
    uint32      uPrevClkConfig = 0; 

    // go through all possible panels
    for (uPanelIndex = 0; uPanelIndex < uPanelCnt; uPanelIndex++)
    {
      uint8     readback[DSI_READ_READBACK_SIZE];
      uint32    readSize                          = sizeof(readback);
      int       iCommandIndex                     = 0;
      uint32    uClkConfig                        = (MDPPLATFORM_PANEL_DETECT_FLAG_CLOCK_FORCEHS & 
                                                     pPanelList[uPanelIndex].uFlags);

      // Check if there is any change in the clock config and set it accordingly
      if (uPrevClkConfig != uClkConfig)
      {
        if (MDP_STATUS_OK != DSIDriver_ConfigClockLane(uClkConfig))
        {
          DEBUG((EFI_D_ERROR, "Display: DSIDriver_ConfigClockLane failed\n"));
        }
        
        uPrevClkConfig = uClkConfig;
      }

      // Reprogram the DSI lane swap based on remap order
      if (MDP_STATUS_OK != DSIDriver_RemapLane(pPanelList[uPanelIndex].uLaneRemapOrder))
      {
        DEBUG((EFI_D_WARN, "Display: DSIDriver_RemapLane failed\n"));
      }

      // Allow debug option to scan panel registers (used to help generate a uniquie panel ID for detection)
      if (TRUE == bDumpPanelId)
      {
        DsiPanelDumpRegisters();
        // Dump just once
        bDumpPanelId = FALSE;
      }

      // clear the panel ID
      MDP_OSAL_MEMZERO(panelID, PLATFORM_PANEL_ID_MAX_COMMANDS);

      // for each possible panel ID read
      for(iCommandIndex = 0; iCommandIndex<PLATFORM_PANEL_ID_MAX_COMMANDS; iCommandIndex++)
      {
        uint32         uRetryCount = 0;

        // if read command is 0, then stop reading panel ID
        if ((0 == pPanelList[uPanelIndex].panelIdCommands[iCommandIndex].address[0]) &&
            (0 == pPanelList[uPanelIndex].panelIdCommands[iCommandIndex].address[1]) )
        {
          break;
        }
        // DSI read
        bMatch = FALSE;

        uRetryCount = 0;
        do
        {
          // clear the readback buffer
          MDP_OSAL_MEMZERO(&readback[0], readSize);
          readSize = sizeof(readback);
          Status = DSIDriver_Read(pPanelList[uPanelIndex].uCmdType, 
                                  pPanelList[uPanelIndex].panelIdCommands[iCommandIndex].address, 
                                  sizeof(pPanelList[uPanelIndex].panelIdCommands[iCommandIndex].address), 
                                  readback, 
                                  &readSize);

          uRetryCount++;
        } while((uRetryCount < pPanelList[uPanelIndex].uTotalRetry) && 
               ((MDP_STATUS_OK != Status)                           ||
                (0 == readSize)));

        if ((uRetryCount <= pPanelList[uPanelIndex].uTotalRetry) &&
            (0 != readSize))
        {
          // Read was successful, now check the data is what we expect
          if (0 == CompareMem(readback, pPanelList[uPanelIndex].panelIdCommands[iCommandIndex].expectedReadback, readSize))
          {
            panelID[iCommandIndex] = readback[0];    // store the first byte of readback as panel ID
            bMatch                 = TRUE;                       // mark one panel ID matched
          }
        }

        // if any panel ID is not matched, then go to detect next panel in the list
        if(FALSE == bMatch)
        {
          break;
        }
      }

      // if all panel IDs are matched for a specific panel, store settings and stop
      if(TRUE == bMatch)
      {
        // store matched panel configuration xml data

        pPlatformPanel->eSelectedPanel  = pPanelList[uPanelIndex].eSelectedPanel;

        // return the final combined panel ID
        *puPanelID = (panelID[0]<<16) | (panelID[1]<<8) | (panelID[2]);
        Status     = MDP_STATUS_OK;
        DEBUG((EFI_D_WARN, "Detected panel id:%08x\n", *puPanelID));
        break;
      }
      else
      {
        DEBUG((EFI_D_WARN, "Dynamic-Detected panel Failed\n"));
        Status = MDP_STATUS_FAILED;
      }
    }

    // Close the DSI context opened in DSIDriver_MinimalInit()
    DSIDriver_Close();
  }
  return Status;
}

MDPPLATFORM_CONFIG_POWERUP

對支持的平台類型進行上電:

  • 針對主屏,使用屏對應的上電時序
  • 針對拓展屏,使用默認的拓展屏上電策略。
switch (eDisplayId)
{
    case MDP_DISPLAY_PRIMARY:
        // Config based on the platform
        switch (sPlatformInfo.sEFIPlatformType.platform)
        {
            case EFI_PLATFORMINFO_TYPE_CDP:
            case EFI_PLATFORMINFO_TYPE_MTP:
            case EFI_PLATFORMINFO_TYPE_QRD:
            case EFI_PLATFORMINFO_TYPE_IDP:
            case EFI_PLATFORMINFO_TYPE_ATP:
                {
                    // Primary Power Sequence
                    if (NULL != sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_PowerUp)
                    {
                        if (MDP_STATUS_OK != (eStatus = sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_PowerUp(eDisplayId, &sPanelPowerCtrl)))
                        {
                            DEBUG((EFI_D_WARN, "DisplayDxe: Primary Power Up Sequence failed (%d)\n", eStatus));
                        }
                    }

                    if (NULL != sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Peripheral_Power)
                    {
                        if (MDP_STATUS_OK != (eStatus = sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Peripheral_Power(eDisplayId, &sPanelPowerCtrl, TRUE)))
                        {
                            DEBUG((EFI_D_WARN, "DisplayDxe: Secondary Power Up Sequence failed (%d)\n", eStatus));
                        }
                    }
                    break;

                }
            default:
                break;
        }
        break;

    case MDP_DISPLAY_EXTERNAL:
        // Config based on the platform
        switch (sPlatformInfo.sEFIPlatformType.platform)
        {
            case EFI_PLATFORMINFO_TYPE_CDP:
            case EFI_PLATFORMINFO_TYPE_MTP:
            case EFI_PLATFORMINFO_TYPE_QRD:
            case EFI_PLATFORMINFO_TYPE_IDP:
            case EFI_PLATFORMINFO_TYPE_ATP:
                eStatus = ExternalPanel_Default_PowerUp(eDisplayId, &sPanelPowerCtrl);
                break;

            default:
                break;
        }
        break;

    default:
        break;
}

MDPPLATFORM_CONFIG_GETPANELDTINFO

獲取支持的所有屏幕

if (NULL == pPlatformParams)
    eStatus = MDP_STATUS_BAD_PARAM;
else
    pPlatformParams->psPanelDTInfo = (PanelDTInfoType*)&fastBootPanelList;

MDPPLATFORM_CONFIG_GETPANELLIST

如果屏幕存在,則拷貝到輸出數組中。

uint32 i = 0;

while (MDPPLATFORM_PANEL_NONE != fastBootPanelList[i].ePanel)
{
    //Copy Panel ID
    pPlatformParams->sPanelList.ePanel[i] = fastBootPanelList[i].ePanel;
    i++; 
}

pPlatformParams->sPanelList.uCount = i;

MDPPLATFORM_CONFIG_GETPANELSUPPORTFLAGS

類似於MDPPLATFORM_CONFIG_GETPANELLIST,只是獲取的是對應的標志位。

//Lookup panel
int32 i = PANEL_LIST_LENGTH(fastBootPanelList) - 1;
while (0 <= i)
{
    if (pPlatformParams->sPanelSupport.ePanel == fastBootPanelList[i].ePanel)
    {
        if ((DISP_TOPOLOGY_CONFIG_NONE == pPlatformParams->sPanelSupport.uModeIndex) ||
            (pPlatformParams->sPanelSupport.uModeIndex > DISPLAY_MODE_MAX))
        {
            pPlatformParams->sPanelSupport.uFlags = fastBootPanelList[i].uModeFlags[0];
        }
        else
        {
            pPlatformParams->sPanelSupport.uFlags = fastBootPanelList[i].uModeFlags[pPlatformParams->sPanelSupport.uModeIndex-1];
        }
        break;
    }
    i--;
}

MDPPLATFORM_CONFIG_POWERDOWN

類似MDPPLATFORM_CONFIG_POWERUP。不介紹了。

MDPPLATFORM_CONFIG_SETBACKLIGHT

設置主屏背光,不支持拓展屏背光。

// Handle backlight level
switch (eDisplayId)
{
    case MDP_DISPLAY_PRIMARY:
        switch (sPlatformInfo.sEFIPlatformType.platform)
        {
            case EFI_PLATFORMINFO_TYPE_CDP:
            case EFI_PLATFORMINFO_TYPE_MTP:
            case EFI_PLATFORMINFO_TYPE_QRD:
            case EFI_PLATFORMINFO_TYPE_IDP:
            case EFI_PLATFORMINFO_TYPE_ATP:
                // 如果 之前背光還沒配置,就配置
                if (FALSE == sPanelPowerCtrl.bBacklightEnabled)
                {
                    if (NULL != sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Brightness_Enable)
                    {
                        if (MDP_STATUS_OK != (eStatus = sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Brightness_Enable(eDisplayId, &sPanelPowerCtrl)))
                        {
                            DEBUG((EFI_D_WARN, "MDPPlatformConfig: Backlight enabled failed\n"));
                        }
                    }

                    sPanelPowerCtrl.bBacklightEnabled = TRUE;
                }
				// 執行背光
                if (NULL != sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Brightness_Level)
                {
                    if (MDP_STATUS_OK != (eStatus = sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Brightness_Level(eDisplayId, &pPlatformParams->sBacklightConfig)))
                    {
                        DEBUG((EFI_D_WARN, "MDPPlatformConfig: Backlight level control failed\n"));
                    }
                }
                break;

            default:
                break;
        }
        break;
    case MDP_DISPLAY_EXTERNAL: // 不支持拓展屏的背光控制
        eStatus = MDP_STATUS_NOT_SUPPORTED;
        break;
    default:
        break;
}

MDPPLATFORM_CONFIG_GETPANELID

什么都沒做。

MDPPLATFORM_CONFIG_GETPLATFORMINFO

獲取當前的MDPPLATFORM

MDP_OSAL_MEMCPY(&pPlatformParams->sPlatformInfo, &sPlatformInfo, sizeof(MDPPlatformInfo));

MDPPLATFORM_CONFIG_RESETPANEL

如果復位腳存在,就按照配置的復位時序將Panel復位。

不支持拓展屏的復位。

if (pPlatformParams->sPlatformPanelReset.uResetGpio == 0)
{
    sPanelPowerCtrl.uResetGpio = DEFAULT_DISP_RESET_GPIO;
    pPlatformParams->sPlatformPanelReset.uResetGpio = DEFAULT_DISP_RESET_GPIO;
}
else 
{
    sPanelPowerCtrl.uResetGpio = pPlatformParams->sPlatformPanelReset.uResetGpio;
}
switch (eDisplayId)
{
    case MDP_DISPLAY_PRIMARY:

        // Config based on the platform
        switch (sPlatformInfo.sEFIPlatformType.platform)
        {
            case EFI_PLATFORMINFO_TYPE_CDP:
            case EFI_PLATFORMINFO_TYPE_MTP:
            case EFI_PLATFORMINFO_TYPE_QRD:
            case EFI_PLATFORMINFO_TYPE_IDP:
            case EFI_PLATFORMINFO_TYPE_ATP:
                if (NULL != sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Reset)
                {
                    if (MDP_STATUS_OK != (eStatus = sMDPPlatformPanelFunction[sPlatformPanel.uSelectedPanelIndex].pPanel_Reset(&pPlatformParams->sPlatformPanelReset)))
                    {
                        DEBUG((EFI_D_WARN, "MDPPlatformConfig: Panel reset failed (%d)\n", eStatus));
                    }
                }
                break;
            default:
                break;
        }

        break;
    case MDP_DISPLAY_EXTERNAL:
        eStatus = MDP_STATUS_NOT_SUPPORTED;
        break;
    default:
        break;
}

MDPPLATFORM_CONFIG_SETGPIOSTATE

設置MDP的Gpio為默認的設置狀態,這些GPIO必須是TLMM(Top Level ),不支持PMIC、PMI類型的GPIO。

 eStatus = SetDefaultGPIOState(&pPlatformParams->sGPIOState);

MDPPLATFORM_CONFIG_GETPANELXMLINFO

獲取當前的XML信息

// Return the raw xml information if it is within range.
if (pPlatformParams->sPanelXMLInfo.uIndex >= PANEL_LIST_LENGTH(uefiPanelList))
{
    eStatus = MDP_STATUS_FAILED;
}
else
{
    MDPPlatformPanelInfo sPlatformPanelInfo;

    MDP_OSAL_MEMZERO(&sPlatformPanelInfo, sizeof(MDPPlatformPanelInfo));
    sPlatformPanelInfo.eSelectedPanel = uefiPanelList[pPlatformParams->sPanelXMLInfo.uIndex].eSelectedPanel;
    if (MDP_STATUS_OK != FindPanelIndex(&sPlatformPanelInfo))
    {
        DEBUG((EFI_D_ERROR, "DisplayDxe: GETPANELXMLINFO: FindPanelIndex: No Panel Id=%d found\n", sPlatformPanelInfo.eSelectedPanel));
    }

    if(MDP_STATUS_OK == GetPanelXmlConfig(&sPlatformPanelInfo))
    {
        pPlatformParams->sPanelXMLInfo.pPanelXMLConfig = (int8*)sPlatformPanelInfo.pPanelXMLConfig;
        pPlatformParams->sPanelXMLInfo.uPanelXMLSize   = sPlatformPanelInfo.uConfigSize;
    }
    else
    {
        pPlatformParams->sPanelXMLInfo.pPanelXMLConfig = (int8 *)dummy_xmldata;
        pPlatformParams->sPanelXMLInfo.uPanelXMLSize   = sizeof (dummy_xmldata);
    }
}

MDPPLATFORM_CONFIG_BYPASS

剛剛已經說了,不做處理;只是單純返回成功。

附錄:OpenProtocol 和LocateProtocol() 的區別

https://blog.csdn.net/robinsongsog/article/details/96431166

一句話總結: OpenProtocol() 需要傳入handle 作為參數, 而LocateProtocol 不需要。

LocateProtocol() 和 OpenProtocol() 都是找到一個自己想要的interface。

對於consumer(driver)來說,可以通過GUID 在handle database 里面找到自己想要的protocol, 對於service protocol 如果在handle database 里面只存在一份instance(實列,即函數實現), consumer 可以使用LocateProtocol() 來達到目的。

如果在handle database 里面,多個handle 上面都有我們想要找的那個protocol , 那么我們可以先用LocateHandleBuffer() 找到所有符合條件的handle(handle

上面有我們想要找的protocol) , 然后通過通過OpenProtocol()在一個特定的handle 上面找到我們想要的protocol.

函數原型如下:

/**
  Returns the first protocol instance that matches the given protocol.
  @param[in]  Protocol          Provides the protocol to search for.
  @param[in]  Registration      Optional registration key returned from
                                RegisterProtocolNotify().
  @param[out]  Interface        On return, a pointer to the first interface that matches Protocol and
                                Registration.
  @retval EFI_SUCCESS           A protocol instance matching Protocol was found and returned in
                                Interface.
  @retval EFI_NOT_FOUND         No protocol instances were found that match Protocol and
                                Registration.
  @retval EFI_INVALID_PARAMETER Interface is NULL.
                                Protocol is NULL.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_PROTOCOL)(
  IN  EFI_GUID  *Protocol,
  IN  VOID      *Registration, OPTIONAL
  OUT VOID      **Interface
  );

可以看到 LocateProtocol 只需要傳入一個參數(GUID) 即可。

而對於OpenProtocol ,傳入的第一個參數即為Handle

/**
  Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
  handle, it opens the protocol on behalf of the calling agent.

  @param[in]   Handle           The handle for the protocol interface that is being opened.
  @param[in]   Protocol         The published unique identifier of the protocol.
  @param[out]  Interface        Supplies the address where a pointer to the corresponding Protocol
                                Interface is returned.
  @param[in]   AgentHandle      The handle of the agent that is opening the protocol interface
                                specified by Protocol and Interface.
  @param[in]   ControllerHandle If the agent that is opening a protocol is a driver that follows the
                                UEFI Driver Model, then this parameter is the controller handle
                                that requires the protocol interface. If the agent does not follow
                                the UEFI Driver Model, then this parameter is optional and may
                                be NULL.
  @param[in]   Attributes       The open mode of the protocol interface specified by Handle
                                and Protocol.

  @retval EFI_SUCCESS           An item was added to the open list for the protocol interface, and the
                                protocol interface was returned in Interface.
  @retval EFI_UNSUPPORTED       Handle does not support Protocol.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  @retval EFI_ACCESS_DENIED     Required attributes can't be supported in current environment.
  @retval EFI_ALREADY_STARTED   Item on the open list already has requierd attributes whose agent
                                handle is the same as AgentHandle.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_OPEN_PROTOCOL)(
  IN  EFI_HANDLE                Handle,
  IN  EFI_GUID                  *Protocol,
  OUT VOID                      **Interface, OPTIONAL
  IN  EFI_HANDLE                AgentHandle,
  IN  EFI_HANDLE                ControllerHandle,
  IN  UINT32                    Attributes
  );

典型用法舉例:

  //
  // Retrieve the array of handles that support Protocol
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  Protocol,
                  NULL,
                  &NoHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
 
  //
  // Allocate array of protocol instances
  //
  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  NoHandles * sizeof (VOID *),
                  (VOID **)Buffer
                  );
  if (EFI_ERROR (Status)) {
    //
    // Free the handle buffer
    //
    gBS->FreePool (HandleBuffer);
    return EFI_OUT_OF_RESOURCES;
  }
  ZeroMem (*Buffer, NoHandles * sizeof (VOID *));
 
  //
  // Lookup Protocol on each handle in HandleBuffer to fill in the array of
  // protocol instances.  Handle case where protocol instance was present when
  // LocateHandleBuffer() was called, but is not present when HandleProtocol()
  // is called.
  //
  for (Index = 0, *NoProtocols = 0; Index < NoHandles; Index++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    Protocol,
                    &((*Buffer)[*NoProtocols])
                    );
    if (!EFI_ERROR (Status)) {
      (*NoProtocols)++;
    }
  }

即分兩步:

1.   先找到所有符合條件的Handle 
     Retrieve the array of handles that support Protocol

2.   然后從每個符合條件的handler 中取出自己想要的protocol (interface)
     Lookup Protocol on each handle in HandleBuffer to fill in the array of
     protocol instances. Handle case where protocol instance was present when
     LocateHandleBuffer() was called, but is not present when HandleProtocol()
     is called. 

附錄:UEFI基礎——PCD

PCD的全稱是Platform Configuration Database,它是一個存放了UEFI下可訪問數據的數據庫。

它的特點是可以在UEFI存在的大部分時間內訪問,在UEFI實戰——在庫中使用全局變量中就曾經介紹過通過PCD來傳遞全局變量。這里說是大部分時間內,那是因為在諸如SEC階段,以及PEI、DXE階段的早期,某些PCD相關的模塊還沒有加載起來之前,這些類型的PCD還是不能訪問的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM