drv_hdmi.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. * Copyright (c) 2006-2020, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-10-26 bigmagic first version
  9. */
  10. #include <stdint.h>
  11. #include <rtthread.h>
  12. #include <ioremap.h>
  13. #if defined(BSP_USING_HDMI) && defined(RT_USING_SMART)
  14. #include <lwp.h>
  15. #include <lwp_user_mm.h>
  16. #include <hypercall.h>
  17. #include "mbox.h"
  18. #include "drv_hdmi.h"
  19. #define LCD_WIDTH (800)
  20. #define LCD_HEIGHT (480)
  21. #define LCD_DEPTH (32)
  22. #define LCD_BPP (32)
  23. #define TAG_ALLOCATE_BUFFER 0x00040001
  24. #define TAG_SET_PHYS_WIDTH_HEIGHT 0x00048003
  25. #define TAG_SET_VIRT_WIDTH_HEIGHT 0x00048004
  26. #define TAG_SET_DEPTH 0x00048005
  27. #define TAG_SET_PIXEL_ORDER 0x00048006
  28. #define TAG_GET_PITCH 0x00040008
  29. #define TAG_SET_VIRT_OFFSET 0x00048009
  30. #define TAG_END 0x00000000
  31. enum {
  32. MBOX_TAG_FB_GET_GPIOVIRT = 0x00040010,
  33. MBOX_TAG_FB_ALLOCATE_BUFFER = 0x00040001,
  34. MBOX_TAG_FB_RELEASE_BUFFER = 0x00048001,
  35. MBOX_TAG_FB_BLANK_SCREEN = 0x00040002,
  36. MBOX_TAG_FB_GET_PHYS_WH = 0x00040003,
  37. MBOX_TAG_FB_TEST_PHYS_WH = 0x00044003,
  38. MBOX_TAG_FB_SET_PHYS_WH = 0x00048003,
  39. MBOX_TAG_FB_GET_VIRT_WH = 0x00040004,
  40. MBOX_TAG_FB_TEST_VIRT_WH = 0x00044004,
  41. MBOX_TAG_FB_SET_VIRT_WH = 0x00048004,
  42. MBOX_TAG_FB_GET_DEPTH = 0x00040005,
  43. MBOX_TAG_FB_TEST_DEPTH = 0x00044005,
  44. MBOX_TAG_FB_SET_DEPTH = 0x00048005,
  45. MBOX_TAG_FB_GET_PIXEL_ORDER = 0x00040006,
  46. MBOX_TAG_FB_TEST_PIXEL_ORDER = 0x00044006,
  47. MBOX_TAG_FB_SET_PIXEL_ORDER = 0x00048006,
  48. MBOX_TAG_FB_GET_ALPHA_MODE = 0x00040007,
  49. MBOX_TAG_FB_TEST_ALPHA_MODE = 0x00044007,
  50. MBOX_TAG_FB_SET_ALPHA_MODE = 0x00048007,
  51. MBOX_TAG_FB_GET_PITCH = 0x00040008,
  52. MBOX_TAG_FB_GET_VIRT_OFFSET = 0x00040009,
  53. MBOX_TAG_FB_TEST_VIRT_OFFSET = 0x00044009,
  54. MBOX_TAG_FB_SET_VIRT_OFFSET = 0x00048009,
  55. MBOX_TAG_FB_GET_OVERSCAN = 0x0004000a,
  56. MBOX_TAG_FB_TEST_OVERSCAN = 0x0004400a,
  57. MBOX_TAG_FB_SET_OVERSCAN = 0x0004800a,
  58. MBOX_TAG_FB_GET_PALETTE = 0x0004000b,
  59. MBOX_TAG_FB_TEST_PALETTE = 0x0004400b,
  60. MBOX_TAG_FB_SET_PALETTE = 0x0004800b,
  61. };
  62. #define LCD_DEVICE(dev) (struct rt_hdmi_fb_device*)(dev)
  63. static struct rt_hdmi_fb_device _hdmi;
  64. typedef rt_uint16_t color_t;
  65. rt_err_t hdmi_fb_open(rt_device_t dev, rt_uint16_t oflag)
  66. {
  67. return RT_EOK;
  68. }
  69. rt_err_t hdmi_fb_close(rt_device_t dev)
  70. {
  71. return RT_EOK;
  72. }
  73. rt_ssize_t hdmi_fb_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size)
  74. {
  75. return 0;
  76. }
  77. rt_ssize_t hdmi_fb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  78. {
  79. return size;
  80. }
  81. rt_err_t hdmi_fb_control(rt_device_t dev, int cmd, void *args)
  82. {
  83. static unsigned long smem_start = 0;
  84. static unsigned long smem_len = 0;
  85. struct rt_hdmi_fb_device *lcd = LCD_DEVICE(dev);
  86. switch (cmd)
  87. {
  88. case RTGRAPHIC_CTRL_RECT_UPDATE:
  89. {
  90. if (smem_start != 0)
  91. {
  92. rt_hw_cpu_dcache_clean_and_invalidate((void *)smem_start, smem_len);
  93. }
  94. }
  95. break;
  96. case RTGRAPHIC_CTRL_GET_INFO:
  97. {
  98. struct rt_device_graphic_info *lcd_info = (struct rt_device_graphic_info *)args;
  99. lcd_info->bits_per_pixel = 32;
  100. lcd_info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_ARGB888; /* should be coherent to adding layers */
  101. lcd_info->width = lcd->width;
  102. lcd_info->height = lcd->height;
  103. lcd_info->framebuffer = (void *)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb, lcd->width * lcd->height * sizeof(rt_uint32_t), 1);
  104. }
  105. break;
  106. #define FBIOGET_FSCREENINFO 0x4602
  107. case FBIOGET_FSCREENINFO:
  108. {
  109. struct fb_fix_screeninfo
  110. {
  111. char id[16];
  112. unsigned long smem_start;
  113. uint32_t smem_len;
  114. uint32_t line_length;
  115. } *info = (struct fb_fix_screeninfo *)args;
  116. rt_strncpy(info->id, "lcd", sizeof(info->id));
  117. info->smem_len = lcd->width * lcd->height * sizeof(rt_uint32_t);
  118. info->smem_start = (size_t)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb, info->smem_len, 1);
  119. info->line_length = lcd->width * sizeof(rt_uint32_t);
  120. rt_memset((void *)info->smem_start, 0, info->smem_len);
  121. smem_start = info->smem_start;
  122. smem_len = info->smem_len;
  123. }
  124. break;
  125. }
  126. return RT_EOK;
  127. }
  128. #ifdef RT_USING_DEVICE_OPS
  129. const static struct rt_device_ops hdmi_fb_ops =
  130. {
  131. RT_NULL,
  132. hdmi_fb_open,
  133. hdmi_fb_close,
  134. hdmi_fb_read,
  135. hdmi_fb_write,
  136. hdmi_fb_control,
  137. };
  138. #endif
  139. rt_err_t rt_hdmi_fb_device_init(struct rt_hdmi_fb_device *hdmi_fb, const char *name)
  140. {
  141. struct rt_device *device;
  142. RT_ASSERT(hdmi_fb != RT_NULL);
  143. device = &hdmi_fb->parent;
  144. /* set device type */
  145. device->type = RT_Device_Class_Graphic;
  146. /* initialize device interface */
  147. #ifdef RT_USING_DEVICE_OPS
  148. device->ops = &hdmi_fb_ops;
  149. #else
  150. device->init = RT_NULL;
  151. device->open = hdmi_fb_open;
  152. device->close = hdmi_fb_close;
  153. device->read = hdmi_fb_read;
  154. device->write = hdmi_fb_write;
  155. device->control = hdmi_fb_control;
  156. #endif
  157. /* register to device manager */
  158. rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
  159. return RT_EOK;
  160. }
  161. rt_uint32_t bcm271x_mbox_fb_get_gpiovirt(void)
  162. {
  163. mbox[0] = 8*4; // length of the message
  164. mbox[1] = MBOX_REQUEST; // this is a request message
  165. mbox[2] = MBOX_TAG_FB_GET_GPIOVIRT;
  166. mbox[3] = 4; // buffer size
  167. mbox[4] = 0; // len
  168. mbox[5] = 0; // id
  169. mbox[6] = 0;
  170. mbox[7] = MBOX_TAG_LAST;
  171. mbox_call(8, MMU_DISABLE);
  172. return (mbox[5] & 0x3fffffff);
  173. }
  174. rt_uint32_t bcm271x_mbox_fb_get_pitch(void)
  175. {
  176. mbox[0] = 8*4; // length of the message
  177. mbox[1] = MBOX_REQUEST; // this is a request message
  178. mbox[2] = MBOX_TAG_FB_GET_PITCH;
  179. mbox[3] = 4; // buffer size
  180. mbox[4] = 0; // len
  181. mbox[5] = 0; // id
  182. mbox[6] = 0;
  183. mbox[7] = MBOX_TAG_LAST;
  184. mbox_call(8, MMU_DISABLE);
  185. return mbox[5];
  186. }
  187. void bcm271x_mbox_fb_set_porder(int rgb)
  188. {
  189. mbox[0] = 8*4; // length of the message
  190. mbox[1] = MBOX_REQUEST; // this is a request message
  191. mbox[2] = MBOX_TAG_FB_SET_PIXEL_ORDER;
  192. mbox[3] = 4; // buffer size
  193. mbox[4] = 4; // len
  194. mbox[5] = rgb; // id
  195. mbox[6] = 0;
  196. mbox[7] = MBOX_TAG_LAST;
  197. mbox_call(8, MMU_DISABLE);
  198. }
  199. void bcm271x_mbox_fb_setoffset(int xoffset, int yoffset)
  200. {
  201. mbox[0] = 8*4; // length of the message
  202. mbox[1] = MBOX_REQUEST; // this is a request message
  203. mbox[2] = MBOX_TAG_FB_SET_VIRT_OFFSET;
  204. mbox[3] = 8; // buffer size
  205. mbox[4] = 8; // len
  206. mbox[5] = xoffset; // id
  207. mbox[6] = yoffset;
  208. mbox[7] = MBOX_TAG_LAST;
  209. mbox_call(8, MMU_DISABLE);
  210. }
  211. void bcm271x_mbox_fb_setalpha(int alpha)
  212. {
  213. mbox[0] = 8*4; // length of the message
  214. mbox[1] = MBOX_REQUEST; // this is a request message
  215. mbox[2] = MBOX_TAG_FB_SET_ALPHA_MODE;
  216. mbox[3] = 4; // buffer size
  217. mbox[4] = 4; // len
  218. mbox[5] = alpha; // id
  219. mbox[6] = 0;
  220. mbox[7] = MBOX_TAG_LAST;
  221. mbox_call(8, MMU_DISABLE);
  222. }
  223. void *bcm271x_mbox_fb_alloc(int width, int height, int bpp, int nrender)
  224. {
  225. mbox[0] = 4 * 35;
  226. mbox[1] = MBOX_REQUEST;
  227. mbox[2] = TAG_ALLOCATE_BUFFER;//get framebuffer, gets alignment on request
  228. mbox[3] = 8; //size
  229. mbox[4] = 4; //len
  230. mbox[5] = 4096; //The design of MBOX driver forces us to give the virtual address 0x3C100000
  231. mbox[6] = 0; //FrameBufferInfo.size
  232. mbox[7] = TAG_SET_PHYS_WIDTH_HEIGHT;
  233. mbox[8] = 8;
  234. mbox[9] = 8;
  235. mbox[10] = width;
  236. mbox[11] = height;
  237. mbox[12] = TAG_SET_VIRT_WIDTH_HEIGHT;
  238. mbox[13] = 8;
  239. mbox[14] = 8;
  240. mbox[15] = width;
  241. mbox[16] = height * nrender;
  242. mbox[17] = TAG_SET_DEPTH;
  243. mbox[18] = 4;
  244. mbox[19] = 4;
  245. mbox[20] = bpp;
  246. mbox[21] = TAG_SET_PIXEL_ORDER;
  247. mbox[22] = 4;
  248. mbox[23] = 0;
  249. mbox[24] = 0; //RGB, not BGR preferably
  250. mbox[25] = TAG_GET_PITCH;
  251. mbox[26] = 4;
  252. mbox[27] = 0;
  253. mbox[28] = 0;
  254. mbox[29] = TAG_SET_VIRT_OFFSET;
  255. mbox[30] = 8;
  256. mbox[31] = 8;
  257. mbox[32] = 0;
  258. mbox[33] = 0;
  259. mbox[34] = TAG_END;
  260. mbox_call(8, MMU_DISABLE);
  261. return (void *)((size_t)(mbox[5] & 0x3fffffff));
  262. }
  263. int hdmi_fb_init(void)
  264. {
  265. _hdmi.fb = (rt_uint8_t *)bcm271x_mbox_fb_alloc(LCD_WIDTH, LCD_HEIGHT, LCD_BPP, 1);
  266. if (_hdmi.fb == RT_NULL)
  267. {
  268. rt_kprintf("init hdmi fb err!\n");
  269. return -RT_ERROR;
  270. }
  271. #ifdef BSP_USING_VM_MODE
  272. if (rt_hv_stage2_map((unsigned long)_hdmi.fb, 0x1400000))
  273. {
  274. rt_kprintf("alloc mmio from hyper fail!\n");
  275. return -RT_ERROR;
  276. }
  277. #endif
  278. bcm271x_mbox_fb_setoffset(0, 0);
  279. bcm271x_mbox_fb_set_porder(0);
  280. _hdmi.width = LCD_WIDTH;
  281. _hdmi.height = LCD_HEIGHT;
  282. _hdmi.depth = LCD_DEPTH;
  283. _hdmi.pitch = 0;
  284. _hdmi.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888;
  285. //rt_kprintf("_hdmi.fb is %p\n", _hdmi.fb);
  286. rt_hdmi_fb_device_init(&_hdmi, "lcd");
  287. return 0;
  288. }
  289. INIT_DEVICE_EXPORT(hdmi_fb_init);
  290. #endif /*BSP_USING_HDMI */