/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "display_layer.h" #include #include #include #include #include #include #include "display_type.h" #include "hdf_log.h" #include "hdf_io_service_if.h" #include "hdf_sbuf.h" #include "osal_mem.h" #define DEV_ID 0 #define LAYER_ID 0 #define FB_PATH "/dev/fb0" #define DISP_WIDTH 800 #define DISP_HEIGHT 480 #define BITS_PER_PIXEL 32 #define BITS_TO_BYTE 8 #define DISP_SERVICE_NAME "hdf_disp" #define DISP_CMD_GET_PANELINFO 1 #undef HDF_LOG_TAG #define HDF_LOG_TAG display_layer_c /* output timing */ enum IntfSync { OUTPUT_USER = 0, /* User timing */ OUTPUT_PAL, /* PAL standard */ OUTPUT_NTSC, /* NTSC standard */ OUTPUT_1080P24, /* 1920 x 1080 at 24 Hz. */ OUTPUT_1080P25, /* 1920 x 1080 at 25 Hz. */ OUTPUT_1080P30, /* 1920 x 1080 at 30 Hz. */ OUTPUT_720P50, /* 1280 x 720 at 50 Hz. */ OUTPUT_720P60, /* 1280 x 720 at 60 Hz. */ OUTPUT_1080I50, /* 1920 x 1080 at 50 Hz, interlace. */ OUTPUT_1080I60, /* 1920 x 1080 at 60 Hz, interlace. */ OUTPUT_1080P50, /* 1920 x 1080 at 50 Hz. */ OUTPUT_1080P60, /* 1920 x 1080 at 60 Hz. */ OUTPUT_576P50, /* 720 x 576 at 50 Hz. */ OUTPUT_480P60, /* 720 x 480 at 60 Hz. */ OUTPUT_800X600_60, /* VESA 800 x 600 at 60 Hz (non-interlaced) */ OUTPUT_1024X768_60, /* VESA 1024 x 768 at 60 Hz (non-interlaced) */ OUTPUT_1280X1024_60, /* VESA 1280 x 1024 at 60 Hz (non-interlaced) */ OUTPUT_1366X768_60, /* VESA 1366 x 768 at 60 Hz (non-interlaced) */ OUTPUT_1440X900_60, /* VESA 1440 x 900 at 60 Hz (non-interlaced) CVT Compliant */ OUTPUT_1280X800_60, /* 1280*800@60Hz VGA@60Hz */ OUTPUT_1600X1200_60, /* VESA 1600 x 1200 at 60 Hz (non-interlaced) */ OUTPUT_1680X1050_60, /* VESA 1680 x 1050 at 60 Hz (non-interlaced) */ OUTPUT_1920X1200_60, /* VESA 1920 x 1600 at 60 Hz (non-interlaced) CVT (Reduced Blanking) */ OUTPUT_640X480_60, /* VESA 640 x 480 at 60 Hz (non-interlaced) CVT */ OUTPUT_960H_PAL, /* ITU-R BT.1302 960 x 576 at 50 Hz (interlaced) */ OUTPUT_960H_NTSC, /* ITU-R BT.1302 960 x 480 at 60 Hz (interlaced) */ OUTPUT_1920X2160_30, /* 1920x2160_30 */ OUTPUT_2560X1440_30, /* 2560x1440_30 */ OUTPUT_2560X1440_60, /* 2560x1440_60 */ OUTPUT_2560X1600_60, /* 2560x1600_60 */ OUTPUT_3840X2160_24, /* 3840x2160_24 */ OUTPUT_3840X2160_25, /* 3840x2160_25 */ OUTPUT_3840X2160_30, /* 3840x2160_30 */ OUTPUT_3840X2160_50, /* 3840x2160_50 */ OUTPUT_3840X2160_60, /* 3840x2160_60 */ OUTPUT_4096X2160_24, /* 4096x2160_24 */ OUTPUT_4096X2160_25, /* 4096x2160_25 */ OUTPUT_4096X2160_30, /* 4096x2160_30 */ OUTPUT_4096X2160_50, /* 4096x2160_50 */ OUTPUT_4096X2160_60, /* 4096x2160_60 */ OUTPUT_320X240_60, /* For ota5182 at 60 Hz (8bit) */ OUTPUT_320X240_50, /* For ili9342 at 50 Hz (6bit) */ OUTPUT_240X320_50, /* Hi3559AV100: For ili9341 at 50 Hz (6bit) */ OUTPUT_240X320_60, /* For ili9341 at 60 Hz (16bit) */ OUTPUT_800X600_50, /* For LCD at 50 Hz (24bit) */ OUTPUT_720X1280_60, /* For MIPI DSI Tx 720 x1280 at 60 Hz */ OUTPUT_1080X1920_60, /* For MIPI DSI Tx 1080x1920 at 60 Hz */ OUTPUT_7680X4320_30, /* For HDMI2.1 at 30 Hz */ }; struct DispInfo { uint32_t width; uint32_t hbp; uint32_t hfp; uint32_t hsw; uint32_t height; uint32_t vbp; uint32_t vfp; uint32_t vsw; uint32_t frameRate; uint32_t intfType; enum IntfSync intfSync; uint32_t minLevel; uint32_t maxLevel; uint32_t defLevel; }; struct LayerPrivate { int32_t fd; uint32_t width; uint32_t height; int32_t pitch; void *fbAddr; uint32_t fbSize; void *layerAddr; PixelFormat pixFmt; }; struct LayerManager { pthread_mutex_t mutex; pthread_mutexattr_t mutexattr; int32_t count; }; static struct LayerManager g_layerManager; static void GetLayerMgr(void) { g_layerManager.count++; } static int32_t PutLayerMgr(void) { g_layerManager.count--; return g_layerManager.count; } static void LockLayerMgr(void) { pthread_mutex_lock(&g_layerManager.mutex); } static void UnlockLayerMgr(void) { pthread_mutex_unlock(&g_layerManager.mutex); } static int32_t DispCmdSend(const uint32_t cmd, struct HdfSBuf *reqData, struct HdfSBuf *respData) { struct HdfIoService *dispService = NULL; dispService = HdfIoServiceBind(DISP_SERVICE_NAME); if ((dispService == NULL) || (dispService->dispatcher == NULL) || (dispService->dispatcher->Dispatch == NULL)) { HDF_LOGE("%s:bad remote service found", __func__); return DISPLAY_FAILURE; } int32_t ret = dispService->dispatcher->Dispatch(&dispService->object, cmd, reqData, respData); if (ret != DISPLAY_SUCCESS) { HDF_LOGE("%s: cmd=%u, ret=%d", __func__, cmd, ret); HdfIoServiceRecycle(dispService); return DISPLAY_FAILURE; } HdfIoServiceRecycle(dispService); return DISPLAY_SUCCESS; } static int32_t GetInfo(uint32_t devId, struct DispInfo *info) { struct DispInfo *tmpInfo = NULL; struct HdfSBuf *data = NULL; struct HdfSBuf *reply = NULL; if (info == NULL) { HDF_LOGE("%s: invalid param", __func__); return DISPLAY_FAILURE; } data = HdfSbufObtainDefaultSize(); if (data == NULL) { HDF_LOGE("%s: obtain data sbuf fail", __func__); return DISPLAY_FAILURE; } reply = HdfSbufObtainDefaultSize(); if (reply == NULL) { HDF_LOGE("%s: obtain reply sbuf fail", __func__); HdfSbufRecycle(data); return DISPLAY_FAILURE; } if (!HdfSbufWriteUint32(data, devId)) { HDF_LOGE("HdfSbufWriteUint32 failure"); goto ERR; } if (DispCmdSend(DISP_CMD_GET_PANELINFO, data, reply) != DISPLAY_SUCCESS) { HDF_LOGE("cmd:DISP_CMD_GET_PANEL_INFO failure"); goto ERR; } uint32_t dataSize = 0; if (!HdfSbufReadBuffer(reply, (const void **)(&tmpInfo), &dataSize) || dataSize != sizeof(struct DispInfo)) { HDF_LOGE("HdfSbufReadBuffer failure"); goto ERR; } if (memcpy_s(info, sizeof(struct DispInfo), tmpInfo, dataSize) != EOK) { HDF_LOGE("memcpy_s failure"); goto ERR; } HdfSbufRecycle(data); HdfSbufRecycle(reply); return DISPLAY_SUCCESS; ERR: HdfSbufRecycle(data); HdfSbufRecycle(reply); return DISPLAY_FAILURE; } static struct LayerPrivate *GetLayerInstance(void) { static int32_t count; static struct DispInfo info; static struct LayerPrivate layerPriv = { .fd = -1, .width = DISP_WIDTH, .height = DISP_HEIGHT, .pixFmt = PIXEL_FMT_RGBA_8888, }; if (count == 0) { count = 1; if (GetInfo(DEV_ID, &info) == DISPLAY_SUCCESS) { layerPriv.width = info.width; layerPriv.height = info.height; } else { HDF_LOGI("%s: GetInfo failed, use default setting", __func__); } } return &layerPriv; } static int32_t InitDisplay(uint32_t devId) { if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } return DISPLAY_SUCCESS; } static int32_t DeinitDisplay(uint32_t devId) { if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } return DISPLAY_SUCCESS; } static void SetBackground(void) { struct LayerPrivate *priv = GetLayerInstance(); uint32_t i; uint32_t j; uint32_t *framebuffer = (uint32_t *)priv->fbAddr; for (j = 0; j < priv->height; j++) { for (i = 0; i < priv->width; i++) { framebuffer[i + j * priv->width] = 0xFF; // Blue background } } } static int32_t CreateLayer(uint32_t devId, const LayerInfo *layerInfo, uint32_t *layerId) { if (layerInfo == NULL || layerId == NULL) { HDF_LOGE("%s: pointer is null", __func__); return DISPLAY_NULL_PTR; } if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } LockLayerMgr(); struct LayerPrivate *priv = GetLayerInstance(); priv->fd = open(FB_PATH, O_RDWR, 0); if (priv->fd < 0) { HDF_LOGE("%s: open fb dev failed", __func__); UnlockLayerMgr(); return DISPLAY_FD_ERR; } priv->pitch = layerInfo->width * BITS_PER_PIXEL / BITS_TO_BYTE; priv->fbSize = ((priv->pitch * priv->height) + 0xfff) & (~0xfff); priv->fbAddr = (void *)mmap(NULL, priv->fbSize, PROT_READ | PROT_WRITE, MAP_SHARED, priv->fd, 0); if (priv->fbAddr == NULL) { HDF_LOGE("%s: mmap fb address failure, errno: %d", __func__, errno); close(priv->fd); priv->fd = -1; priv->pitch = 0; priv->fbSize = 0; UnlockLayerMgr(); return DISPLAY_FAILURE; } SetBackground(); *layerId = LAYER_ID; HDF_LOGI("%s: open layer success", __func__); UnlockLayerMgr(); return DISPLAY_SUCCESS; } static int32_t CloseLayer(uint32_t devId, uint32_t layerId) { if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } if (layerId != LAYER_ID) { HDF_LOGE("%s: layerId invalid", __func__); return DISPLAY_FAILURE; } LockLayerMgr(); struct LayerPrivate *priv = GetLayerInstance(); if (priv->fd >= 0) { close(priv->fd); } if (priv->layerAddr != NULL) { free(priv->layerAddr); priv->layerAddr = NULL; } if (priv->fbAddr != NULL) { munmap(priv->fbAddr, priv->fbSize); } priv->fd = -1; UnlockLayerMgr(); return DISPLAY_SUCCESS; } static int32_t GetDisplayInfo(uint32_t devId, DisplayInfo *dispInfo) { if (dispInfo == NULL) { HDF_LOGE("%s: dispInfo is null", __func__); return DISPLAY_NULL_PTR; } if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } LockLayerMgr(); struct LayerPrivate *priv = GetLayerInstance(); dispInfo->width = priv->width; dispInfo->height = priv->height; dispInfo->rotAngle = ROTATE_NONE; HDF_LOGD("%s: width = %u, height = %u, rotAngle = %u", __func__, dispInfo->width, dispInfo->height, dispInfo->rotAngle); UnlockLayerMgr(); return DISPLAY_SUCCESS; } static int32_t Flush(uint32_t devId, uint32_t layerId, LayerBuffer *buffer) { int32_t ret; if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } if (layerId != LAYER_ID) { HDF_LOGE("%s: layerId invalid", __func__); return DISPLAY_FAILURE; } if (buffer == NULL) { HDF_LOGE("%s: buffer is null", __func__); return DISPLAY_FAILURE; } HDF_LOGD("%s: width = %d, height = %d, pixFormat = %d, pitch = %d", __func__, buffer->width, buffer->height, buffer->pixFormat, buffer->pitch); LockLayerMgr(); struct LayerPrivate *priv = GetLayerInstance(); ret = memcpy_s(priv->fbAddr, priv->fbSize, buffer->data.virAddr, priv->fbSize); if (ret != EOK) { HDF_LOGE("%s: memcpy_s fail, ret %d", __func__, ret); UnlockLayerMgr(); return ret; } UnlockLayerMgr(); return DISPLAY_SUCCESS; } static int32_t GetLayerBuffer(uint32_t devId, uint32_t layerId, LayerBuffer *buffer) { if (buffer == NULL) { HDF_LOGE("%s: buffer is null", __func__); return DISPLAY_NULL_PTR; } if (devId != DEV_ID) { HDF_LOGE("%s: devId invalid", __func__); return DISPLAY_FAILURE; } if (layerId != LAYER_ID) { HDF_LOGE("%s: layerId invalid", __func__); return DISPLAY_FAILURE; } LockLayerMgr(); struct LayerPrivate *priv = GetLayerInstance(); if (priv->fd < 0) { HDF_LOGE("%s: fd invalid", __func__); UnlockLayerMgr(); return DISPLAY_FAILURE; } buffer->fenceId = 0; buffer->width = priv->width; buffer->height = priv->height; buffer->pixFormat = priv->pixFmt; buffer->pitch = priv->pitch; buffer->data.virAddr = malloc(priv->fbSize); if (buffer->data.virAddr == NULL) { HDF_LOGE("%s: malloc failure", __func__); UnlockLayerMgr(); return DISPLAY_FAILURE; } priv->layerAddr = buffer->data.virAddr; (void)memset_s(buffer->data.virAddr, priv->fbSize, 0x00, priv->fbSize); HDF_LOGD("%s: fenceId = %d, width = %d, height = %d, pixFormat = %d, pitch = %d", __func__, buffer->fenceId, buffer->width, buffer->height, buffer->pixFormat, buffer->pitch); UnlockLayerMgr(); return DISPLAY_SUCCESS; } int32_t LayerInitialize(LayerFuncs **funcs) { static LayerFuncs *lFuncs = NULL; if (funcs == NULL) { HDF_LOGE("%s: funcs is null", __func__); return DISPLAY_NULL_PTR; } if (lFuncs == NULL) { lFuncs = (LayerFuncs *)OsalMemCalloc(sizeof(LayerFuncs)); if (lFuncs == NULL) { HDF_LOGE("%s: lFuncs is null", __func__); return DISPLAY_NULL_PTR; } pthread_mutexattr_init(&g_layerManager.mutexattr); pthread_mutexattr_setpshared(&g_layerManager.mutexattr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&g_layerManager.mutex, &g_layerManager.mutexattr); lFuncs->InitDisplay = InitDisplay; lFuncs->DeinitDisplay = DeinitDisplay; lFuncs->GetDisplayInfo = GetDisplayInfo; lFuncs->CreateLayer = CreateLayer; lFuncs->CloseLayer = CloseLayer; lFuncs->Flush = Flush; lFuncs->GetLayerBuffer = GetLayerBuffer; } *funcs = lFuncs; GetLayerMgr(); HDF_LOGI("%s: success", __func__); return DISPLAY_SUCCESS; } int32_t LayerUninitialize(LayerFuncs *funcs) { if (funcs == NULL) { HDF_LOGE("%s: funcs is null", __func__); return DISPLAY_NULL_PTR; } if (PutLayerMgr() == 0) { pthread_mutexattr_destroy(&g_layerManager.mutexattr); pthread_mutex_destroy(&g_layerManager.mutex); OsalMemFree(funcs); } HDF_LOGI("%s: layer uninitialize success", __func__); return DISPLAY_SUCCESS; }