背景
在啟動流程分析中,看到了幾個經常出現的函數,這里實際分析一下有關的實現。以搞清楚高通做了什么,以及我們能做什么。
重要函數
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() 的區別
一句話總結: 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還是不能訪問的。