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