virtio_gpu.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  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. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <cpuport.h>
  13. #ifdef RT_USING_VIRTIO_GPU
  14. #include <virtio_gpu.h>
  15. static struct virtio_gpu_device *_primary_virtio_gpu_dev = RT_NULL;
  16. static rt_ubase_t _pixel_format_convert(rt_ubase_t format, rt_bool_t to_virtio_gpu_format)
  17. {
  18. rt_ubase_t ret = 0;
  19. if (to_virtio_gpu_format)
  20. {
  21. switch (format)
  22. {
  23. case RTGRAPHIC_PIXEL_FORMAT_RGB888:
  24. ret = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
  25. break;
  26. case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
  27. ret = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
  28. break;
  29. case RTGRAPHIC_PIXEL_FORMAT_ABGR888:
  30. ret = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
  31. break;
  32. default:
  33. break;
  34. }
  35. }
  36. else
  37. {
  38. switch (format)
  39. {
  40. case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
  41. ret = RTGRAPHIC_PIXEL_FORMAT_RGB888;
  42. break;
  43. case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
  44. ret = RTGRAPHIC_PIXEL_FORMAT_ARGB888;
  45. break;
  46. case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
  47. ret = RTGRAPHIC_PIXEL_FORMAT_ABGR888;
  48. break;
  49. default:
  50. break;
  51. }
  52. }
  53. return ret;
  54. }
  55. static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_dev,
  56. const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len)
  57. {
  58. rt_uint16_t idx[2];
  59. void *addr = &virtio_gpu_dev->gpu_request;
  60. void *ret_res = ((rt_uint8_t *)addr + cmd_len);
  61. struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
  62. #ifdef RT_USING_SMP
  63. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  64. #endif
  65. while (virtio_alloc_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, 2, idx))
  66. {
  67. #ifdef RT_USING_SMP
  68. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  69. #endif
  70. rt_thread_yield();
  71. #ifdef RT_USING_SMP
  72. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  73. #endif
  74. }
  75. rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
  76. virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0],
  77. VIRTIO_VA2PA(addr), cmd_len, VIRTQ_DESC_F_NEXT, idx[1]);
  78. virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[1],
  79. VIRTIO_VA2PA(addr) + cmd_len, res_len, VIRTQ_DESC_F_WRITE, 0);
  80. rt_memset(ret_res, 0, res_len);
  81. virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
  82. virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
  83. virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
  84. while (virtio_gpu_dev->info[idx[0]].ctrl_valid)
  85. {
  86. #ifdef RT_USING_SMP
  87. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  88. #endif
  89. rt_thread_yield();
  90. #ifdef RT_USING_SMP
  91. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  92. #endif
  93. }
  94. virtio_free_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
  95. rt_memcpy(res, ret_res, res_len);
  96. #ifdef RT_USING_SMP
  97. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  98. #endif
  99. }
  100. static void virtio_gpu_cursor_send_command(struct virtio_gpu_device *virtio_gpu_dev,
  101. const void *cmd, rt_size_t cmd_len)
  102. {
  103. rt_uint16_t id;
  104. void *addr;
  105. struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
  106. #ifdef RT_USING_SMP
  107. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  108. #endif
  109. while ((id = virtio_alloc_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR)) == VIRTQ_INVALID_DESC_ID)
  110. {
  111. #ifdef RT_USING_SMP
  112. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  113. #endif
  114. rt_thread_yield();
  115. #ifdef RT_USING_SMP
  116. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  117. #endif
  118. }
  119. addr = &virtio_gpu_dev->info[id].cursor_cmd;
  120. virtio_gpu_dev->info[id].cursor_valid = RT_TRUE;
  121. rt_memcpy(addr, cmd, cmd_len);
  122. virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id, VIRTIO_VA2PA(addr), cmd_len, 0, 0);
  123. virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
  124. virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR);
  125. while (virtio_gpu_dev->info[id].cursor_valid)
  126. {
  127. #ifdef RT_USING_SMP
  128. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  129. #endif
  130. rt_thread_yield();
  131. #ifdef RT_USING_SMP
  132. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  133. #endif
  134. }
  135. virtio_free_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
  136. #ifdef RT_USING_SMP
  137. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  138. #endif
  139. }
  140. static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu_device *virtio_gpu_dev, enum virtio_gpu_formats format,
  141. rt_uint32_t *resource_id, rt_uint32_t width, rt_uint32_t height)
  142. {
  143. struct virtio_gpu_ctrl_hdr res;
  144. struct virtio_gpu_resource_create_2d req;
  145. *resource_id = ++virtio_gpu_dev->next_resource_id;
  146. req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
  147. req.resource_id = *resource_id;
  148. req.format = format;
  149. req.width = width;
  150. req.height = height;
  151. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  152. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  153. {
  154. return RT_EOK;
  155. }
  156. return -RT_ERROR;
  157. }
  158. static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id)
  159. {
  160. struct virtio_gpu_ctrl_hdr res;
  161. struct virtio_gpu_resource_unref req;
  162. rt_memset(&req, 0, sizeof(req));
  163. req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF;
  164. req.resource_id = resource_id;
  165. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  166. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  167. {
  168. return RT_EOK;
  169. }
  170. return -RT_ERROR;
  171. }
  172. static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
  173. void *buffer, rt_size_t size)
  174. {
  175. struct virtio_gpu_ctrl_hdr res;
  176. struct
  177. {
  178. struct virtio_gpu_resource_attach_backing req;
  179. struct virtio_gpu_mem_entry mem;
  180. } req;
  181. rt_memset(&req, 0, sizeof(req));
  182. req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
  183. req.req.resource_id = resource_id;
  184. req.req.nr_entries = 1;
  185. req.mem.addr = VIRTIO_VA2PA(buffer);
  186. req.mem.length = size;
  187. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  188. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  189. {
  190. return RT_EOK;
  191. }
  192. return -RT_ERROR;
  193. }
  194. static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
  195. rt_uint32_t resource_id, rt_uint32_t width, rt_uint32_t height)
  196. {
  197. struct virtio_gpu_ctrl_hdr res;
  198. struct virtio_gpu_set_scanout req;
  199. rt_memset(&req, 0, sizeof(req));
  200. req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
  201. req.r.x = 0;
  202. req.r.y = 0;
  203. req.r.width = width;
  204. req.r.height = height;
  205. req.scanout_id = scanout_id;
  206. req.resource_id = resource_id;
  207. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  208. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  209. {
  210. return RT_EOK;
  211. }
  212. return -RT_ERROR;
  213. }
  214. static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
  215. rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
  216. {
  217. struct virtio_gpu_ctrl_hdr res;
  218. struct virtio_gpu_resource_flush req;
  219. rt_memset(&req, 0, sizeof(req));
  220. req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
  221. req.r.x = x;
  222. req.r.y = y;
  223. req.r.width = width;
  224. req.r.height = height;
  225. req.resource_id = resource_id;
  226. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  227. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  228. {
  229. return RT_EOK;
  230. }
  231. return -RT_ERROR;
  232. }
  233. static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
  234. rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, rt_uint32_t offset)
  235. {
  236. struct virtio_gpu_ctrl_hdr res;
  237. struct virtio_gpu_transfer_to_host_2d req;
  238. rt_memset(&req, 0, sizeof(req));
  239. req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
  240. req.r.x = x;
  241. req.r.y = y;
  242. req.r.width = width;
  243. req.r.height = height;
  244. req.offset = offset;
  245. req.resource_id = resource_id;
  246. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
  247. if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
  248. {
  249. return RT_EOK;
  250. }
  251. return -RT_ERROR;
  252. }
  253. static rt_err_t virtio_gpu_gfx_flush_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
  254. rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
  255. {
  256. rt_err_t status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, resource_id, x, y, width, height, 0);
  257. if (status == RT_EOK)
  258. {
  259. status = virtio_gpu_flush_resource(virtio_gpu_dev, resource_id, x, y, width, height);
  260. }
  261. return status;
  262. }
  263. static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
  264. rt_uint32_t resource_id, rt_uint32_t hot_x, rt_uint32_t hot_y)
  265. {
  266. struct virtio_gpu_update_cursor req;
  267. rt_memset(&req, 0, sizeof(req));
  268. req.hdr.type = VIRTIO_GPU_CMD_UPDATE_CURSOR;
  269. req.pos.scanout_id = scanout_id;
  270. req.resource_id = resource_id;
  271. req.hot_x = hot_x;
  272. req.hot_y = hot_y;
  273. virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
  274. return RT_EOK;
  275. }
  276. static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
  277. rt_uint32_t resource_id, rt_uint32_t x, rt_uint32_t y)
  278. {
  279. struct virtio_gpu_update_cursor req;
  280. rt_memset(&req, 0, sizeof(req));
  281. req.hdr.type = VIRTIO_GPU_CMD_MOVE_CURSOR;
  282. req.pos.scanout_id = scanout_id;
  283. req.pos.x = x;
  284. req.pos.y = y;
  285. req.resource_id = resource_id;
  286. virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
  287. return RT_EOK;
  288. }
  289. static rt_err_t virtio_gpu_cursor_set_img(struct virtio_gpu_device *virtio_gpu_dev, void *img)
  290. {
  291. rt_err_t status;
  292. rt_memcpy(virtio_gpu_dev->cursor_img, img, VIRTIO_GPU_CURSOR_IMG_SIZE);
  293. status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
  294. virtio_gpu_dev->cursor_resource_id, virtio_gpu_dev->cursor_img, VIRTIO_GPU_CURSOR_IMG_SIZE);
  295. if (status != RT_EOK)
  296. {
  297. return status;
  298. }
  299. status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, virtio_gpu_dev->cursor_resource_id,
  300. 0, 0, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT, 0);
  301. return status;
  302. }
  303. static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu_device *virtio_gpu_dev)
  304. {
  305. int i;
  306. struct virtio_gpu_ctrl_hdr req;
  307. struct virtio_gpu_resp_display_info info;
  308. rt_memset(&req, 0, sizeof(req));
  309. req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
  310. virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &info, sizeof(info));
  311. if (info.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO)
  312. {
  313. return -RT_ERROR;
  314. }
  315. for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i)
  316. {
  317. if (info.pmodes[i].enabled)
  318. {
  319. if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  320. {
  321. rt_memcpy(&virtio_gpu_dev->pmode, &info.pmodes[i], sizeof(virtio_gpu_dev->pmode));
  322. virtio_gpu_dev->pmode_id = i;
  323. }
  324. }
  325. }
  326. return RT_EOK;
  327. }
  328. static rt_err_t virtio_gpu_init(rt_device_t dev)
  329. {
  330. rt_err_t status;
  331. struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
  332. struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
  333. struct virtq *queue_ctrl, *queue_cursor;
  334. queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
  335. queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
  336. queue_ctrl->avail->flags = 0;
  337. queue_cursor->avail->flags = 0;
  338. status = virtio_gpu_get_display_info(virtio_gpu_dev);
  339. if (virtio_gpu_dev->pmode_id != VIRTIO_GPU_INVALID_PMODE_ID && _primary_virtio_gpu_dev == RT_NULL)
  340. {
  341. /* This device is ready */
  342. _primary_virtio_gpu_dev = virtio_gpu_dev;
  343. }
  344. return status;
  345. }
  346. static rt_ssize_t virtio_gpu_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  347. {
  348. struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
  349. if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
  350. {
  351. return 0;
  352. }
  353. rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
  354. rt_memcpy(buffer, (rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, size);
  355. rt_mutex_release(&virtio_gpu_dev->rw_mutex);
  356. return size;
  357. }
  358. static rt_ssize_t virtio_gpu_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  359. {
  360. struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
  361. if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
  362. {
  363. return 0;
  364. }
  365. rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
  366. rt_memcpy((rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, buffer, size);
  367. rt_mutex_release(&virtio_gpu_dev->rw_mutex);
  368. return size;
  369. }
  370. static rt_err_t virtio_gpu_control(rt_device_t dev, int cmd, void *args)
  371. {
  372. rt_err_t status = RT_EOK;
  373. struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
  374. switch (cmd)
  375. {
  376. case VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY:
  377. _primary_virtio_gpu_dev = virtio_gpu_dev;
  378. return status;
  379. }
  380. if (args == RT_NULL)
  381. {
  382. return -RT_ERROR;
  383. }
  384. switch (cmd)
  385. {
  386. case RTGRAPHIC_CTRL_RECT_UPDATE:
  387. {
  388. struct rt_device_rect_info *info = (struct rt_device_rect_info *)args;
  389. if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  390. {
  391. status = -RT_ERROR;
  392. break;
  393. }
  394. status = virtio_gpu_gfx_flush_2d(virtio_gpu_dev, virtio_gpu_dev->display_resource_id,
  395. info->x, info->y, info->width, info->height);
  396. }
  397. break;
  398. case RTGRAPHIC_CTRL_GET_INFO:
  399. {
  400. struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
  401. info->pixel_format = _pixel_format_convert((rt_ubase_t)args, RT_FALSE);
  402. info->bits_per_pixel = VIRTIO_GPU_FORMAT_BPP;
  403. info->pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
  404. info->width = virtio_gpu_dev->pmode.r.width;
  405. info->height = virtio_gpu_dev->pmode.r.height;
  406. info->framebuffer = virtio_gpu_dev->framebuffer;
  407. info->smem_len = virtio_gpu_dev->smem_len;
  408. }
  409. break;
  410. case VIRTIO_DEVICE_CTRL_GPU_CREATE_2D:
  411. virtio_gpu_dev->format = _pixel_format_convert((rt_ubase_t)args, RT_TRUE);
  412. if (virtio_gpu_dev->format == 0 || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  413. {
  414. status = -RT_ERROR;
  415. break;
  416. }
  417. status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
  418. &virtio_gpu_dev->display_resource_id, virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
  419. if (status != RT_EOK)
  420. {
  421. break;
  422. }
  423. virtio_gpu_dev->smem_len =
  424. virtio_gpu_dev->pmode.r.width * virtio_gpu_dev->pmode.r.height * VIRTIO_GPU_FORMAT_PIXEL;
  425. virtio_gpu_dev->smem_len = RT_ALIGN(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
  426. virtio_gpu_dev->framebuffer = rt_malloc_align(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
  427. if (virtio_gpu_dev->framebuffer == RT_NULL)
  428. {
  429. virtio_gpu_unref_resource(virtio_gpu_dev, virtio_gpu_dev->display_resource_id);
  430. status = -RT_ENOMEM;
  431. break;
  432. }
  433. status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
  434. virtio_gpu_dev->display_resource_id, virtio_gpu_dev->framebuffer, virtio_gpu_dev->smem_len);
  435. if (status != RT_EOK)
  436. {
  437. break;
  438. }
  439. status = virtio_gpu_set_scanout(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->display_resource_id,
  440. virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
  441. break;
  442. case VIRTIO_DEVICE_CTRL_CURSOR_SETUP:
  443. if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  444. {
  445. status = -RT_ERROR;
  446. break;
  447. }
  448. rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
  449. status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
  450. &virtio_gpu_dev->cursor_resource_id, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT);
  451. if (status != RT_EOK)
  452. {
  453. goto _cursor_setup_end;
  454. }
  455. status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
  456. if (status != RT_EOK)
  457. {
  458. goto _cursor_setup_end;
  459. }
  460. virtio_gpu_dev->cursor_x = 0;
  461. virtio_gpu_dev->cursor_y = 0;
  462. status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
  463. virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
  464. if (status == RT_EOK)
  465. {
  466. virtio_gpu_dev->cursor_enable = RT_TRUE;
  467. }
  468. _cursor_setup_end:
  469. rt_mutex_release(&virtio_gpu_dev->ops_mutex);
  470. break;
  471. case VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG:
  472. if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
  473. {
  474. status = -RT_ERROR;
  475. break;
  476. }
  477. rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
  478. status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
  479. if (status != RT_EOK)
  480. {
  481. goto _cursor_set_img_end;
  482. }
  483. status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
  484. virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
  485. _cursor_set_img_end:
  486. rt_mutex_release(&virtio_gpu_dev->ops_mutex);
  487. break;
  488. case VIRTIO_DEVICE_CTRL_CURSOR_MOVE:
  489. if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
  490. {
  491. status = -RT_ERROR;
  492. break;
  493. }
  494. rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
  495. virtio_gpu_dev->cursor_x = ((rt_uint32_t *)args)[0];
  496. virtio_gpu_dev->cursor_y = ((rt_uint32_t *)args)[1];
  497. status = virtio_gpu_cursor_move(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
  498. virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
  499. rt_mutex_release(&virtio_gpu_dev->ops_mutex);
  500. break;
  501. default:
  502. status = -RT_EINVAL;
  503. break;
  504. }
  505. return status;
  506. }
  507. #ifdef RT_USING_DEVICE_OPS
  508. const static struct rt_device_ops virtio_gpu_ops =
  509. {
  510. virtio_gpu_init,
  511. RT_NULL,
  512. RT_NULL,
  513. virtio_gpu_read,
  514. virtio_gpu_write,
  515. virtio_gpu_control
  516. };
  517. #endif
  518. static void virtio_gpu_set_pixel(const char *pixel, int x, int y)
  519. {
  520. rt_uint8_t *fb;
  521. struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
  522. if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  523. {
  524. return;
  525. }
  526. fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
  527. fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
  528. *((rt_uint32_t *)fb) = *((rt_uint32_t *)pixel);
  529. }
  530. static void virtio_gpu_get_pixel(char *pixel, int x, int y)
  531. {
  532. rt_uint8_t *fb;
  533. struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
  534. if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
  535. {
  536. return;
  537. }
  538. fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
  539. *((rt_uint32_t *)pixel) = *(fb + (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL);
  540. }
  541. static void virtio_gpu_draw_hline(const char *pixel, int x1, int x2, int y)
  542. {
  543. int i;
  544. rt_uint8_t *fb;
  545. rt_uint32_t color = *((rt_uint32_t *)pixel);
  546. struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
  547. if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
  548. x1 < 0 || x2 < 0 || y < 0)
  549. {
  550. return;
  551. }
  552. if (x1 > x2)
  553. {
  554. x1 ^= x2;
  555. x2 ^= x1;
  556. x1 ^= x2;
  557. }
  558. fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
  559. fb += (y * virtio_gpu_dev->pmode.r.width + x1) * VIRTIO_GPU_FORMAT_PIXEL;
  560. for (i = x1; i < x2; ++i)
  561. {
  562. *((rt_uint32_t *)fb) = color;
  563. fb += VIRTIO_GPU_FORMAT_PIXEL;
  564. }
  565. }
  566. static void virtio_gpu_draw_vline(const char *pixel, int x, int y1, int y2)
  567. {
  568. int i;
  569. rt_uint8_t *fb;
  570. rt_uint16_t pitch;
  571. rt_uint32_t color = *((rt_uint32_t *)pixel);
  572. struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
  573. if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
  574. x < 0 || y1 < 0 || y2 < 0)
  575. {
  576. return;
  577. }
  578. if (y1 > y2)
  579. {
  580. y1 ^= y2;
  581. y2 ^= y1;
  582. y1 ^= y2;
  583. }
  584. fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
  585. fb += (y1 * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
  586. pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
  587. for (i = y1; i < y2; ++i)
  588. {
  589. *((rt_uint32_t *)fb) = color;
  590. fb += pitch;
  591. }
  592. }
  593. static void virtio_gpu_blit_line(const char *pixel, int x, int y, rt_size_t size)
  594. {
  595. int i;
  596. rt_uint8_t *fb;
  597. rt_uint32_t *colors = (rt_uint32_t *)pixel;
  598. struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
  599. if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || x < 0 || y < 0)
  600. {
  601. return;
  602. }
  603. fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
  604. fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
  605. for (i = 0; i < size; ++i)
  606. {
  607. *((rt_uint32_t *)fb) = *colors++;
  608. fb += VIRTIO_GPU_FORMAT_PIXEL;
  609. }
  610. }
  611. static struct rt_device_graphic_ops virtio_gpu_graphic_ops =
  612. {
  613. virtio_gpu_set_pixel,
  614. virtio_gpu_get_pixel,
  615. virtio_gpu_draw_hline,
  616. virtio_gpu_draw_vline,
  617. virtio_gpu_blit_line
  618. };
  619. static void virtio_gpu_isr(int irqno, void *param)
  620. {
  621. rt_uint16_t id;
  622. struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)param;
  623. struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
  624. struct virtq *queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
  625. struct virtq *queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
  626. #ifdef RT_USING_SMP
  627. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  628. #endif
  629. virtio_interrupt_ack(virtio_dev);
  630. rt_hw_dsb();
  631. while (queue_ctrl->used_idx != queue_ctrl->used->idx)
  632. {
  633. rt_hw_dsb();
  634. id = queue_ctrl->used->ring[queue_ctrl->used_idx % queue_ctrl->num].id;
  635. virtio_gpu_dev->info[id].ctrl_valid = RT_FALSE;
  636. queue_ctrl->used_idx++;
  637. }
  638. while (queue_cursor->used_idx != queue_cursor->used->idx)
  639. {
  640. rt_hw_dsb();
  641. id = queue_cursor->used->ring[queue_cursor->used_idx % queue_cursor->num].id;
  642. virtio_gpu_dev->info[id].cursor_valid = RT_FALSE;
  643. queue_cursor->used_idx++;
  644. }
  645. #ifdef RT_USING_SMP
  646. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  647. #endif
  648. }
  649. rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
  650. {
  651. static int dev_no = 0;
  652. char dev_name[RT_NAME_MAX];
  653. struct virtio_device *virtio_dev;
  654. struct virtio_gpu_device *virtio_gpu_dev;
  655. virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device));
  656. if (virtio_gpu_dev == RT_NULL)
  657. {
  658. goto _alloc_fail;
  659. }
  660. virtio_dev = &virtio_gpu_dev->virtio_dev;
  661. virtio_dev->irq = irq;
  662. virtio_dev->mmio_base = mmio_base;
  663. virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID;
  664. virtio_gpu_dev->display_resource_id = 0;
  665. virtio_gpu_dev->cursor_resource_id = 0;
  666. virtio_gpu_dev->next_resource_id = 0;
  667. virtio_gpu_dev->framebuffer = RT_NULL;
  668. virtio_gpu_dev->smem_len = 0;
  669. virtio_gpu_dev->cursor_enable = RT_FALSE;
  670. #ifdef RT_USING_SMP
  671. rt_spin_lock_init(&virtio_dev->spinlock);
  672. #endif
  673. virtio_reset_device(virtio_dev);
  674. virtio_status_acknowledge_driver(virtio_dev);
  675. virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
  676. (1 << VIRTIO_F_RING_EVENT_IDX) |
  677. (1 << VIRTIO_F_RING_INDIRECT_DESC));
  678. virtio_status_driver_ok(virtio_dev);
  679. if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
  680. {
  681. goto _alloc_fail;
  682. }
  683. if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
  684. {
  685. goto _alloc_fail;
  686. }
  687. if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
  688. {
  689. virtio_queue_destroy(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
  690. goto _alloc_fail;
  691. }
  692. virtio_gpu_dev->parent.type = RT_Device_Class_Graphic;
  693. #ifdef RT_USING_DEVICE_OPS
  694. virtio_gpu_dev->parent.ops = &virtio_gpu_ops;
  695. #else
  696. virtio_gpu_dev->parent.init = virtio_gpu_init;
  697. virtio_gpu_dev->parent.open = RT_NULL;
  698. virtio_gpu_dev->parent.close = RT_NULL;
  699. virtio_gpu_dev->parent.read = virtio_gpu_read;
  700. virtio_gpu_dev->parent.write = virtio_gpu_write;
  701. virtio_gpu_dev->parent.control = virtio_gpu_control;
  702. #endif
  703. virtio_gpu_dev->parent.user_data = &virtio_gpu_graphic_ops;
  704. rt_snprintf(dev_name, RT_NAME_MAX, "virtio-gpu%d", dev_no++);
  705. rt_mutex_init(&virtio_gpu_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
  706. rt_mutex_init(&virtio_gpu_dev->ops_mutex, dev_name, RT_IPC_FLAG_PRIO);
  707. rt_hw_interrupt_install(irq, virtio_gpu_isr, virtio_gpu_dev, dev_name);
  708. rt_hw_interrupt_umask(irq);
  709. return rt_device_register((rt_device_t)virtio_gpu_dev, dev_name, RT_DEVICE_FLAG_RDWR);
  710. _alloc_fail:
  711. if (virtio_gpu_dev != RT_NULL)
  712. {
  713. virtio_queues_free(virtio_dev);
  714. rt_free(virtio_gpu_dev);
  715. }
  716. return -RT_ENOMEM;
  717. }
  718. #endif /* RT_USING_VIRTIO_GPU */