1d6aed566Sopenharmony_ci/* 2d6aed566Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3d6aed566Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d6aed566Sopenharmony_ci * you may not use this file except in compliance with the License. 5d6aed566Sopenharmony_ci * You may obtain a copy of the License at 6d6aed566Sopenharmony_ci * 7d6aed566Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d6aed566Sopenharmony_ci * 9d6aed566Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d6aed566Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d6aed566Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d6aed566Sopenharmony_ci * See the License for the specific language governing permissions and 13d6aed566Sopenharmony_ci * limitations under the License. 14d6aed566Sopenharmony_ci */ 15d6aed566Sopenharmony_ci/* 16d6aed566Sopenharmony_ci * Simple virtio-mmio gpu driver, without hardware accelarator. 17d6aed566Sopenharmony_ci * Using only synchronous request/response, no IRQ. 18d6aed566Sopenharmony_ci */ 19d6aed566Sopenharmony_ci 20d6aed566Sopenharmony_ci#include "osal.h" 21d6aed566Sopenharmony_ci#include "osal_io.h" 22d6aed566Sopenharmony_ci#include "hdf_device_desc.h" 23d6aed566Sopenharmony_ci#include "securec.h" 24d6aed566Sopenharmony_ci#include "los_compiler.h" 25d6aed566Sopenharmony_ci#include "los_memory.h" 26d6aed566Sopenharmony_ci#include "fb.h" 27d6aed566Sopenharmony_ci#include "virtmmio.h" 28d6aed566Sopenharmony_ci 29d6aed566Sopenharmony_ci#define VIRTIO_GPU_F_EDID (1 << 1) 30d6aed566Sopenharmony_ci 31d6aed566Sopenharmony_ci#define VIRTQ_CONTROL_QSZ 4 32d6aed566Sopenharmony_ci#define VIRTQ_CURSOR_QSZ 2 33d6aed566Sopenharmony_ci#define NORMAL_CMD_ENTRIES 2 34d6aed566Sopenharmony_ci 35d6aed566Sopenharmony_ci#define FB_WIDTH_DFT 800 36d6aed566Sopenharmony_ci#define FB_HEIGHT_DFT 480 37d6aed566Sopenharmony_ci#define GPU_DFT_RATE (1000 / 30) /* ms, 30Hz */ 38d6aed566Sopenharmony_ci#define PIXEL_BYTES 4 39d6aed566Sopenharmony_ci 40d6aed566Sopenharmony_ci#define RESOURCEID_FB 1 41d6aed566Sopenharmony_ci 42d6aed566Sopenharmony_cienum VirtgpuCtrlType { 43d6aed566Sopenharmony_ci /* 2d commands */ 44d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, 45d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, 46d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_RESOURCE_UNREF, 47d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_SET_SCANOUT, 48d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_RESOURCE_FLUSH, 49d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, 50d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, 51d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, 52d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_GET_CAPSET_INFO, 53d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_GET_CAPSET, 54d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_GET_EDID, 55d6aed566Sopenharmony_ci /* cursor commands */ 56d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, 57d6aed566Sopenharmony_ci VIRTIO_GPU_CMD_MOVE_CURSOR, 58d6aed566Sopenharmony_ci /* success responses */ 59d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_OK_NODATA = 0x1100, 60d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_OK_DISPLAY_INFO, 61d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_OK_CAPSET_INFO, 62d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_OK_CAPSET, 63d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_OK_EDID, 64d6aed566Sopenharmony_ci /* error responses */ 65d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, 66d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, 67d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, 68d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, 69d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, 70d6aed566Sopenharmony_ci VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, 71d6aed566Sopenharmony_ci}; 72d6aed566Sopenharmony_ci 73d6aed566Sopenharmony_cienum VirtgpuFormats { 74d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, 75d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM, 76d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM, 77d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM, 78d6aed566Sopenharmony_ci 79d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, 80d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM, 81d6aed566Sopenharmony_ci 82d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, 83d6aed566Sopenharmony_ci VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, 84d6aed566Sopenharmony_ci}; 85d6aed566Sopenharmony_ci 86d6aed566Sopenharmony_cistruct VirtgpuCtrlHdr { 87d6aed566Sopenharmony_ci uint32_t type; 88d6aed566Sopenharmony_ci#define VIRTIO_GPU_FLAG_FENCE (1 << 0) 89d6aed566Sopenharmony_ci uint32_t flags; 90d6aed566Sopenharmony_ci uint64_t fenceId; 91d6aed566Sopenharmony_ci uint32_t ctxId; 92d6aed566Sopenharmony_ci uint32_t padding; 93d6aed566Sopenharmony_ci}; 94d6aed566Sopenharmony_ci 95d6aed566Sopenharmony_cistruct VirtgpuRect { 96d6aed566Sopenharmony_ci uint32_t x; 97d6aed566Sopenharmony_ci uint32_t y; 98d6aed566Sopenharmony_ci uint32_t width; 99d6aed566Sopenharmony_ci uint32_t height; 100d6aed566Sopenharmony_ci}; 101d6aed566Sopenharmony_ci 102d6aed566Sopenharmony_cistruct VirtgpuResourceFlush { 103d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 104d6aed566Sopenharmony_ci struct VirtgpuRect r; 105d6aed566Sopenharmony_ci uint32_t resourceId; 106d6aed566Sopenharmony_ci uint32_t padding; 107d6aed566Sopenharmony_ci}; 108d6aed566Sopenharmony_ci 109d6aed566Sopenharmony_cistruct VirtgpuTransferToHost2D { 110d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 111d6aed566Sopenharmony_ci struct VirtgpuRect r; 112d6aed566Sopenharmony_ci uint64_t offset; 113d6aed566Sopenharmony_ci uint32_t resourceId; 114d6aed566Sopenharmony_ci uint32_t padding; 115d6aed566Sopenharmony_ci}; 116d6aed566Sopenharmony_ci 117d6aed566Sopenharmony_cistruct Virtgpu { 118d6aed566Sopenharmony_ci struct VirtmmioDev dev; 119d6aed566Sopenharmony_ci OSAL_DECLARE_TIMER(timer); /* refresh timer */ 120d6aed566Sopenharmony_ci 121d6aed566Sopenharmony_ci struct VirtgpuRect screen; 122d6aed566Sopenharmony_ci uint8_t *fb; /* frame buffer */ 123d6aed566Sopenharmony_ci bool edid; 124d6aed566Sopenharmony_ci 125d6aed566Sopenharmony_ci /* 126d6aed566Sopenharmony_ci * Normal operations(timer refresh) request/response buffers. 127d6aed566Sopenharmony_ci * We do not wait for their completion, so they must be static memory. 128d6aed566Sopenharmony_ci * When an operation happened, the last one must already done. 129d6aed566Sopenharmony_ci * Response is shared and ignored. 130d6aed566Sopenharmony_ci * 131d6aed566Sopenharmony_ci * control queue 4 descs: 0-trans_req 1-trans_resp 2-flush_req 3-flush_resp 132d6aed566Sopenharmony_ci * 0-... (30Hz is enough to avoid override) 133d6aed566Sopenharmony_ci */ 134d6aed566Sopenharmony_ci struct VirtgpuResourceFlush flushReq; 135d6aed566Sopenharmony_ci struct VirtgpuTransferToHost2D transReq; 136d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp; 137d6aed566Sopenharmony_ci}; 138d6aed566Sopenharmony_cistatic struct Virtgpu *g_virtGpu; /* fb module need this data, using global for simplicity */ 139d6aed566Sopenharmony_ci 140d6aed566Sopenharmony_cistatic const char *ErrString(int err) 141d6aed566Sopenharmony_ci{ 142d6aed566Sopenharmony_ci switch (err) { 143d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_UNSPEC: return "unspec"; 144d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY: return "out of memory"; 145d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID: return "invalid scanout ID"; 146d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID: return "invalid resource ID"; 147d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID: return "invalid context ID"; 148d6aed566Sopenharmony_ci case VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER: return "invalid parameter"; 149d6aed566Sopenharmony_ci default: break; 150d6aed566Sopenharmony_ci } 151d6aed566Sopenharmony_ci return "unknown error"; 152d6aed566Sopenharmony_ci} 153d6aed566Sopenharmony_ci 154d6aed566Sopenharmony_cistatic bool Feature0(uint32_t features, uint32_t *supported, void *dev) 155d6aed566Sopenharmony_ci{ 156d6aed566Sopenharmony_ci struct Virtgpu *gpu = dev; 157d6aed566Sopenharmony_ci 158d6aed566Sopenharmony_ci if (features & VIRTIO_GPU_F_EDID) { 159d6aed566Sopenharmony_ci *supported |= VIRTIO_GPU_F_EDID; 160d6aed566Sopenharmony_ci gpu->edid = true; 161d6aed566Sopenharmony_ci } 162d6aed566Sopenharmony_ci 163d6aed566Sopenharmony_ci return true; 164d6aed566Sopenharmony_ci} 165d6aed566Sopenharmony_ci 166d6aed566Sopenharmony_cistatic bool Feature1(uint32_t features, uint32_t *supported, void *dev) 167d6aed566Sopenharmony_ci{ 168d6aed566Sopenharmony_ci (void)dev; 169d6aed566Sopenharmony_ci if (features & VIRTIO_F_VERSION_1) { 170d6aed566Sopenharmony_ci *supported |= VIRTIO_F_VERSION_1; 171d6aed566Sopenharmony_ci } else { 172d6aed566Sopenharmony_ci HDF_LOGE("[%s]virtio-gpu has no VERSION_1 feature", __func__); 173d6aed566Sopenharmony_ci return false; 174d6aed566Sopenharmony_ci } 175d6aed566Sopenharmony_ci 176d6aed566Sopenharmony_ci return true; 177d6aed566Sopenharmony_ci} 178d6aed566Sopenharmony_ci 179d6aed566Sopenharmony_cistatic bool NotifyAndWaitResponse(unsigned queue, struct Virtq *q, const void *req, volatile void *resp) 180d6aed566Sopenharmony_ci{ 181d6aed566Sopenharmony_ci const struct VirtgpuCtrlHdr *a = req; 182d6aed566Sopenharmony_ci volatile struct VirtgpuCtrlHdr *b = resp; 183d6aed566Sopenharmony_ci 184d6aed566Sopenharmony_ci /* always use desc[0] [1] ([2]) for request-wait-response */ 185d6aed566Sopenharmony_ci q->avail->ring[q->avail->index % q->qsz] = 0; 186d6aed566Sopenharmony_ci DSB; 187d6aed566Sopenharmony_ci q->avail->index++; 188d6aed566Sopenharmony_ci OSAL_WRITEL(queue, g_virtGpu->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 189d6aed566Sopenharmony_ci 190d6aed566Sopenharmony_ci /* spin for response */ 191d6aed566Sopenharmony_ci while ((q->last == q->used->index) || 192d6aed566Sopenharmony_ci ((a->flags == VIRTIO_GPU_FLAG_FENCE) && (a->fenceId != b->fenceId))) { 193d6aed566Sopenharmony_ci DSB; 194d6aed566Sopenharmony_ci } 195d6aed566Sopenharmony_ci q->last++; 196d6aed566Sopenharmony_ci 197d6aed566Sopenharmony_ci if ((b->type < VIRTIO_GPU_RESP_OK_NODATA) || (b->type > VIRTIO_GPU_RESP_OK_EDID)) { 198d6aed566Sopenharmony_ci HDF_LOGE("[%s]virtio-gpu command=0x%x error=0x%x: %s", __func__, a->type, b->type, ErrString(b->type)); 199d6aed566Sopenharmony_ci return false; 200d6aed566Sopenharmony_ci } 201d6aed566Sopenharmony_ci 202d6aed566Sopenharmony_ci return true; 203d6aed566Sopenharmony_ci} 204d6aed566Sopenharmony_ci 205d6aed566Sopenharmony_cistatic bool RequestResponse(unsigned queue, const void *req, size_t reqSize, volatile void *resp, size_t respSize) 206d6aed566Sopenharmony_ci{ 207d6aed566Sopenharmony_ci struct Virtq *q = &g_virtGpu->dev.vq[queue]; 208d6aed566Sopenharmony_ci uint16_t idx = 0; 209d6aed566Sopenharmony_ci 210d6aed566Sopenharmony_ci /* NOTE: We need these data physical continuous. They came from kernel stack, so they must. */ 211d6aed566Sopenharmony_ci q->desc[idx].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)req)); 212d6aed566Sopenharmony_ci q->desc[idx].len = reqSize; 213d6aed566Sopenharmony_ci q->desc[idx].flag = VIRTQ_DESC_F_NEXT; 214d6aed566Sopenharmony_ci q->desc[idx].next = idx + 1; 215d6aed566Sopenharmony_ci idx++; 216d6aed566Sopenharmony_ci q->desc[idx].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)resp)); 217d6aed566Sopenharmony_ci q->desc[idx].len = respSize; 218d6aed566Sopenharmony_ci q->desc[idx].flag = VIRTQ_DESC_F_WRITE; 219d6aed566Sopenharmony_ci 220d6aed566Sopenharmony_ci return NotifyAndWaitResponse(queue, q, req, resp); 221d6aed566Sopenharmony_ci} 222d6aed566Sopenharmony_ci 223d6aed566Sopenharmony_cistatic bool RequestDataResponse(const void *req, size_t reqSize, const void *data, 224d6aed566Sopenharmony_ci size_t dataSize, volatile void *resp, size_t respSize) 225d6aed566Sopenharmony_ci{ 226d6aed566Sopenharmony_ci struct Virtq *q = &g_virtGpu->dev.vq[0]; 227d6aed566Sopenharmony_ci uint16_t idx = 0; 228d6aed566Sopenharmony_ci 229d6aed566Sopenharmony_ci q->desc[idx].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)req)); 230d6aed566Sopenharmony_ci q->desc[idx].len = reqSize; 231d6aed566Sopenharmony_ci q->desc[idx].flag = VIRTQ_DESC_F_NEXT; 232d6aed566Sopenharmony_ci q->desc[idx].next = idx + 1; 233d6aed566Sopenharmony_ci idx++; 234d6aed566Sopenharmony_ci q->desc[idx].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)data)); 235d6aed566Sopenharmony_ci q->desc[idx].len = dataSize; 236d6aed566Sopenharmony_ci q->desc[idx].flag = VIRTQ_DESC_F_NEXT; 237d6aed566Sopenharmony_ci q->desc[idx].next = idx + 1; 238d6aed566Sopenharmony_ci idx++; 239d6aed566Sopenharmony_ci q->desc[idx].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)resp)); 240d6aed566Sopenharmony_ci q->desc[idx].len = respSize; 241d6aed566Sopenharmony_ci q->desc[idx].flag = VIRTQ_DESC_F_WRITE; 242d6aed566Sopenharmony_ci 243d6aed566Sopenharmony_ci return NotifyAndWaitResponse(0, q, req, resp); 244d6aed566Sopenharmony_ci} 245d6aed566Sopenharmony_ci 246d6aed566Sopenharmony_ci/* For normal display refresh, do not wait response */ 247d6aed566Sopenharmony_cistatic void RequestNoResponse(unsigned queue, const void *req, size_t reqSize, bool notify) 248d6aed566Sopenharmony_ci{ 249d6aed566Sopenharmony_ci struct Virtq *q = &g_virtGpu->dev.vq[queue]; 250d6aed566Sopenharmony_ci uint16_t head = q->last % q->qsz; /* `last` record next writable desc entry for request */ 251d6aed566Sopenharmony_ci 252d6aed566Sopenharmony_ci /* QEMU is busy for the full queue, give up this request */ 253d6aed566Sopenharmony_ci if (abs(q->avail->index - (volatile uint16_t)q->used->index) >= VIRTQ_CONTROL_QSZ) { 254d6aed566Sopenharmony_ci return; 255d6aed566Sopenharmony_ci } 256d6aed566Sopenharmony_ci 257d6aed566Sopenharmony_ci /* other fields initiated by PopulateVirtQ */ 258d6aed566Sopenharmony_ci q->desc[head].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)req)); 259d6aed566Sopenharmony_ci q->desc[head].len = reqSize; 260d6aed566Sopenharmony_ci q->last += NORMAL_CMD_ENTRIES; 261d6aed566Sopenharmony_ci 262d6aed566Sopenharmony_ci q->avail->ring[q->avail->index % q->qsz] = head; 263d6aed566Sopenharmony_ci DSB; 264d6aed566Sopenharmony_ci q->avail->index++; 265d6aed566Sopenharmony_ci 266d6aed566Sopenharmony_ci if (notify) { 267d6aed566Sopenharmony_ci OSAL_WRITEL(queue, g_virtGpu->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 268d6aed566Sopenharmony_ci } 269d6aed566Sopenharmony_ci} 270d6aed566Sopenharmony_ci 271d6aed566Sopenharmony_ci#define VIRTIO_GPU_MAX_SCANOUTS 16 272d6aed566Sopenharmony_cistruct VirtgpuRespDisplayInfo { 273d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 274d6aed566Sopenharmony_ci struct { 275d6aed566Sopenharmony_ci struct VirtgpuRect r; 276d6aed566Sopenharmony_ci uint32_t enabled; 277d6aed566Sopenharmony_ci uint32_t flags; 278d6aed566Sopenharmony_ci } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; 279d6aed566Sopenharmony_ci}; 280d6aed566Sopenharmony_cistatic void CMDGetDisplayInfo(void) 281d6aed566Sopenharmony_ci{ 282d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr req = { 283d6aed566Sopenharmony_ci .type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO 284d6aed566Sopenharmony_ci }; 285d6aed566Sopenharmony_ci struct VirtgpuRespDisplayInfo resp = { 0 }; 286d6aed566Sopenharmony_ci 287d6aed566Sopenharmony_ci if (!RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp))) { 288d6aed566Sopenharmony_ci goto DEFAULT; 289d6aed566Sopenharmony_ci } 290d6aed566Sopenharmony_ci 291d6aed566Sopenharmony_ci if (resp.pmodes[0].enabled) { 292d6aed566Sopenharmony_ci g_virtGpu->screen = resp.pmodes[0].r; 293d6aed566Sopenharmony_ci return; 294d6aed566Sopenharmony_ci } else { 295d6aed566Sopenharmony_ci HDF_LOGE("[%s]scanout 0 not enabled", __func__); 296d6aed566Sopenharmony_ci } 297d6aed566Sopenharmony_ci 298d6aed566Sopenharmony_ciDEFAULT: 299d6aed566Sopenharmony_ci g_virtGpu->screen.x = g_virtGpu->screen.y = 0; 300d6aed566Sopenharmony_ci g_virtGpu->screen.width = FB_WIDTH_DFT; 301d6aed566Sopenharmony_ci g_virtGpu->screen.height = FB_HEIGHT_DFT; 302d6aed566Sopenharmony_ci} 303d6aed566Sopenharmony_ci 304d6aed566Sopenharmony_ci/* reserved for future use */ 305d6aed566Sopenharmony_cistruct VirtgpuGetEdid { 306d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 307d6aed566Sopenharmony_ci uint32_t scanout; 308d6aed566Sopenharmony_ci uint32_t padding; 309d6aed566Sopenharmony_ci}; 310d6aed566Sopenharmony_cistruct VirtgpuRespEdid { 311d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 312d6aed566Sopenharmony_ci uint32_t size; 313d6aed566Sopenharmony_ci uint32_t padding; 314d6aed566Sopenharmony_ci uint8_t edid[1024]; 315d6aed566Sopenharmony_ci}; 316d6aed566Sopenharmony_cistatic void CMDGetEdid(void) 317d6aed566Sopenharmony_ci{ 318d6aed566Sopenharmony_ci struct VirtgpuGetEdid req = { 319d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_GET_EDID 320d6aed566Sopenharmony_ci }; 321d6aed566Sopenharmony_ci struct VirtgpuRespEdid resp = { 0 }; 322d6aed566Sopenharmony_ci 323d6aed566Sopenharmony_ci if (!RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp))) { 324d6aed566Sopenharmony_ci goto DEFAULT; 325d6aed566Sopenharmony_ci } 326d6aed566Sopenharmony_ci 327d6aed566Sopenharmony_ciDEFAULT: 328d6aed566Sopenharmony_ci return; 329d6aed566Sopenharmony_ci} 330d6aed566Sopenharmony_ci 331d6aed566Sopenharmony_cistruct VirtgpuResourceCreate2D { 332d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 333d6aed566Sopenharmony_ci uint32_t resourceId; 334d6aed566Sopenharmony_ci uint32_t format; 335d6aed566Sopenharmony_ci uint32_t width; 336d6aed566Sopenharmony_ci uint32_t height; 337d6aed566Sopenharmony_ci}; 338d6aed566Sopenharmony_cistatic bool CMDResourceCreate2D(uint32_t resourceId) 339d6aed566Sopenharmony_ci{ 340d6aed566Sopenharmony_ci struct VirtgpuResourceCreate2D req = { 341d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, 342d6aed566Sopenharmony_ci .resourceId = resourceId, 343d6aed566Sopenharmony_ci .format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM, /* sRGB, byte order: RGBARGBA... */ 344d6aed566Sopenharmony_ci .width = (resourceId == RESOURCEID_FB) ? g_virtGpu->screen.width : 0, 345d6aed566Sopenharmony_ci .height = (resourceId == RESOURCEID_FB) ? g_virtGpu->screen.height : 0 346d6aed566Sopenharmony_ci }; 347d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp = { 0 }; 348d6aed566Sopenharmony_ci 349d6aed566Sopenharmony_ci return RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp)); 350d6aed566Sopenharmony_ci} 351d6aed566Sopenharmony_ci 352d6aed566Sopenharmony_cistruct VirtgpuSetScanout { 353d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 354d6aed566Sopenharmony_ci struct VirtgpuRect r; 355d6aed566Sopenharmony_ci uint32_t scanoutId; 356d6aed566Sopenharmony_ci uint32_t resourceId; 357d6aed566Sopenharmony_ci}; 358d6aed566Sopenharmony_cistatic bool CMDSetScanout(const struct VirtgpuRect *r) 359d6aed566Sopenharmony_ci{ 360d6aed566Sopenharmony_ci struct VirtgpuSetScanout req = { 361d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT, 362d6aed566Sopenharmony_ci .r = *r, 363d6aed566Sopenharmony_ci .resourceId = RESOURCEID_FB 364d6aed566Sopenharmony_ci }; 365d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp = { 0 }; 366d6aed566Sopenharmony_ci 367d6aed566Sopenharmony_ci return RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp)); 368d6aed566Sopenharmony_ci} 369d6aed566Sopenharmony_ci 370d6aed566Sopenharmony_cistatic bool CMDTransferToHost(uint32_t resourceId, const struct VirtgpuRect *r) 371d6aed566Sopenharmony_ci{ 372d6aed566Sopenharmony_ci struct VirtgpuTransferToHost2D req = { 373d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, 374d6aed566Sopenharmony_ci .hdr.flags = VIRTIO_GPU_FLAG_FENCE, 375d6aed566Sopenharmony_ci .hdr.fenceId = r->x + r->y + r->width + r->height, 376d6aed566Sopenharmony_ci .r = *r, 377d6aed566Sopenharmony_ci .resourceId = resourceId, 378d6aed566Sopenharmony_ci }; 379d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp = { 0 }; 380d6aed566Sopenharmony_ci 381d6aed566Sopenharmony_ci return RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp)); 382d6aed566Sopenharmony_ci} 383d6aed566Sopenharmony_ci 384d6aed566Sopenharmony_cistatic bool CMDResourceFlush(void) 385d6aed566Sopenharmony_ci{ 386d6aed566Sopenharmony_ci struct VirtgpuResourceFlush req = { 387d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH, 388d6aed566Sopenharmony_ci .r = g_virtGpu->screen, 389d6aed566Sopenharmony_ci .resourceId = RESOURCEID_FB, 390d6aed566Sopenharmony_ci }; 391d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp = { 0 }; 392d6aed566Sopenharmony_ci 393d6aed566Sopenharmony_ci return RequestResponse(0, &req, sizeof(req), &resp, sizeof(resp)); 394d6aed566Sopenharmony_ci} 395d6aed566Sopenharmony_ci 396d6aed566Sopenharmony_cistruct VirtgpuResourceAttachBacking { 397d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr hdr; 398d6aed566Sopenharmony_ci uint32_t resourceId; 399d6aed566Sopenharmony_ci uint32_t nrEntries; 400d6aed566Sopenharmony_ci}; 401d6aed566Sopenharmony_cistruct VirtgpuMemEntry { 402d6aed566Sopenharmony_ci uint64_t addr; 403d6aed566Sopenharmony_ci uint32_t length; 404d6aed566Sopenharmony_ci uint32_t padding; 405d6aed566Sopenharmony_ci}; 406d6aed566Sopenharmony_ci 407d6aed566Sopenharmony_ci/* vaddr's physical address should be continuous */ 408d6aed566Sopenharmony_cistatic bool CMDResourceAttachBacking(uint32_t resourceId, uint64_t vaddr, uint32_t len) 409d6aed566Sopenharmony_ci{ 410d6aed566Sopenharmony_ci struct VirtgpuResourceAttachBacking req = { 411d6aed566Sopenharmony_ci .hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, 412d6aed566Sopenharmony_ci .resourceId = resourceId, 413d6aed566Sopenharmony_ci .nrEntries = 1 414d6aed566Sopenharmony_ci }; 415d6aed566Sopenharmony_ci struct VirtgpuMemEntry data = { 416d6aed566Sopenharmony_ci .addr = VMM_TO_DMA_ADDR(vaddr), 417d6aed566Sopenharmony_ci .length = len, 418d6aed566Sopenharmony_ci }; 419d6aed566Sopenharmony_ci struct VirtgpuCtrlHdr resp = { 0 }; 420d6aed566Sopenharmony_ci 421d6aed566Sopenharmony_ci return RequestDataResponse(&req, sizeof(req), &data, sizeof(data), &resp, sizeof(resp)); 422d6aed566Sopenharmony_ci} 423d6aed566Sopenharmony_ci 424d6aed566Sopenharmony_cistatic void NormOpsRefresh(uintptr_t arg) 425d6aed566Sopenharmony_ci{ 426d6aed566Sopenharmony_ci (void)arg; 427d6aed566Sopenharmony_ci RequestNoResponse(0, &g_virtGpu->transReq, sizeof(g_virtGpu->transReq), false); 428d6aed566Sopenharmony_ci RequestNoResponse(0, &g_virtGpu->flushReq, sizeof(g_virtGpu->flushReq), true); 429d6aed566Sopenharmony_ci} 430d6aed566Sopenharmony_ci 431d6aed566Sopenharmony_ci/* fit user-space page size mmap */ 432d6aed566Sopenharmony_cistatic inline size_t VirtgpuFbPageSize(void) 433d6aed566Sopenharmony_ci{ 434d6aed566Sopenharmony_ci return g_virtGpu->screen.width * g_virtGpu->screen.height * PIXEL_BYTES; 435d6aed566Sopenharmony_ci} 436d6aed566Sopenharmony_ci 437d6aed566Sopenharmony_cistatic void PopulateVirtQ(void) 438d6aed566Sopenharmony_ci{ 439d6aed566Sopenharmony_ci struct Virtq *q = NULL; 440d6aed566Sopenharmony_ci int i, n; 441d6aed566Sopenharmony_ci uint16_t qsz; 442d6aed566Sopenharmony_ci 443d6aed566Sopenharmony_ci for (n = 0; n < VIRTQ_NUM; n++) { 444d6aed566Sopenharmony_ci if (n) { 445d6aed566Sopenharmony_ci qsz = VIRTQ_CURSOR_QSZ; 446d6aed566Sopenharmony_ci } else { 447d6aed566Sopenharmony_ci qsz = VIRTQ_CONTROL_QSZ; 448d6aed566Sopenharmony_ci } 449d6aed566Sopenharmony_ci q = &g_virtGpu->dev.vq[n]; 450d6aed566Sopenharmony_ci 451d6aed566Sopenharmony_ci for (i = 0; i < qsz; i += NORMAL_CMD_ENTRIES) { 452d6aed566Sopenharmony_ci q->desc[i].flag = VIRTQ_DESC_F_NEXT; 453d6aed566Sopenharmony_ci q->desc[i].next = i + 1; 454d6aed566Sopenharmony_ci q->desc[i + 1].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)&g_virtGpu->resp)); 455d6aed566Sopenharmony_ci q->desc[i + 1].len = sizeof(g_virtGpu->resp); 456d6aed566Sopenharmony_ci q->desc[i + 1].flag = VIRTQ_DESC_F_WRITE; 457d6aed566Sopenharmony_ci } 458d6aed566Sopenharmony_ci /* change usage to record our next writable index */ 459d6aed566Sopenharmony_ci q->last = 0; 460d6aed566Sopenharmony_ci } 461d6aed566Sopenharmony_ci 462d6aed566Sopenharmony_ci g_virtGpu->transReq.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; 463d6aed566Sopenharmony_ci g_virtGpu->transReq.r = g_virtGpu->screen; 464d6aed566Sopenharmony_ci g_virtGpu->transReq.resourceId = RESOURCEID_FB; 465d6aed566Sopenharmony_ci 466d6aed566Sopenharmony_ci g_virtGpu->flushReq.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; 467d6aed566Sopenharmony_ci g_virtGpu->flushReq.r = g_virtGpu->screen; 468d6aed566Sopenharmony_ci g_virtGpu->flushReq.resourceId = RESOURCEID_FB; 469d6aed566Sopenharmony_ci} 470d6aed566Sopenharmony_ci 471d6aed566Sopenharmony_cistatic bool VirtgpuBeginNormDisplay(void) 472d6aed566Sopenharmony_ci{ 473d6aed566Sopenharmony_ci int32_t ret; 474d6aed566Sopenharmony_ci 475d6aed566Sopenharmony_ci if (!CMDTransferToHost(RESOURCEID_FB, &g_virtGpu->screen)) { 476d6aed566Sopenharmony_ci return false; 477d6aed566Sopenharmony_ci } 478d6aed566Sopenharmony_ci if (!CMDResourceFlush()) { 479d6aed566Sopenharmony_ci return false; 480d6aed566Sopenharmony_ci } 481d6aed566Sopenharmony_ci 482d6aed566Sopenharmony_ci /* now we can fix queue entries to avoid redundant when do normal OPs */ 483d6aed566Sopenharmony_ci PopulateVirtQ(); 484d6aed566Sopenharmony_ci 485d6aed566Sopenharmony_ci if ((ret = OsalTimerStartLoop(&g_virtGpu->timer)) != HDF_SUCCESS) { 486d6aed566Sopenharmony_ci HDF_LOGE("[%s]start timer failed: %d\n", __func__, ret); 487d6aed566Sopenharmony_ci return false; 488d6aed566Sopenharmony_ci } 489d6aed566Sopenharmony_ci 490d6aed566Sopenharmony_ci return true; 491d6aed566Sopenharmony_ci} 492d6aed566Sopenharmony_ci 493d6aed566Sopenharmony_ci/* unified DeInit for InitDev, HDF and fb */ 494d6aed566Sopenharmony_cistatic void VirtgpuDeInit(struct Virtgpu *gpu) 495d6aed566Sopenharmony_ci{ 496d6aed566Sopenharmony_ci if (gpu->timer.realTimer) { 497d6aed566Sopenharmony_ci OsalTimerDelete(&gpu->timer); 498d6aed566Sopenharmony_ci } 499d6aed566Sopenharmony_ci if (gpu->fb) { 500d6aed566Sopenharmony_ci LOS_MemFree(OS_SYS_MEM_ADDR, gpu->fb); 501d6aed566Sopenharmony_ci } 502d6aed566Sopenharmony_ci LOS_MemFree(OS_SYS_MEM_ADDR, gpu); 503d6aed566Sopenharmony_ci g_virtGpu = NULL; 504d6aed566Sopenharmony_ci} 505d6aed566Sopenharmony_ci 506d6aed566Sopenharmony_cistatic struct Virtgpu *VirtgpuInitDev(void) 507d6aed566Sopenharmony_ci{ 508d6aed566Sopenharmony_ci struct Virtgpu *gpu = NULL; 509d6aed566Sopenharmony_ci VADDR_T base; 510d6aed566Sopenharmony_ci uint16_t qsz[VIRTQ_NUM]; 511d6aed566Sopenharmony_ci int32_t ret, len; 512d6aed566Sopenharmony_ci 513d6aed566Sopenharmony_ci /* NOTE: For simplicity, alloc all these data from physical continuous memory. */ 514d6aed566Sopenharmony_ci len = sizeof(struct Virtgpu) + VirtqSize(VIRTQ_CONTROL_QSZ) + VirtqSize(VIRTQ_CURSOR_QSZ); 515d6aed566Sopenharmony_ci gpu = LOS_MemAlloc(OS_SYS_MEM_ADDR, len * sizeof(void *)); 516d6aed566Sopenharmony_ci if (gpu != NULL) { 517d6aed566Sopenharmony_ci (void)memset_s(gpu, len * sizeof(void *), 0, len * sizeof(void *)); 518d6aed566Sopenharmony_ci } else { 519d6aed566Sopenharmony_ci HDF_LOGE("[%s]alloc gpu memory failed\n", __func__); 520d6aed566Sopenharmony_ci return NULL; 521d6aed566Sopenharmony_ci } 522d6aed566Sopenharmony_ci 523d6aed566Sopenharmony_ci if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_GPU, &gpu->dev)) { 524d6aed566Sopenharmony_ci HDF_LOGE("[%s]VirtmmioDiscover failed\n", __func__); 525d6aed566Sopenharmony_ci goto ERR_OUT; 526d6aed566Sopenharmony_ci } 527d6aed566Sopenharmony_ci 528d6aed566Sopenharmony_ci VirtmmioInitBegin(&gpu->dev); 529d6aed566Sopenharmony_ci 530d6aed566Sopenharmony_ci if (!VirtmmioNegotiate(&gpu->dev, Feature0, Feature1, gpu)) { 531d6aed566Sopenharmony_ci HDF_LOGE("[%s]VirtmmioNegotiate failed\n", __func__); 532d6aed566Sopenharmony_ci goto ERR_OUT1; 533d6aed566Sopenharmony_ci } 534d6aed566Sopenharmony_ci 535d6aed566Sopenharmony_ci base = ALIGN((VADDR_T)gpu + sizeof(struct Virtgpu), VIRTQ_ALIGN_DESC); 536d6aed566Sopenharmony_ci qsz[0] = VIRTQ_CONTROL_QSZ; 537d6aed566Sopenharmony_ci qsz[1] = VIRTQ_CURSOR_QSZ; 538d6aed566Sopenharmony_ci if (VirtmmioConfigQueue(&gpu->dev, base, qsz, VIRTQ_NUM) == 0) { 539d6aed566Sopenharmony_ci HDF_LOGE("[%s]VirtmmioConfigQueue failed\n", __func__); 540d6aed566Sopenharmony_ci goto ERR_OUT1; 541d6aed566Sopenharmony_ci } 542d6aed566Sopenharmony_ci 543d6aed566Sopenharmony_ci /* framebuffer can be modified at any time, so we need a full screen refresh timer */ 544d6aed566Sopenharmony_ci ret = OsalTimerCreate(&gpu->timer, GPU_DFT_RATE, NormOpsRefresh, 0); 545d6aed566Sopenharmony_ci if (ret != HDF_SUCCESS) { 546d6aed566Sopenharmony_ci HDF_LOGE("[%s]create timer failed: %d\n", __func__, ret); 547d6aed566Sopenharmony_ci goto ERR_OUT1; 548d6aed566Sopenharmony_ci } 549d6aed566Sopenharmony_ci 550d6aed566Sopenharmony_ci for (int i = 0; i < VIRTQ_NUM; i++) { /* hint device not using IRQ */ 551d6aed566Sopenharmony_ci gpu->dev.vq[i].avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT; 552d6aed566Sopenharmony_ci } 553d6aed566Sopenharmony_ci 554d6aed566Sopenharmony_ci VritmmioInitEnd(&gpu->dev); /* now virt queue can be used */ 555d6aed566Sopenharmony_ci return gpu; 556d6aed566Sopenharmony_ci 557d6aed566Sopenharmony_ciERR_OUT1: 558d6aed566Sopenharmony_ci VirtmmioInitFailed(&gpu->dev); 559d6aed566Sopenharmony_ciERR_OUT: 560d6aed566Sopenharmony_ci VirtgpuDeInit(gpu); 561d6aed566Sopenharmony_ci return NULL; 562d6aed566Sopenharmony_ci} 563d6aed566Sopenharmony_ci 564d6aed566Sopenharmony_cistatic int32_t HdfVirtgpuInit(struct HdfDeviceObject *device) 565d6aed566Sopenharmony_ci{ 566d6aed566Sopenharmony_ci int32_t ret; 567d6aed566Sopenharmony_ci HDF_LOGI("HdfVirtgpuInit begin!......\n"); 568d6aed566Sopenharmony_ci 569d6aed566Sopenharmony_ci if (device == NULL) { 570d6aed566Sopenharmony_ci HDF_LOGE("[%s]device is null", __func__); 571d6aed566Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 572d6aed566Sopenharmony_ci } 573d6aed566Sopenharmony_ci 574d6aed566Sopenharmony_ci g_virtGpu = VirtgpuInitDev(); 575d6aed566Sopenharmony_ci if (g_virtGpu == NULL) { 576d6aed566Sopenharmony_ci return HDF_FAILURE; 577d6aed566Sopenharmony_ci } 578d6aed566Sopenharmony_ci device->priv = g_virtGpu; 579d6aed566Sopenharmony_ci 580d6aed566Sopenharmony_ci /* frame buffer resource are initiated here, using virt queue mechanism */ 581d6aed566Sopenharmony_ci if ((ret = fb_register(0, 0)) != 0) { 582d6aed566Sopenharmony_ci HDF_LOGE("[%s]framebuffer register failed: %d", __func__, ret); 583d6aed566Sopenharmony_ci return HDF_FAILURE; 584d6aed566Sopenharmony_ci } 585d6aed566Sopenharmony_ci 586d6aed566Sopenharmony_ci if (!VirtgpuBeginNormDisplay()) { 587d6aed566Sopenharmony_ci return HDF_FAILURE; 588d6aed566Sopenharmony_ci } 589d6aed566Sopenharmony_ci 590d6aed566Sopenharmony_ci HDF_LOGI("HdfVirtgpuInit end!......\n"); 591d6aed566Sopenharmony_ci 592d6aed566Sopenharmony_ci return HDF_SUCCESS; 593d6aed566Sopenharmony_ci} 594d6aed566Sopenharmony_ci 595d6aed566Sopenharmony_cistatic void HdfVirtgpuRelease(struct HdfDeviceObject *deviceObject) 596d6aed566Sopenharmony_ci{ 597d6aed566Sopenharmony_ci if (deviceObject) { 598d6aed566Sopenharmony_ci if (deviceObject->priv) { 599d6aed566Sopenharmony_ci fb_unregister(0); 600d6aed566Sopenharmony_ci } 601d6aed566Sopenharmony_ci } 602d6aed566Sopenharmony_ci} 603d6aed566Sopenharmony_ci 604d6aed566Sopenharmony_cistruct HdfDriverEntry g_virtGpuEntry = { 605d6aed566Sopenharmony_ci .moduleVersion = 1, 606d6aed566Sopenharmony_ci .moduleName = "HDF_VIRTIO_GPU", 607d6aed566Sopenharmony_ci .Init = HdfVirtgpuInit, 608d6aed566Sopenharmony_ci .Release = HdfVirtgpuRelease, 609d6aed566Sopenharmony_ci}; 610d6aed566Sopenharmony_ci 611d6aed566Sopenharmony_ciHDF_INIT(g_virtGpuEntry); 612d6aed566Sopenharmony_ci 613d6aed566Sopenharmony_ci 614d6aed566Sopenharmony_ci/* 615d6aed566Sopenharmony_ci * video/fb.h interface implementation 616d6aed566Sopenharmony_ci */ 617d6aed566Sopenharmony_ci 618d6aed566Sopenharmony_cistatic bool VirtgpuInitResourceHelper(uint32_t resourceId) 619d6aed566Sopenharmony_ci{ 620d6aed566Sopenharmony_ci uint64_t va; 621d6aed566Sopenharmony_ci uint32_t len, w, h; 622d6aed566Sopenharmony_ci 623d6aed566Sopenharmony_ci if (!CMDResourceCreate2D(resourceId)) { 624d6aed566Sopenharmony_ci return false; 625d6aed566Sopenharmony_ci } 626d6aed566Sopenharmony_ci 627d6aed566Sopenharmony_ci if (resourceId == RESOURCEID_FB) { 628d6aed566Sopenharmony_ci va = u32_to_u64((uint32_t)g_virtGpu->fb); 629d6aed566Sopenharmony_ci w = g_virtGpu->screen.width; 630d6aed566Sopenharmony_ci h = g_virtGpu->screen.height; 631d6aed566Sopenharmony_ci } else { 632d6aed566Sopenharmony_ci HDF_LOGE("[%s]error resource ID: %u", __func__, resourceId); 633d6aed566Sopenharmony_ci return false; 634d6aed566Sopenharmony_ci } 635d6aed566Sopenharmony_ci len = w * h * PIXEL_BYTES; 636d6aed566Sopenharmony_ci if (!CMDResourceAttachBacking(resourceId, va, len)) { 637d6aed566Sopenharmony_ci return false; 638d6aed566Sopenharmony_ci } 639d6aed566Sopenharmony_ci 640d6aed566Sopenharmony_ci if (resourceId == RESOURCEID_FB) { 641d6aed566Sopenharmony_ci struct VirtgpuRect r = { 0, 0, w, h }; 642d6aed566Sopenharmony_ci return CMDSetScanout(&r); 643d6aed566Sopenharmony_ci } 644d6aed566Sopenharmony_ci return true; 645d6aed566Sopenharmony_ci} 646d6aed566Sopenharmony_ci 647d6aed566Sopenharmony_cistatic bool VirtgpuInitResource(void) 648d6aed566Sopenharmony_ci{ 649d6aed566Sopenharmony_ci /* Framebuffer must be physical continuous. fb_register will zero the buffer */ 650d6aed566Sopenharmony_ci g_virtGpu->fb = LOS_MemAlloc(OS_SYS_MEM_ADDR, VirtgpuFbPageSize()); 651d6aed566Sopenharmony_ci if (g_virtGpu->fb != NULL) { 652d6aed566Sopenharmony_ci (void)memset_s(g_virtGpu->fb, VirtgpuFbPageSize(), 0, VirtgpuFbPageSize()); 653d6aed566Sopenharmony_ci } else { 654d6aed566Sopenharmony_ci HDF_LOGE("[%s]alloc framebuffer memory fail", __func__); 655d6aed566Sopenharmony_ci return false; 656d6aed566Sopenharmony_ci } 657d6aed566Sopenharmony_ci if (!VirtgpuInitResourceHelper(RESOURCEID_FB)) { 658d6aed566Sopenharmony_ci return false; 659d6aed566Sopenharmony_ci } 660d6aed566Sopenharmony_ci 661d6aed566Sopenharmony_ci return true; 662d6aed566Sopenharmony_ci} 663d6aed566Sopenharmony_ci 664d6aed566Sopenharmony_ciint up_fbinitialize(int display) 665d6aed566Sopenharmony_ci{ 666d6aed566Sopenharmony_ci if (display != 0) { 667d6aed566Sopenharmony_ci return -1; 668d6aed566Sopenharmony_ci } 669d6aed566Sopenharmony_ci 670d6aed566Sopenharmony_ci CMDGetDisplayInfo(); 671d6aed566Sopenharmony_ci if (g_virtGpu->edid) { 672d6aed566Sopenharmony_ci CMDGetEdid(); 673d6aed566Sopenharmony_ci } 674d6aed566Sopenharmony_ci 675d6aed566Sopenharmony_ci if (!VirtgpuInitResource()) { 676d6aed566Sopenharmony_ci return -1; 677d6aed566Sopenharmony_ci } 678d6aed566Sopenharmony_ci 679d6aed566Sopenharmony_ci return 0; 680d6aed566Sopenharmony_ci} 681d6aed566Sopenharmony_ci 682d6aed566Sopenharmony_cistatic int FbGetVideoInfo(struct fb_vtable_s *vtable, struct fb_videoinfo_s *vinfo) 683d6aed566Sopenharmony_ci{ 684d6aed566Sopenharmony_ci (void)vtable; 685d6aed566Sopenharmony_ci vinfo->fmt = FB_FMT_RGB32; /* sRGB */ 686d6aed566Sopenharmony_ci vinfo->xres = g_virtGpu->screen.width; 687d6aed566Sopenharmony_ci vinfo->yres = g_virtGpu->screen.height; 688d6aed566Sopenharmony_ci vinfo->nplanes = 1; 689d6aed566Sopenharmony_ci return 0; 690d6aed566Sopenharmony_ci} 691d6aed566Sopenharmony_ci 692d6aed566Sopenharmony_ci#define BYTE_BITS 8 693d6aed566Sopenharmony_cistatic int FbGetPlaneInfo(struct fb_vtable_s *vtable, int planeno, struct fb_planeinfo_s *pinfo) 694d6aed566Sopenharmony_ci{ 695d6aed566Sopenharmony_ci if (planeno != 0) { 696d6aed566Sopenharmony_ci return -1; 697d6aed566Sopenharmony_ci } 698d6aed566Sopenharmony_ci (void)vtable; 699d6aed566Sopenharmony_ci 700d6aed566Sopenharmony_ci pinfo->fbmem = g_virtGpu->fb; 701d6aed566Sopenharmony_ci pinfo->stride = g_virtGpu->screen.width * PIXEL_BYTES; 702d6aed566Sopenharmony_ci pinfo->fblen = pinfo->stride * g_virtGpu->screen.height; 703d6aed566Sopenharmony_ci pinfo->display = 0; 704d6aed566Sopenharmony_ci pinfo->bpp = PIXEL_BYTES * BYTE_BITS; 705d6aed566Sopenharmony_ci return 0; 706d6aed566Sopenharmony_ci} 707d6aed566Sopenharmony_ci 708d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY 709d6aed566Sopenharmony_cistatic int FbGetOverlayInfo(struct fb_vtable_s *v, int overlayno, struct fb_overlayinfo_s *info) 710d6aed566Sopenharmony_ci{ 711d6aed566Sopenharmony_ci (void)v; 712d6aed566Sopenharmony_ci if (overlayno != 0) { 713d6aed566Sopenharmony_ci return -1; 714d6aed566Sopenharmony_ci } 715d6aed566Sopenharmony_ci 716d6aed566Sopenharmony_ci info->fbmem = g_virtGpu->fb; 717d6aed566Sopenharmony_ci info->memphys = (void *)VMM_TO_DMA_ADDR((VADDR_T)g_virtGpu->fb); 718d6aed566Sopenharmony_ci info->stride = g_virtGpu->screen.width * PIXEL_BYTES; 719d6aed566Sopenharmony_ci info->fblen = info->stride * g_virtGpu->screen.height; 720d6aed566Sopenharmony_ci info->overlay = 0; 721d6aed566Sopenharmony_ci info->bpp = PIXEL_BYTES * BYTE_BITS; 722d6aed566Sopenharmony_ci info->accl = 0; 723d6aed566Sopenharmony_ci return 0; 724d6aed566Sopenharmony_ci} 725d6aed566Sopenharmony_ci#endif 726d6aed566Sopenharmony_ci 727d6aed566Sopenharmony_ci/* expect windows manager deal with concurrent access */ 728d6aed566Sopenharmony_cistatic int FbOpen(struct fb_vtable_s *vtable) 729d6aed566Sopenharmony_ci{ 730d6aed566Sopenharmony_ci (void)vtable; 731d6aed566Sopenharmony_ci return 0; 732d6aed566Sopenharmony_ci} 733d6aed566Sopenharmony_ci 734d6aed566Sopenharmony_cistatic int FbRelease(struct fb_vtable_s *vtable) 735d6aed566Sopenharmony_ci{ 736d6aed566Sopenharmony_ci (void)vtable; 737d6aed566Sopenharmony_ci return 0; 738d6aed566Sopenharmony_ci} 739d6aed566Sopenharmony_ci 740d6aed566Sopenharmony_ci/* used to happy video/fb.h configure */ 741d6aed566Sopenharmony_cistatic int FbDummy(struct fb_vtable_s *v, int *s) 742d6aed566Sopenharmony_ci{ 743d6aed566Sopenharmony_ci (void)v; 744d6aed566Sopenharmony_ci (void)s; 745d6aed566Sopenharmony_ci HDF_LOGE("[%s]unsupported method", __func__); 746d6aed566Sopenharmony_ci return -1; 747d6aed566Sopenharmony_ci} 748d6aed566Sopenharmony_ci 749d6aed566Sopenharmony_cistatic struct fb_vtable_s g_virtGpuFbOps = { 750d6aed566Sopenharmony_ci .getvideoinfo = FbGetVideoInfo, 751d6aed566Sopenharmony_ci .getplaneinfo = FbGetPlaneInfo, 752d6aed566Sopenharmony_ci .fb_open = FbOpen, 753d6aed566Sopenharmony_ci .fb_release = FbRelease, 754d6aed566Sopenharmony_ci#ifdef CONFIG_FB_CMAP 755d6aed566Sopenharmony_ci .getcmap = (int (*)(struct fb_vtable_s *, struct fb_cmap_s *))FbDummy, 756d6aed566Sopenharmony_ci .putcmap = (int (*)(struct fb_vtable_s *, const struct fb_cmap_s *))FbDummy, 757d6aed566Sopenharmony_ci#endif 758d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY 759d6aed566Sopenharmony_ci .getoverlayinfo = FbGetOverlayInfo, 760d6aed566Sopenharmony_ci .settransp = (int (*)(struct fb_vtable_s *, const struct fb_overlayinfo_s *))FbDummy, 761d6aed566Sopenharmony_ci .setchromakey = (int (*)(struct fb_vtable_s *, const struct fb_overlayinfo_s *))FbDummy, 762d6aed566Sopenharmony_ci .setcolor = (int (*)(struct fb_vtable_s *, const struct fb_overlayinfo_s *))FbDummy, 763d6aed566Sopenharmony_ci .setblank = (int (*)(struct fb_vtable_s *, const struct fb_overlayinfo_s *))FbDummy, 764d6aed566Sopenharmony_ci .setarea = (int (*)(struct fb_vtable_s *, const struct fb_overlayinfo_s *))FbDummy, 765d6aed566Sopenharmony_ci# ifdef CONFIG_FB_OVERLAY_BLIT 766d6aed566Sopenharmony_ci .blit = (int (*)(struct fb_vtable_s *, const struct fb_overlayblit_s *))FbDummy, 767d6aed566Sopenharmony_ci .blend = (int (*)(struct fb_vtable_s *, const struct fb_overlayblend_s *))FbDummy, 768d6aed566Sopenharmony_ci# endif 769d6aed566Sopenharmony_ci .fb_pan_display = (int (*)(struct fb_vtable_s *, struct fb_overlayinfo_s *))FbDummy, 770d6aed566Sopenharmony_ci#endif 771d6aed566Sopenharmony_ci}; 772d6aed566Sopenharmony_ci 773d6aed566Sopenharmony_cistruct fb_vtable_s *up_fbgetvplane(int display, int vplane) 774d6aed566Sopenharmony_ci{ 775d6aed566Sopenharmony_ci if ((display != 0) || (vplane != 0)) { 776d6aed566Sopenharmony_ci return NULL; 777d6aed566Sopenharmony_ci } 778d6aed566Sopenharmony_ci return &g_virtGpuFbOps; 779d6aed566Sopenharmony_ci} 780d6aed566Sopenharmony_ci 781d6aed566Sopenharmony_civoid up_fbuninitialize(int display) 782d6aed566Sopenharmony_ci{ 783d6aed566Sopenharmony_ci if (display != 0) { 784d6aed566Sopenharmony_ci return; 785d6aed566Sopenharmony_ci } 786d6aed566Sopenharmony_ci 787d6aed566Sopenharmony_ci if (g_virtGpu) { 788d6aed566Sopenharmony_ci VirtgpuDeInit(g_virtGpu); 789d6aed566Sopenharmony_ci } 790d6aed566Sopenharmony_ci} 791