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