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