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(&region->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}