virtio_gpu.c 26 KB

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