* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "hdf_disp.h"
#include <securec.h>
#include "hdf_base.h"
#include "hdf_bl.h"
#include "hdf_log.h"
#include "osal.h"
#define OFFSET_TWO_BYTE 16
static struct DispManager *g_dispManager = NULL;
static struct PanelManager g_panelManager;
int32_t RegisterPanel(struct PanelData *panel)
{
uint32_t panelNum;
if (panel == NULL) {
HDF_LOGE("%s: panel data is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (panel->info == NULL) {
HDF_LOGE("%s panel info is null", __func__);
return HDF_FAILURE;
}
if ((panel->on == NULL) || (panel->off == NULL)) {
HDF_LOGE("%s on or off is null", __func__);
return HDF_FAILURE;
}
panel->powerStatus = POWER_STATUS_OFF;
panelNum = g_panelManager.panelNum;
if (panelNum >= PANEL_MAX) {
HDF_LOGE("%s registered panel up PANEL_MAX", __func__);
return HDF_FAILURE;
}
g_panelManager.panel[panelNum] = panel;
g_panelManager.panelNum++;
HDF_LOGI("%s: register success", __func__);
return HDF_SUCCESS;
}
struct PanelManager *GetPanelManager(void)
{
if (g_panelManager.panelNum == 0) {
return NULL;
} else {
return &g_panelManager;
}
}
struct DispManager *GetDispManager(void)
{
if (g_dispManager != NULL && g_dispManager->initialzed) {
return g_dispManager;
}
return NULL;
}
static int32_t InitDisp(uint32_t devId);
int32_t DispOn(uint32_t devId);
int32_t DispOff(uint32_t devId);
int32_t SetDispBacklight(uint32_t devId, uint32_t level);
static int32_t GetDispInfo(uint32_t devId, struct DispInfo *info);
static int32_t SetDispPower(uint32_t devId, uint32_t powerStatus);
static void EsdCheckStartUp(struct DispEsd *esd, uint32_t devId);
static void EsdCheckEnd(struct DispEsd *esd, uint32_t devId);
struct DispOperations *GetDispOps(void)
{
static struct DispOperations dispOps = {
.init = InitDisp,
.on = DispOn,
.off = DispOff,
.setBacklight = SetDispBacklight,
.getDispInfo = GetDispInfo,
};
return &dispOps;
}
#ifdef __KERNEL__
EXPORT_SYMBOL(GetDispOps);
EXPORT_SYMBOL(DispOn);
EXPORT_SYMBOL(DispOff);
EXPORT_SYMBOL(SetDispBacklight);
#endif
static int32_t InitDisp(uint32_t devId)
{
return 0;
}
int32_t DispOn(uint32_t devId)
{
return SetDispPower(devId, POWER_STATUS_ON);
}
int32_t DispOff(uint32_t devId)
{
return SetDispPower(devId, POWER_STATUS_OFF);
}
int32_t SetDispBacklight(uint32_t devId, uint32_t level)
{
struct DispManager *disp = NULL;
struct PanelData *panel = NULL;
disp = GetDispManager();
if (disp && disp->panelManager && devId < disp->panelManager->panelNum) {
panel = disp->panelManager->panel[devId];
}
if ((panel == NULL) || (UpdateBrightness(panel->blDev, level) != HDF_SUCCESS)) {
HDF_LOGE("%s:panel is null or UpdateBrightness failed", __func__);
return HDF_FAILURE;
}
HDF_LOGI("%s:level = %u", __func__, level);
return HDF_SUCCESS;
}
static int32_t GetDispInfo(uint32_t devId, struct DispInfo *info)
{
struct DispManager *disp = NULL;
struct PanelData *panel = NULL;
if (info == NULL) {
HDF_LOGE("%s:info is null", __func__);
return HDF_FAILURE;
}
disp = GetDispManager();
if (disp == NULL) {
HDF_LOGE("%s: disp is null", __func__);
return HDF_FAILURE;
}
if (devId >= disp->panelManager->panelNum) {
HDF_LOGE("%s: devId exceed registered panelNum", __func__);
return HDF_FAILURE;
}
panel = disp->panelManager->panel[devId];
info->width = panel->info->width;
info->height = panel->info->height;
info->hbp = panel->info->hbp;
info->hfp = panel->info->hfp;
info->hsw = panel->info->hsw;
info->vbp = panel->info->vbp;
info->vfp = panel->info->vfp;
info->vsw = panel->info->vsw;
info->intfType = panel->info->intfType;
info->intfSync = panel->info->intfSync;
info->frameRate = panel->info->frameRate;
info->minLevel = panel->info->blk.minLevel;
info->maxLevel = panel->info->blk.maxLevel;
info->defLevel = panel->info->blk.defLevel;
return HDF_SUCCESS;
}
static int32_t SetDispPower(uint32_t devId, uint32_t powerStatus)
{
int32_t ret = HDF_FAILURE;
struct DispManager *disp = NULL;
struct PanelData *panel = NULL;
disp = GetDispManager();
if (disp == NULL) {
HDF_LOGE("%s:disp is null", __func__);
return HDF_FAILURE;
}
if (devId >= disp->panelManager->panelNum) {
HDF_LOGE("%s:devId exceed registered panelNum", __func__);
return HDF_FAILURE;
}
panel = disp->panelManager->panel[devId];
OsalMutexLock(&disp->dispMutex);
if (panel->powerStatus == powerStatus) {
OsalMutexUnlock(&disp->dispMutex);
HDF_LOGE("%s: panel already in mode = %d", __func__, powerStatus);
return HDF_SUCCESS;
}
switch (powerStatus) {
case POWER_STATUS_ON:
ret = panel->on(panel);
if (ret == HDF_SUCCESS) {
panel->powerStatus = POWER_STATUS_ON;
ret = UpdateBacklightState(panel->blDev, FB_POWER_ON);
EsdCheckStartUp(disp->esd, devId);
}
break;
case POWER_STATUS_OFF:
ret = panel->off(panel);
if (ret == HDF_SUCCESS) {
panel->powerStatus = POWER_STATUS_OFF;
ret = UpdateBacklightState(panel->blDev, FB_POWER_OFF);
EsdCheckEnd(disp->esd, devId);
}
break;
default:
HDF_LOGE("%s: not support powerStatus: %d", __func__, powerStatus);
break;
}
OsalMutexUnlock(&disp->dispMutex);
return ret;
}
static int32_t SetPowerStatus(struct HdfDeviceObject *device, struct HdfSBuf *reqData, struct HdfSBuf *rspData)
{
uint32_t para = 0;
(void)device;
(void)rspData;
if (reqData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (!HdfSbufReadUint32(reqData, ¶)) {
HDF_LOGE("%s: HdfSbufReadBuffer failed", __func__);
return HDF_FAILURE;
}
uint32_t devId = (para >> OFFSET_TWO_BYTE) & 0xffff;
uint32_t powerStatus = para & 0xffff;
return SetDispPower(devId, powerStatus);
}
static int32_t GetPowerStatus(struct HdfDeviceObject *device, struct HdfSBuf *reqData, struct HdfSBuf *rspData)
{
uint32_t devId = 0;
enum PowerStatus powerStatus;
struct DispManager *disp = NULL;
struct PanelData *panel = NULL;
(void)device;
if (reqData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (!HdfSbufReadUint32(reqData, &devId)) {
HDF_LOGE("%s: HdfSbufReadBuffer failed", __func__);
return HDF_FAILURE;
}
disp = GetDispManager();
if (disp == NULL || disp->panelManager == NULL || (devId >= disp->panelManager->panelNum)) {
HDF_LOGE("%s: get panel failed", __func__);
return HDF_FAILURE;
}
OsalMutexLock(&disp->dispMutex);
panel = disp->panelManager->panel[devId];
powerStatus = panel->powerStatus;
OsalMutexUnlock(&disp->dispMutex);
if (!HdfSbufWriteUint32(rspData, powerStatus)) {
HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SetBacklight(struct HdfDeviceObject *device, struct HdfSBuf *reqData, struct HdfSBuf *rspData)
{
int32_t ret;
(void)device;
(void)rspData;
if (reqData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
uint32_t para = 0;
if (!HdfSbufReadUint32(reqData, ¶)) {
HDF_LOGE("%s: HdfSbufReadBuffer failed", __func__);
return HDF_FAILURE;
}
uint32_t devId = (para >> OFFSET_TWO_BYTE) & 0xffff;
uint32_t level = para & 0xffff;
ret = SetDispBacklight(devId, level);
return ret;
}
static int32_t GetBacklight(struct HdfDeviceObject *device, struct HdfSBuf *reqData, struct HdfSBuf *rspData)
{
uint32_t devId = 0;
uint32_t currLevel;
struct DispManager *disp = NULL;
struct PanelData *panel = NULL;
(void)device;
if (reqData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (!HdfSbufReadUint32(reqData, &devId)) {
HDF_LOGE("%s: HdfSbufReadBuffer failed", __func__);
return HDF_FAILURE;
}
disp = GetDispManager();
if (disp == NULL || disp->panelManager == NULL || (devId >= disp->panelManager->panelNum)) {
HDF_LOGE("%s: get panel failed", __func__);
return HDF_FAILURE;
}
panel = disp->panelManager->panel[devId];
if (GetCurrBrightness(panel->blDev, &currLevel) != HDF_SUCCESS) {
HDF_LOGE("%s: GetCurrBrightness failed", __func__);
return HDF_FAILURE;
}
if (!HdfSbufWriteUint32(rspData, currLevel)) {
HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t GetInfo(struct HdfDeviceObject *device, struct HdfSBuf *reqData, struct HdfSBuf *rspData)
{
(void)device;
(void)rspData;
uint32_t devId = 0;
struct DispInfo info;
if (reqData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (!HdfSbufReadUint32(reqData, &devId)) {
HDF_LOGE("%s: HdfSbufReadBuffer failed", __func__);
return HDF_FAILURE;
}
(void)memset_s(&info, sizeof(struct DispInfo), 0, sizeof(struct DispInfo));
if (GetDispInfo(devId, &info) != HDF_SUCCESS) {
HDF_LOGE("%s: GetDispInfo failed", __func__);
return HDF_FAILURE;
}
if (!HdfSbufWriteBuffer(rspData, &info, sizeof(struct DispInfo)) != 0) {
HDF_LOGE("%s: copy info failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
DispCmdHandle g_dispCmdHandle[] = {
GetPowerStatus,
GetInfo,
SetPowerStatus,
SetBacklight,
GetBacklight,
};
static int32_t DispCmdProcess(struct HdfDeviceObject *device, int32_t cmd, struct HdfSBuf *reqData,
struct HdfSBuf *rspData)
{
int32_t cmdNum = sizeof(g_dispCmdHandle) / sizeof(g_dispCmdHandle[0]);
if (device == NULL || reqData == NULL || rspData == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (cmd >= cmdNum || cmd < 0) {
HDF_LOGE("%s: invalid cmd = %d", __func__, cmd);
return HDF_FAILURE;
}
HDF_LOGD("%s: cmd = %d", __func__, cmd);
if (g_dispCmdHandle[cmd] == NULL) {
return HDF_FAILURE;
}
return g_dispCmdHandle[cmd](device, reqData, rspData);
}
static int32_t HdfDispDispatch(struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data,
struct HdfSBuf *reply)
{
if (client == NULL) {
return HDF_ERR_INVALID_PARAM;
}
return DispCmdProcess(client->device, id, data, reply);
}
static int HdfDispBind(struct HdfDeviceObject *dev)
{
if (dev == NULL) {
return HDF_FAILURE;
}
static struct IDeviceIoService dispService = {
.object.objectId = 1,
.Dispatch = HdfDispDispatch,
};
dev->service = &dispService;
return HDF_SUCCESS;
}
static void PanelRecovery(struct PanelData *panel)
{
HDF_LOGI("%s enter", __func__);
if (panel->off) {
panel->off(panel);
}
OsalMSleep(150);
if (panel->on) {
panel->on(panel);
}
}
static void EsdTimerHandler(uintptr_t arg)
{
uint32_t devId = (uint32_t)arg;
struct DispManager *disp = NULL;
disp = GetDispManager();
if ((disp == NULL) || (disp->esd == NULL)) {
HDF_LOGE("%s: disp or esd is null", __func__);
return;
}
if (devId >= disp->esd->panelNum) {
HDF_LOGE("%s: esd is null", __func__);
return;
}
HdfAddWork(&disp->dispWorkQueue, disp->esd->work[devId]);
HDF_LOGD("%s devId[%d] add work to wq", __func__, devId);
}
static void EsdWorkHandler(void *arg)
{
int32_t ret = HDF_SUCCESS;
uint32_t devId = (uint32_t)arg;
struct PanelData *panel = NULL;
struct DispManager *disp = NULL;
disp = GetDispManager();
if ((disp == NULL) || (disp->panelManager == NULL)) {
HDF_LOGE("%s: disp or panelManager is null", __func__);
return;
}
if (devId >= disp->panelManager->panelNum) {
HDF_LOGE("%s: dispCtrl is null or panel is null", __func__);
return;
}
panel = disp->panelManager->panel[devId];
if ((panel->esd == NULL) || (panel->esd->checkFunc == NULL)) {
HDF_LOGE("%s: esd or checkFunc is null", __func__);
return;
}
ret = panel->esd->checkFunc(panel);
if (ret != HDF_SUCCESS) {
OsalMutexLock(&disp->dispMutex);
if (panel->esd->state == ESD_RUNNING) {
PanelRecovery(panel);
} else {
HDF_LOGI("%s: esd check has disabled", __func__);
OsalMutexUnlock(&disp->dispMutex);
return;
}
OsalMutexUnlock(&disp->dispMutex);
panel->esd->recoveryNum++;
}
HDF_LOGD("%s recoveryNum = %d", __func__, panel->esd->recoveryNum);
if (panel->esd->recoveryNum >= ESD_MAX_RECOVERY) {
panel->esd->recoveryNum = 0;
OsalMutexLock(&disp->dispMutex);
if (panel->esd->state == ESD_RUNNING) {
OsalTimerDelete(disp->esd->timer[devId]);
panel->esd->state = ESD_READY;
HDF_LOGI("%s disable esd check", __func__);
} else {
HDF_LOGI("%s: esd check has disabled", __func__);
OsalMutexUnlock(&disp->dispMutex);
return;
}
OsalMutexUnlock(&disp->dispMutex);
}
}
static void EsdCheckStartUp(struct DispEsd *esd, uint32_t devId)
{
if (esd == NULL) {
HDF_LOGE("%s esd is null", __func__);
return;
}
HDF_LOGD("%s enter", __func__);
if ((esd->panelEsd[devId] != NULL) && esd->panelEsd[devId]->support) {
if (esd->panelEsd[devId]->state == ESD_READY) {
OsalTimerCreate(esd->timer[devId], esd->panelEsd[devId]->interval,
EsdTimerHandler, (uintptr_t)devId);
OsalTimerStartLoop(esd->timer[devId]);
esd->panelEsd[devId]->state = ESD_RUNNING;
HDF_LOGI("%s panel enable esd check", __func__);
}
}
}
static void EsdCheckEnd(struct DispEsd *esd, uint32_t devId)
{
if (esd == NULL) {
HDF_LOGE("%s esd is null", __func__);
return;
}
HDF_LOGD("%s enter", __func__);
if ((esd->panelEsd[devId] != NULL) && (esd->panelEsd[devId]->support)) {
esd->panelEsd[devId]->recoveryNum = 0;
if (esd->panelEsd[devId]->state == ESD_RUNNING) {
OsalTimerDelete(esd->timer[devId]);
esd->panelEsd[devId]->state = ESD_READY;
HDF_LOGI("%s panel disable esd check", __func__);
}
}
}
static struct DispEsd *EsdResMalloc(int32_t panelNum)
{
struct DispEsd *esd = NULL;
esd = (struct DispEsd *)OsalMemCalloc(sizeof(struct DispEsd));
if (esd == NULL) {
HDF_LOGE("%s esd malloc fail", __func__);
return NULL;
}
esd->panelEsd = (struct PanelEsd **)OsalMemCalloc(sizeof(struct PanelEsd *) * panelNum);
if (esd->panelEsd == NULL) {
HDF_LOGE("%s panelEsd malloc fail", __func__);
goto PANEL_ESD_EXIT;
}
esd->work = (HdfWork **)OsalMemCalloc(sizeof(HdfWork *) * panelNum);
if (esd->work == NULL) {
HDF_LOGE("%s work malloc fail", __func__);
goto WORK_EXIT;
}
esd->timer = (OsalTimer **)OsalMemCalloc(sizeof(OsalTimer *) * panelNum);
if (esd->timer == NULL) {
HDF_LOGE("%s timer malloc fail", __func__);
goto TIMER_EXIT;
}
esd->workInit = (bool *)OsalMemCalloc(sizeof(bool) * panelNum);
if (esd->workInit == NULL) {
HDF_LOGE("%s workInit malloc fail", __func__);
goto WORK_INIT_EXIT;
}
return esd;
WORK_INIT_EXIT:
OsalMemFree(esd->timer);
TIMER_EXIT:
OsalMemFree(esd->work);
WORK_EXIT:
OsalMemFree(esd->panelEsd);
PANEL_ESD_EXIT:
OsalMemFree(esd);
return NULL;
}
static void EsdMemFree(struct DispEsd *esd)
{
uint32_t i;
for (i = 0; i < esd->panelNum; i++) {
if (esd->workInit[i] == true) {
HdfWorkDestroy(esd->work[i]);
}
OsalMemFree(esd->work[i]);
OsalMemFree(esd->timer[i]);
}
OsalMemFree(esd->panelEsd);
OsalMemFree(esd->work);
OsalMemFree(esd->timer);
OsalMemFree(esd);
}
static int32_t EsdResInit(struct DispEsd *esd, struct PanelData **panel)
{
uint32_t i;
int32_t ret;
for (i = 0; i < esd->panelNum; i++) {
if ((panel[i]->esd != NULL) && panel[i]->esd->support) {
esd->panelEsd[i] = panel[i]->esd;
esd->work[i] = (HdfWork *)OsalMemCalloc(sizeof(HdfWork));
if (esd->work[i] == NULL) {
HDF_LOGE("%s work malloc fail", __func__);
EsdMemFree(esd);
return HDF_FAILURE;
}
esd->timer[i] = (OsalTimer *)OsalMemCalloc(sizeof(OsalTimer));
if (esd->timer[i] == NULL) {
EsdMemFree(esd);
HDF_LOGE("%s timer malloc fail", __func__);
return HDF_FAILURE;
}
if (esd->panelEsd[i]->interval < ESD_DEFAULT_INTERVAL) {
esd->panelEsd[i]->interval = ESD_DEFAULT_INTERVAL;
}
ret = HdfWorkInit(esd->work[i], EsdWorkHandler, (void *)i);
if (ret != HDF_SUCCESS) {
EsdMemFree(esd);
HDF_LOGE("%s HdfWorkInit fail", __func__);
return HDF_FAILURE;
}
esd->workInit[i] = true;
esd->panelEsd[i]->state = ESD_READY;
}
}
return HDF_SUCCESS;
}
static int32_t EsdCheckInit(struct DispManager *disp)
{
uint32_t i;
int32_t ret;
int32_t count = 0;
uint32_t panelNum;
struct DispEsd *esd = NULL;
struct PanelData **panel = NULL;
if (disp->panelManager == NULL) {
HDF_LOGE("%s panelManager is null", __func__);
return HDF_FAILURE;
}
panel = disp->panelManager->panel;
panelNum = disp->panelManager->panelNum;
for (i = 0; i < panelNum; i++) {
if ((panel[i]->esd != NULL) && panel[i]->esd->support) {
count++;
break;
}
}
if (count == 0) {
HDF_LOGI("%s none of panels support esd", __func__);
return HDF_SUCCESS;
}
esd = EsdResMalloc(panelNum);
if (esd == NULL) {
HDF_LOGE("%s EsdResInit fail", __func__);
return HDF_FAILURE;
}
esd->panelNum = panelNum;
ret = EsdResInit(esd, panel);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s EsdResInit fail", __func__);
EsdMemFree(esd);
return HDF_FAILURE;
}
disp->esd = esd;
return HDF_SUCCESS;
}
static int32_t DispManagerInit(struct PanelManager *panelManager)
{
int32_t ret;
g_dispManager = (struct DispManager *)OsalMemCalloc(sizeof(struct DispManager));
if (g_dispManager == NULL) {
HDF_LOGE("%s g_dispManager malloc fail", __func__);
return HDF_FAILURE;
}
g_dispManager->panelManager = panelManager;
ret = HdfWorkQueueInit(&g_dispManager->dispWorkQueue, "dispWQ");
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: HdfWorkQueueInit fail", __func__);
return HDF_FAILURE;
}
ret = EsdCheckInit(g_dispManager);
if (ret != HDF_SUCCESS) {
HdfWorkQueueDestroy(&g_dispManager->dispWorkQueue);
HDF_LOGE("%s: EsdCheckInit fail", __func__);
return HDF_FAILURE;
}
OsalMutexInit(&g_dispManager->dispMutex);
g_dispManager->initialzed = true;
return HDF_SUCCESS;
}
static int32_t HdfDispEntryInit(struct HdfDeviceObject *object)
{
int32_t ret;
struct PanelManager *panelManager = NULL;
if (object == NULL) {
HDF_LOGE("%s: object is null!", __func__);
return HDF_FAILURE;
}
panelManager = GetPanelManager();
if (panelManager == NULL) {
HDF_LOGE("%s: panelManager is null!", __func__);
return HDF_FAILURE;
}
ret = DispManagerInit(panelManager);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: DispManagerInit fail", __func__);
return HDF_FAILURE;
}
HDF_LOGI("%s success", __func__);
return HDF_SUCCESS;
}
struct HdfDriverEntry g_dispDevEntry = {
.moduleVersion = 1,
.moduleName = "HDF_DISP",
.Init = HdfDispEntryInit,
.Bind = HdfDispBind,
};
HDF_INIT(g_dispDevEntry);