# 高通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还是不能访问的。

高通Android UEFI中的LCD分析(2):关键的函数的更多相关文章

  1. 高通Android display架构分析

    目录(?)[-] Kernel Space Display架构介绍 函数和数据结构介绍 函数和数据结构介绍 函数和数据结构介绍 数据流分析 初始化过程分析 User Space display接口 K ...

  2. 高通Android display分析【转】

    本文转载自:http://blog.csdn.net/zhangchiytu/article/details/6777039 高通7系列硬件架构分析 如上图,高通7系列 Display的硬件部分主要由 ...

  3. 高通平台msm8909 LK 实现LCD 兼容

    前段时间小米出现红米note2 换屏门,现在我们公司也要上演了:有两个供应商提供不同IC 的LCD panel. 软件区分的办法是读取LCD IC 的ID 寄存器,下面解析高通平台LK中LCD兼容的过 ...

  4. 高通Android平台硬件调试之Camera篇

    之前一段时间有幸在高通android平台上调试2款camera sensor,一款是OV的5M YUV sensor,支持jpeg out,同时也支持AF,调试比较比较简单,因为别的项目已经在使用了, ...

  5. 高通android开发摘要

    一部分是开源的,可以从codeaurora.org上下载,还有一部分是高通产权的,需要从高通的网站上下载. 将高通产权的代码放到:vendor/qcom/proprietary 1. 设置bms一些参 ...

  6. 高通 android平台LCD驱动分析

    目前手机芯片厂家提供的源码里包含整个LCD驱动框架,一般厂家会定义一个xxx_fb.c的源文件,注册一个平台设备和平台驱动,在驱动的probe函数中来调用register_framebuffer(), ...

  7. 高通Android camera运行流程【转】

    本文转载自:http://blog.csdn.net/unicornkylin/article/details/13293295 1.总体架构 Android Camera 框架从整体上看是一个 cl ...

  8. 高通公司 MSM8K GPT异常原因分析无法开机的问题

    问题分析过程如下面: 一. MSM8916台gpt概率问题:采用QPST emmc software download下载软件工具后,无法开机.例如下面的附图: log分析是userdata分区未成功 ...

  9. 高通android开发缩写

    1.TLMM MSM TLMM pinmux controller,Qualcomm MSM integrates a GPIO and Pin mux/config hardware, (TOP L ...

  10. 【AT91SAM3S】SAM3S-EK Demo工程中,LCD驱动程序的加载(函数指针结构体)

    为了调试LCD,在英倍特的板子上烧Atmel的sam3s-ek_demo_1.4_source示例代码.LCD显示正常了,却找不到LCD的驱动究竟在哪. 花了好久,追踪到了这个执行过程. 进入main ...

随机推荐

  1. uiautomator2环境搭建+元素定位(安卓)

    一.环境搭建 1.安装uiautomator2 在终端使用pip安装即可 pip install uiautomator2 2.安装adb 可参考:https://www.cnblogs.com/li ...

  2. 4.10 + (double)(rand()%10)/100.0

    黑色星期四 坏消息: 没有奥赛课,所以大概率调不出来 CF1479D 好消息: 5k 回来了,调题有望 中午起床直接来的机房,有学科自习就说 氟硫氢 不知道 结果被叫回去了 而且今天班里没水了,趁着大 ...

  3. ruby后台传变量到前端的JS里

    后端变量 @namelist 前端解释 var result_json = <%= @namelist.to_json.html_safe %>

  4. golang、JS AES(CBC模式)加密解密兼容

    目录 golang.JS AES(CBC模式)加密解密兼容 golang代码 前端javascript的代码 aes.js 原文地址: https://www.cnblogs.com/haima/p/ ...

  5. 一键自动化博客发布工具,用过的人都说好(infoq篇)

    infoq的博客发布界面也是非常简洁的.首页就只有基本的标题,内容和封面图片,所以infoq的实现也相对比较简单. 一起来看看吧. 前提条件 前提条件当然是先下载 blog-auto-publishi ...

  6. P3667 Bovine Genomics Hash+二分题解

    砂金听说了你在学字符串,于是在CLOI里出了道题给你 P3667 Bovine Genomics 题链:洛谷 hzoi提高 \(hash\)基础题. 思路是二分答案,\(check\)中比较每一个区间 ...

  7. WPF自定义控件,如何使得xaml涉及器中的修改能立即反应到预览

    这是我无意中发现的,xaml中设置的是依赖属性而不是包装器,所以我们可以直接在注册依赖属性那里设置回调,触发某个控件重绘,比如本身或父控件重绘. xaml设计器就会实时更新 1 // !!!由于xam ...

  8. SpringBoot使用@Value获取不到值的问题

    背景 在一次SpringBoot项目改造为Cloud的过程中,使用Nacos作为配置中心获取属性,改造后程序启动报错,查看日志,定位到代码: 解决方案 如果了解Bean的生命周期的同学应该知道,Spr ...

  9. java中SimpleDateFormat解析日期格式的问题

    在日常写代码的过程中,我们经常要处理各种格式的日期,常见的日期格式有:"20240601","2024-06-01","2024-6-1". ...

  10. Linux signal()函数

    这是在网易云课堂学习Linux下的signal()函数的笔记,课程链接:https://study.163.com/course/courseLearn.htm?courseId=1002913011 ...