1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-11-11     GuEe-GUI     the first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <cpuport.h>
14 #include <rtdevice.h>
15 
16 #ifdef RT_USING_VIRTIO_GPU
17 
18 #include <virtio_gpu.h>
19 
20 static struct virtio_gpu_device *_primary_virtio_gpu_dev = RT_NULL;
21 
_pixel_format_convert(rt_ubase_t format,rt_bool_t to_virtio_gpu_format)22 static rt_ubase_t _pixel_format_convert(rt_ubase_t format, rt_bool_t to_virtio_gpu_format)
23 {
24     rt_ubase_t ret = 0;
25 
26     if (to_virtio_gpu_format)
27     {
28         switch (format)
29         {
30         case RTGRAPHIC_PIXEL_FORMAT_RGB888:
31             ret = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
32             break;
33         case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
34             ret = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
35             break;
36         case RTGRAPHIC_PIXEL_FORMAT_ABGR888:
37             ret = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
38             break;
39         default:
40             break;
41         }
42     }
43     else
44     {
45         switch (format)
46         {
47         case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
48             ret = RTGRAPHIC_PIXEL_FORMAT_RGB888;
49             break;
50         case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
51             ret = RTGRAPHIC_PIXEL_FORMAT_ARGB888;
52             break;
53         case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
54             ret = RTGRAPHIC_PIXEL_FORMAT_ABGR888;
55             break;
56         default:
57             break;
58         }
59     }
60 
61     return ret;
62 }
63 
virtio_gpu_ctrl_send_command(struct virtio_gpu_device * virtio_gpu_dev,const void * cmd,rt_size_t cmd_len,void * res,rt_size_t res_len)64 static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_dev,
65         const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len)
66 {
67     rt_uint16_t idx[2];
68     void *addr = &virtio_gpu_dev->gpu_request;
69     void *ret_res = ((rt_uint8_t *)addr + cmd_len);
70     struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
71 
72 #ifdef RT_USING_SMP
73     rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
74 #endif
75 
76     while (virtio_alloc_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, 2, idx))
77     {
78 #ifdef RT_USING_SMP
79         rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
80 #endif
81         rt_thread_yield();
82 
83 #ifdef RT_USING_SMP
84         level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
85 #endif
86     }
87 
88     rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
89 
90     virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0],
91             VIRTIO_VA2PA(addr), cmd_len, VIRTQ_DESC_F_NEXT, idx[1]);
92 
93     virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[1],
94             VIRTIO_VA2PA(addr) + cmd_len, res_len, VIRTQ_DESC_F_WRITE, 0);
95 
96     rt_memset(ret_res, 0, res_len);
97 
98     virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
99 
100     virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
101 
102     virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
103 
104     while (virtio_gpu_dev->info[idx[0]].ctrl_valid)
105     {
106 #ifdef RT_USING_SMP
107         rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
108 #endif
109         rt_thread_yield();
110 
111 #ifdef RT_USING_SMP
112         level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
113 #endif
114     }
115 
116     virtio_free_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
117 
118     rt_memcpy(res, ret_res, res_len);
119 
120 #ifdef RT_USING_SMP
121     rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
122 #endif
123 }
124 
virtio_gpu_cursor_send_command(struct virtio_gpu_device * virtio_gpu_dev,const void * cmd,rt_size_t cmd_len)125 static void virtio_gpu_cursor_send_command(struct virtio_gpu_device *virtio_gpu_dev,
126         const void *cmd, rt_size_t cmd_len)
127 {
128     rt_uint16_t id;
129     void *addr;
130     struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
131 
132 #ifdef RT_USING_SMP
133     rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
134 #endif
135 
136     while ((id = virtio_alloc_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR)) == VIRTQ_INVALID_DESC_ID)
137     {
138 #ifdef RT_USING_SMP
139         rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
140 #endif
141         rt_thread_yield();
142 
143 #ifdef RT_USING_SMP
144         level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
145 #endif
146     }
147 
148     addr = &virtio_gpu_dev->info[id].cursor_cmd;
149     virtio_gpu_dev->info[id].cursor_valid = RT_TRUE;
150 
151     rt_memcpy(addr, cmd, cmd_len);
152 
153     virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id, VIRTIO_VA2PA(addr), cmd_len, 0, 0);
154 
155     virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
156 
157     virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR);
158 
159     while (virtio_gpu_dev->info[id].cursor_valid)
160     {
161 #ifdef RT_USING_SMP
162         rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
163 #endif
164         rt_thread_yield();
165 
166 #ifdef RT_USING_SMP
167         level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
168 #endif
169     }
170 
171     virtio_free_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
172 
173 #ifdef RT_USING_SMP
174     rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
175 #endif
176 }
177 
virtio_gpu_create_2d_resource(struct virtio_gpu_device * virtio_gpu_dev,enum virtio_gpu_formats format,rt_uint32_t * resource_id,rt_uint32_t width,rt_uint32_t height)178 static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu_device *virtio_gpu_dev, enum virtio_gpu_formats format,
179         rt_uint32_t *resource_id, rt_uint32_t width, rt_uint32_t height)
180 {
181     struct virtio_gpu_ctrl_hdr res;
182     struct virtio_gpu_resource_create_2d req;
183 
184     *resource_id = ++virtio_gpu_dev->next_resource_id;
185 
186     req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
187     req.resource_id = *resource_id;
188     req.format = format;
189     req.width = width;
190     req.height = height;
191 
192     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
193 
194     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
195     {
196         return RT_EOK;
197     }
198 
199     return -RT_ERROR;
200 }
201 
virtio_gpu_unref_resource(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t resource_id)202 static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id)
203 {
204     struct virtio_gpu_ctrl_hdr res;
205     struct virtio_gpu_resource_unref req;
206 
207     rt_memset(&req, 0, sizeof(req));
208 
209     req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF;
210     req.resource_id = resource_id;
211 
212     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
213 
214     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
215     {
216         return RT_EOK;
217     }
218 
219     return -RT_ERROR;
220 }
221 
virtio_gpu_attach_backing_resource(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t resource_id,void * buffer,rt_size_t size)222 static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
223         void *buffer, rt_size_t size)
224 {
225     struct virtio_gpu_ctrl_hdr res;
226     struct
227     {
228         struct virtio_gpu_resource_attach_backing req;
229         struct virtio_gpu_mem_entry mem;
230     } req;
231 
232     rt_memset(&req, 0, sizeof(req));
233 
234     req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
235     req.req.resource_id = resource_id;
236     req.req.nr_entries = 1;
237 
238     req.mem.addr = VIRTIO_VA2PA(buffer);
239     req.mem.length = size;
240 
241     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
242 
243     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
244     {
245         return RT_EOK;
246     }
247 
248     return -RT_ERROR;
249 }
250 
virtio_gpu_set_scanout(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t scanout_id,rt_uint32_t resource_id,rt_uint32_t width,rt_uint32_t height)251 static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
252         rt_uint32_t resource_id, rt_uint32_t width, rt_uint32_t height)
253 {
254     struct virtio_gpu_ctrl_hdr res;
255     struct virtio_gpu_set_scanout req;
256 
257     rt_memset(&req, 0, sizeof(req));
258 
259     req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
260     req.r.x = 0;
261     req.r.y = 0;
262     req.r.width = width;
263     req.r.height = height;
264     req.scanout_id = scanout_id;
265     req.resource_id = resource_id;
266 
267     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
268 
269     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
270     {
271         return RT_EOK;
272     }
273 
274     return -RT_ERROR;
275 }
276 
virtio_gpu_flush_resource(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t resource_id,rt_uint32_t x,rt_uint32_t y,rt_uint32_t width,rt_uint32_t height)277 static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
278         rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
279 {
280     struct virtio_gpu_ctrl_hdr res;
281     struct virtio_gpu_resource_flush req;
282 
283     rt_memset(&req, 0, sizeof(req));
284 
285     req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
286     req.r.x = x;
287     req.r.y = y;
288     req.r.width = width;
289     req.r.height = height;
290     req.resource_id = resource_id;
291 
292     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
293 
294     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
295     {
296         return RT_EOK;
297     }
298 
299     return -RT_ERROR;
300 }
301 
virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t resource_id,rt_uint32_t x,rt_uint32_t y,rt_uint32_t width,rt_uint32_t height,rt_uint32_t offset)302 static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
303         rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, rt_uint32_t offset)
304 {
305     struct virtio_gpu_ctrl_hdr res;
306     struct virtio_gpu_transfer_to_host_2d req;
307 
308     rt_memset(&req, 0, sizeof(req));
309 
310     req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
311     req.r.x = x;
312     req.r.y = y;
313     req.r.width = width;
314     req.r.height = height;
315     req.offset = offset;
316     req.resource_id = resource_id;
317 
318     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
319 
320     if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
321     {
322         return RT_EOK;
323     }
324 
325     return -RT_ERROR;
326 }
327 
virtio_gpu_gfx_flush_2d(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t resource_id,rt_uint32_t x,rt_uint32_t y,rt_uint32_t width,rt_uint32_t height)328 static rt_err_t virtio_gpu_gfx_flush_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
329         rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
330 {
331     rt_err_t status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, resource_id, x, y, width, height, 0);
332 
333     if (status == RT_EOK)
334     {
335         status = virtio_gpu_flush_resource(virtio_gpu_dev, resource_id, x, y, width, height);
336     }
337 
338     return status;
339 }
340 
virtio_gpu_update_cursor(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t scanout_id,rt_uint32_t resource_id,rt_uint32_t hot_x,rt_uint32_t hot_y)341 static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
342         rt_uint32_t resource_id, rt_uint32_t hot_x, rt_uint32_t hot_y)
343 {
344     struct virtio_gpu_update_cursor req;
345 
346     rt_memset(&req, 0, sizeof(req));
347 
348     req.hdr.type = VIRTIO_GPU_CMD_UPDATE_CURSOR;
349     req.pos.scanout_id = scanout_id;
350     req.resource_id = resource_id;
351     req.hot_x = hot_x;
352     req.hot_y = hot_y;
353 
354     virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
355 
356     return RT_EOK;
357 }
358 
virtio_gpu_cursor_move(struct virtio_gpu_device * virtio_gpu_dev,rt_uint32_t scanout_id,rt_uint32_t resource_id,rt_uint32_t x,rt_uint32_t y)359 static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
360         rt_uint32_t resource_id, rt_uint32_t x, rt_uint32_t y)
361 {
362     struct virtio_gpu_update_cursor req;
363 
364     rt_memset(&req, 0, sizeof(req));
365 
366     req.hdr.type = VIRTIO_GPU_CMD_MOVE_CURSOR;
367     req.pos.scanout_id = scanout_id;
368     req.pos.x = x;
369     req.pos.y = y;
370     req.resource_id = resource_id;
371 
372     virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
373 
374     return RT_EOK;
375 }
376 
virtio_gpu_cursor_set_img(struct virtio_gpu_device * virtio_gpu_dev,void * img)377 static rt_err_t virtio_gpu_cursor_set_img(struct virtio_gpu_device *virtio_gpu_dev, void *img)
378 {
379     rt_err_t status;
380 
381     rt_memcpy(virtio_gpu_dev->cursor_img, img, VIRTIO_GPU_CURSOR_IMG_SIZE);
382 
383     status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
384             virtio_gpu_dev->cursor_resource_id, virtio_gpu_dev->cursor_img, VIRTIO_GPU_CURSOR_IMG_SIZE);
385 
386     if (status != RT_EOK)
387     {
388         return status;
389     }
390 
391     status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, virtio_gpu_dev->cursor_resource_id,
392             0, 0, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT, 0);
393 
394     return status;
395 }
396 
virtio_gpu_get_display_info(struct virtio_gpu_device * virtio_gpu_dev)397 static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu_device *virtio_gpu_dev)
398 {
399     int i;
400     struct virtio_gpu_ctrl_hdr req;
401     struct virtio_gpu_resp_display_info info;
402 
403     rt_memset(&req, 0, sizeof(req));
404     req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
405 
406     virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &info, sizeof(info));
407 
408     if (info.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO)
409     {
410         return -RT_ERROR;
411     }
412 
413     for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i)
414     {
415         if (info.pmodes[i].enabled)
416         {
417             if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
418             {
419                 rt_memcpy(&virtio_gpu_dev->pmode, &info.pmodes[i], sizeof(virtio_gpu_dev->pmode));
420                 virtio_gpu_dev->pmode_id = i;
421             }
422         }
423     }
424 
425     return RT_EOK;
426 }
427 
virtio_gpu_init(rt_device_t dev)428 static rt_err_t virtio_gpu_init(rt_device_t dev)
429 {
430     rt_err_t status;
431     struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
432     struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
433     struct virtq *queue_ctrl, *queue_cursor;
434 
435     queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
436     queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
437 
438     queue_ctrl->avail->flags = 0;
439     queue_cursor->avail->flags = 0;
440 
441     status = virtio_gpu_get_display_info(virtio_gpu_dev);
442 
443     if (virtio_gpu_dev->pmode_id != VIRTIO_GPU_INVALID_PMODE_ID && _primary_virtio_gpu_dev == RT_NULL)
444     {
445         /* This device is ready */
446         _primary_virtio_gpu_dev = virtio_gpu_dev;
447     }
448 
449     return status;
450 }
451 
virtio_gpu_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)452 static rt_ssize_t virtio_gpu_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
453 {
454     struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
455 
456     if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
457     {
458         return 0;
459     }
460 
461     rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
462 
463     rt_memcpy(buffer, (rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, size);
464 
465     rt_mutex_release(&virtio_gpu_dev->rw_mutex);
466 
467     return size;
468 }
469 
virtio_gpu_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)470 static rt_ssize_t virtio_gpu_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
471 {
472     struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
473 
474     if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
475     {
476         return 0;
477     }
478 
479     rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
480 
481     rt_memcpy((rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, buffer, size);
482 
483     rt_mutex_release(&virtio_gpu_dev->rw_mutex);
484 
485     return size;
486 }
487 
virtio_gpu_control(rt_device_t dev,int cmd,void * args)488 static rt_err_t virtio_gpu_control(rt_device_t dev, int cmd, void *args)
489 {
490     rt_err_t status = RT_EOK;
491     struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
492 
493     switch (cmd)
494     {
495     case VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY:
496 
497         _primary_virtio_gpu_dev = virtio_gpu_dev;
498 
499         return status;
500     }
501 
502     if (args == RT_NULL)
503     {
504         return -RT_ERROR;
505     }
506 
507     switch (cmd)
508     {
509     case RTGRAPHIC_CTRL_RECT_UPDATE:
510         {
511             struct rt_device_rect_info *info = (struct rt_device_rect_info *)args;
512 
513             if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
514             {
515                 status = -RT_ERROR;
516                 break;
517             }
518 
519             status = virtio_gpu_gfx_flush_2d(virtio_gpu_dev, virtio_gpu_dev->display_resource_id,
520                     info->x, info->y, info->width, info->height);
521         }
522         break;
523     case RTGRAPHIC_CTRL_GET_INFO:
524         {
525             struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
526 
527             info->pixel_format      = _pixel_format_convert((rt_ubase_t)args, RT_FALSE);
528             info->bits_per_pixel    = VIRTIO_GPU_FORMAT_BPP;
529             info->pitch             = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
530             info->width             = virtio_gpu_dev->pmode.r.width;
531             info->height            = virtio_gpu_dev->pmode.r.height;
532             info->framebuffer       = virtio_gpu_dev->framebuffer;
533             info->smem_len          = virtio_gpu_dev->smem_len;
534         }
535         break;
536     case VIRTIO_DEVICE_CTRL_GPU_CREATE_2D:
537 
538         virtio_gpu_dev->format = _pixel_format_convert((rt_ubase_t)args, RT_TRUE);
539 
540         if (virtio_gpu_dev->format == 0 || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
541         {
542             status = -RT_ERROR;
543             break;
544         }
545 
546         status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
547                 &virtio_gpu_dev->display_resource_id, virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
548 
549         if (status != RT_EOK)
550         {
551             break;
552         }
553 
554         virtio_gpu_dev->smem_len =
555                 virtio_gpu_dev->pmode.r.width * virtio_gpu_dev->pmode.r.height * VIRTIO_GPU_FORMAT_PIXEL;
556         virtio_gpu_dev->smem_len = RT_ALIGN(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
557         virtio_gpu_dev->framebuffer = rt_malloc_align(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
558 
559         if (virtio_gpu_dev->framebuffer == RT_NULL)
560         {
561             virtio_gpu_unref_resource(virtio_gpu_dev, virtio_gpu_dev->display_resource_id);
562 
563             status = -RT_ENOMEM;
564             break;
565         }
566 
567         status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
568                 virtio_gpu_dev->display_resource_id, virtio_gpu_dev->framebuffer, virtio_gpu_dev->smem_len);
569 
570         if (status != RT_EOK)
571         {
572             break;
573         }
574 
575         status = virtio_gpu_set_scanout(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->display_resource_id,
576                 virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
577 
578         break;
579     case VIRTIO_DEVICE_CTRL_CURSOR_SETUP:
580 
581         if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
582         {
583             status = -RT_ERROR;
584             break;
585         }
586 
587         rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
588 
589         status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
590                 &virtio_gpu_dev->cursor_resource_id, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT);
591 
592         if (status != RT_EOK)
593         {
594             goto _cursor_setup_end;
595         }
596 
597         status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
598 
599         if (status != RT_EOK)
600         {
601             goto _cursor_setup_end;
602         }
603 
604         virtio_gpu_dev->cursor_x = 0;
605         virtio_gpu_dev->cursor_y = 0;
606 
607         status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
608             virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
609 
610         if (status == RT_EOK)
611         {
612             virtio_gpu_dev->cursor_enable = RT_TRUE;
613         }
614 
615 _cursor_setup_end:
616         rt_mutex_release(&virtio_gpu_dev->ops_mutex);
617 
618         break;
619     case VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG:
620 
621         if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
622         {
623             status = -RT_ERROR;
624             break;
625         }
626 
627         rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
628 
629         status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
630 
631         if (status != RT_EOK)
632         {
633             goto _cursor_set_img_end;
634         }
635 
636         status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
637             virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
638 
639 _cursor_set_img_end:
640         rt_mutex_release(&virtio_gpu_dev->ops_mutex);
641 
642         break;
643     case VIRTIO_DEVICE_CTRL_CURSOR_MOVE:
644 
645         if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
646         {
647             status = -RT_ERROR;
648             break;
649         }
650 
651         rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
652 
653         virtio_gpu_dev->cursor_x = ((rt_uint32_t *)args)[0];
654         virtio_gpu_dev->cursor_y = ((rt_uint32_t *)args)[1];
655 
656         status = virtio_gpu_cursor_move(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
657             virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
658 
659         rt_mutex_release(&virtio_gpu_dev->ops_mutex);
660 
661         break;
662     default:
663         status = -RT_EINVAL;
664         break;
665     }
666 
667     return status;
668 }
669 
670 #ifdef RT_USING_DEVICE_OPS
671 const static struct rt_device_ops virtio_gpu_ops =
672 {
673     virtio_gpu_init,
674     RT_NULL,
675     RT_NULL,
676     virtio_gpu_read,
677     virtio_gpu_write,
678     virtio_gpu_control
679 };
680 #endif
681 
virtio_gpu_set_pixel(const char * pixel,int x,int y)682 static void virtio_gpu_set_pixel(const char *pixel, int x, int y)
683 {
684     rt_uint8_t *fb;
685     struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
686 
687     if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
688     {
689         return;
690     }
691 
692     fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
693     fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
694     *((rt_uint32_t *)fb) = *((rt_uint32_t *)pixel);
695 }
696 
virtio_gpu_get_pixel(char * pixel,int x,int y)697 static void virtio_gpu_get_pixel(char *pixel, int x, int y)
698 {
699     rt_uint8_t *fb;
700     struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
701 
702     if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
703     {
704         return;
705     }
706 
707     fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
708     *((rt_uint32_t *)pixel) = *(fb + (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL);
709 }
710 
virtio_gpu_draw_hline(const char * pixel,int x1,int x2,int y)711 static void virtio_gpu_draw_hline(const char *pixel, int x1, int x2, int y)
712 {
713     int i;
714     rt_uint8_t *fb;
715     rt_uint32_t color = *((rt_uint32_t *)pixel);
716     struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
717 
718     if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
719         x1 < 0 || x2 < 0 || y < 0)
720     {
721         return;
722     }
723 
724     if (x1 > x2)
725     {
726         x1 ^= x2;
727         x2 ^= x1;
728         x1 ^= x2;
729     }
730 
731     fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
732     fb += (y * virtio_gpu_dev->pmode.r.width + x1) * VIRTIO_GPU_FORMAT_PIXEL;
733 
734     for (i = x1; i < x2; ++i)
735     {
736         *((rt_uint32_t *)fb) = color;
737 
738         fb += VIRTIO_GPU_FORMAT_PIXEL;
739     }
740 }
741 
virtio_gpu_draw_vline(const char * pixel,int x,int y1,int y2)742 static void virtio_gpu_draw_vline(const char *pixel, int x, int y1, int y2)
743 {
744     int i;
745     rt_uint8_t *fb;
746     rt_uint16_t pitch;
747     rt_uint32_t color = *((rt_uint32_t *)pixel);
748     struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
749 
750     if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
751         x < 0 || y1 < 0 || y2 < 0)
752     {
753         return;
754     }
755 
756     if (y1 > y2)
757     {
758         y1 ^= y2;
759         y2 ^= y1;
760         y1 ^= y2;
761     }
762 
763     fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
764     fb += (y1 * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
765 
766     pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
767 
768     for (i = y1; i < y2; ++i)
769     {
770         *((rt_uint32_t *)fb) = color;
771 
772         fb += pitch;
773     }
774 }
775 
virtio_gpu_blit_line(const char * pixel,int x,int y,rt_size_t size)776 static void virtio_gpu_blit_line(const char *pixel, int x, int y, rt_size_t size)
777 {
778     int i;
779     rt_uint8_t *fb;
780     rt_uint32_t *colors = (rt_uint32_t *)pixel;
781     struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
782 
783     if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || x < 0 || y < 0)
784     {
785         return;
786     }
787 
788     fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
789     fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
790 
791     for (i = 0; i < size; ++i)
792     {
793         *((rt_uint32_t *)fb) = *colors++;
794         fb += VIRTIO_GPU_FORMAT_PIXEL;
795     }
796 }
797 
798 static struct rt_device_graphic_ops virtio_gpu_graphic_ops =
799 {
800     virtio_gpu_set_pixel,
801     virtio_gpu_get_pixel,
802     virtio_gpu_draw_hline,
803     virtio_gpu_draw_vline,
804     virtio_gpu_blit_line
805 };
806 
virtio_gpu_isr(int irqno,void * param)807 static void virtio_gpu_isr(int irqno, void *param)
808 {
809     rt_uint16_t id;
810     struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)param;
811     struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
812     struct virtq *queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
813     struct virtq *queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
814 
815 #ifdef RT_USING_SMP
816     rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
817 #endif
818 
819     virtio_interrupt_ack(virtio_dev);
820     rt_hw_dsb();
821 
822     while (queue_ctrl->used_idx != queue_ctrl->used->idx)
823     {
824         rt_hw_dsb();
825         id = queue_ctrl->used->ring[queue_ctrl->used_idx % queue_ctrl->num].id;
826 
827         virtio_gpu_dev->info[id].ctrl_valid = RT_FALSE;
828 
829         queue_ctrl->used_idx++;
830     }
831 
832     while (queue_cursor->used_idx != queue_cursor->used->idx)
833     {
834         rt_hw_dsb();
835         id = queue_cursor->used->ring[queue_cursor->used_idx % queue_cursor->num].id;
836 
837         virtio_gpu_dev->info[id].cursor_valid = RT_FALSE;
838 
839         queue_cursor->used_idx++;
840     }
841 
842 #ifdef RT_USING_SMP
843     rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
844 #endif
845 }
846 
rt_virtio_gpu_init(rt_ubase_t * mmio_base,rt_uint32_t irq)847 rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
848 {
849     static int dev_no = 0;
850     char dev_name[RT_NAME_MAX];
851     struct virtio_device *virtio_dev;
852     struct virtio_gpu_device *virtio_gpu_dev;
853 
854     virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device));
855 
856     if (virtio_gpu_dev == RT_NULL)
857     {
858         goto _alloc_fail;
859     }
860 
861     virtio_dev = &virtio_gpu_dev->virtio_dev;
862     virtio_dev->irq = irq;
863     virtio_dev->mmio_base = mmio_base;
864 
865     virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID;
866     virtio_gpu_dev->display_resource_id = 0;
867     virtio_gpu_dev->cursor_resource_id = 0;
868     virtio_gpu_dev->next_resource_id = 0;
869     virtio_gpu_dev->framebuffer = RT_NULL;
870     virtio_gpu_dev->smem_len = 0;
871     virtio_gpu_dev->cursor_enable = RT_FALSE;
872 
873 #ifdef RT_USING_SMP
874     rt_spin_lock_init(&virtio_dev->spinlock);
875 #endif
876 
877     virtio_reset_device(virtio_dev);
878     virtio_status_acknowledge_driver(virtio_dev);
879 
880     virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
881             (1 << VIRTIO_F_RING_EVENT_IDX) |
882             (1 << VIRTIO_F_RING_INDIRECT_DESC));
883 
884     virtio_status_driver_ok(virtio_dev);
885 
886     if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
887     {
888         goto _alloc_fail;
889     }
890 
891     if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
892     {
893         goto _alloc_fail;
894     }
895 
896     if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
897     {
898         virtio_queue_destroy(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
899 
900         goto _alloc_fail;
901     }
902 
903     virtio_gpu_dev->parent.type = RT_Device_Class_Graphic;
904 #ifdef RT_USING_DEVICE_OPS
905     virtio_gpu_dev->parent.ops = &virtio_gpu_ops;
906 #else
907     virtio_gpu_dev->parent.init     = virtio_gpu_init;
908     virtio_gpu_dev->parent.open     = RT_NULL;
909     virtio_gpu_dev->parent.close    = RT_NULL;
910     virtio_gpu_dev->parent.read     = virtio_gpu_read;
911     virtio_gpu_dev->parent.write    = virtio_gpu_write;
912     virtio_gpu_dev->parent.control  = virtio_gpu_control;
913 #endif
914     virtio_gpu_dev->parent.user_data = &virtio_gpu_graphic_ops;
915 
916     rt_snprintf(dev_name, RT_NAME_MAX, "virtio-gpu%d", dev_no++);
917 
918     rt_mutex_init(&virtio_gpu_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
919     rt_mutex_init(&virtio_gpu_dev->ops_mutex, dev_name, RT_IPC_FLAG_PRIO);
920 
921     rt_hw_interrupt_install(irq, virtio_gpu_isr, virtio_gpu_dev, dev_name);
922     rt_hw_interrupt_umask(irq);
923 
924     return rt_device_register((rt_device_t)virtio_gpu_dev, dev_name, RT_DEVICE_FLAG_RDWR);
925 
926 _alloc_fail:
927 
928     if (virtio_gpu_dev != RT_NULL)
929     {
930         virtio_queues_free(virtio_dev);
931         rt_free(virtio_gpu_dev);
932     }
933     return -RT_ENOMEM;
934 }
935 #endif /* RT_USING_VIRTIO_GPU */
936