mtk_drm_fbdev.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. * Copyright (c) 2016 MediaTek Inc.
  3. * Copyright (C) 2021 XiaoMi, Inc.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/gfp.h>
  15. #include <linux/kmemleak.h>
  16. #include <drm/drmP.h>
  17. #include <drm/drm_crtc_helper.h>
  18. #include <drm/drm_fb_helper.h>
  19. #include <drm/drm_gem.h>
  20. #include <drm/drm_crtc.h>
  21. #include <drm/drm_atomic_helper.h>
  22. #include "mtk_drm_drv.h"
  23. #include "mtk_drm_fb.h"
  24. #include "mtk_drm_gem.h"
  25. #include "mtk_drm_fbdev.h"
  26. #include "mtk_drm_assert.h"
  27. #include "mtk_log.h"
  28. #include "mtk_drm_crtc.h"
  29. #include "mtk_drm_helper.h"
  30. #include "mtk_log.h"
  31. #include "mtk_drm_mmp.h"
  32. #define to_drm_private(x) container_of(x, struct mtk_drm_private, fb_helper)
  33. #define ALIGN_TO_32(x) ALIGN_TO(x, 32)
  34. struct fb_info *debug_info;
  35. unsigned int mtk_drm_fb_fm_auto_test(struct fb_info *info)
  36. {
  37. struct drm_fb_helper *fb_helper = info->par;
  38. struct drm_device *drm_dev = fb_helper->dev;
  39. struct drm_crtc *crtc;
  40. struct mtk_drm_crtc *mtk_crtc;
  41. struct mtk_drm_private *private;
  42. int ret = 0;
  43. /* this debug cmd only for crtc0 */
  44. crtc = list_first_entry(&(drm_dev)->mode_config.crtc_list,
  45. typeof(*crtc), head);
  46. if (!crtc) {
  47. DDPPR_ERR("find crtc fail\n");
  48. return -1;
  49. }
  50. mtk_crtc = to_mtk_crtc(crtc);
  51. DDP_MUTEX_LOCK(&mtk_crtc->lock, __func__, __LINE__);
  52. if (!mtk_crtc->enabled || mtk_crtc->ddp_mode == DDP_NO_USE) {
  53. DDPINFO("crtc 0 is already sleep, skip\n");
  54. DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
  55. return 0;
  56. }
  57. private = drm_dev->dev_private;
  58. if (mtk_drm_helper_get_opt(private->helper_opt,
  59. MTK_DRM_OPT_IDLE_MGR)) {
  60. mtk_drm_set_idlemgr(crtc, 0, 0);
  61. }
  62. ret = mtk_crtc_lcm_ATA(crtc);
  63. if (mtk_drm_helper_get_opt(private->helper_opt,
  64. MTK_DRM_OPT_IDLE_MGR))
  65. mtk_drm_set_idlemgr(crtc, 1, 0);
  66. DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
  67. if (ret == 0)
  68. DDPPR_ERR("ATA LCM failed\n");
  69. else
  70. DDPPR_ERR("ATA LCM passed\n");
  71. return ret;
  72. }
  73. static int mtk_drm_fb_ioctl(struct fb_info *info, unsigned int cmd,
  74. unsigned long arg)
  75. {
  76. switch (cmd) {
  77. case MTKFB_FACTORY_AUTO_TEST:
  78. {
  79. unsigned int result = 0;
  80. void __user *argp = (void __user *)arg;
  81. DDPMSG("factory mode: lcm auto test\n");
  82. result = mtk_drm_fb_fm_auto_test(info);
  83. return copy_to_user(argp, &result, sizeof(result)) ?
  84. -EFAULT : 0;
  85. }
  86. default:
  87. DDPINFO("%s: Not support:info=0x%p, cmd=0x%08x, arg=0x%08lx\n",
  88. __func__, info, (unsigned int)cmd, arg);
  89. break;
  90. }
  91. return 0;
  92. }
  93. static int mtk_drm_fb_pan_display(struct fb_var_screeninfo *var,
  94. struct fb_info *info)
  95. {
  96. struct drm_fb_helper *fb_helper = info->par;
  97. struct drm_device *drm_dev = fb_helper->dev;
  98. struct drm_crtc *crtc;
  99. struct mtk_drm_crtc *mtk_crtc;
  100. struct cmdq_pkt *cmdq_handle;
  101. int ret;
  102. ret = drm_fb_helper_pan_display(var, info);
  103. crtc = list_first_entry(&(drm_dev)->mode_config.crtc_list,
  104. typeof(*crtc), head);
  105. if (!crtc) {
  106. DDPPR_ERR("find crtc fail\n");
  107. return ret;
  108. }
  109. mtk_crtc = to_mtk_crtc(crtc);
  110. DDP_MUTEX_LOCK(&mtk_crtc->lock, __func__, __LINE__);
  111. mtk_crtc_pkt_create(&cmdq_handle, &mtk_crtc->base,
  112. mtk_crtc->gce_obj.client[CLIENT_CFG]);
  113. if (mtk_crtc_with_sub_path(crtc, mtk_crtc->ddp_mode))
  114. mtk_crtc_wait_frame_done(mtk_crtc, cmdq_handle,
  115. DDP_SECOND_PATH, 0);
  116. else
  117. mtk_crtc_wait_frame_done(mtk_crtc, cmdq_handle,
  118. DDP_FIRST_PATH, 0);
  119. cmdq_pkt_flush(cmdq_handle);
  120. cmdq_pkt_destroy(cmdq_handle);
  121. DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
  122. return ret;
  123. }
  124. /* used when early porting, test pan display*/
  125. void disp_get_fb_address(unsigned long *fbVirAddr)
  126. {
  127. *fbVirAddr = (unsigned long)debug_info->screen_base;
  128. pr_info(
  129. "%s fbdev->fb_va_base = 0x%p\n",
  130. __func__, debug_info->screen_base);
  131. }
  132. int pan_display_test(int frame_num, int bpp)
  133. {
  134. int i, j;
  135. int Bpp = bpp / 8;
  136. unsigned char *fb_va;
  137. unsigned int fb_size;
  138. int w, h, fb_h;
  139. int yoffset_max;
  140. int yoffset;
  141. debug_info->var.yoffset = 0;
  142. disp_get_fb_address((unsigned long *)&fb_va);
  143. if (!fb_va)
  144. return 0;
  145. if (!mtk_crtc_frame_buffer_existed())
  146. return 0;
  147. fb_size = debug_info->fix.smem_len;
  148. w = debug_info->var.xres;
  149. h = debug_info->var.yres;
  150. fb_h = fb_size / (ALIGN_TO(w, 32) * Bpp) - 10;
  151. pr_info("%s: frame_num=%d,bpp=%d, w=%d,h=%d,fb_h=%d\n",
  152. __func__, frame_num, bpp, w, h, fb_h);
  153. for (i = 0; i < fb_h; i++)
  154. for (j = 0; j < w; j++) {
  155. int x = (i * ALIGN_TO(w, 32) + j) * Bpp;
  156. fb_va[x++] = (i + j) % 256;
  157. fb_va[x++] = (i + j) % 256;
  158. fb_va[x++] = (i + j) % 256;
  159. if (Bpp == 4)
  160. fb_va[x++] = 255;
  161. }
  162. debug_info->var.bits_per_pixel = bpp;
  163. yoffset_max = fb_h - h;
  164. yoffset = 0;
  165. for (i = 0; i < frame_num; i++, yoffset += 10) {
  166. if (yoffset >= yoffset_max)
  167. yoffset = 0;
  168. debug_info->var.xoffset = 0;
  169. debug_info->var.yoffset = yoffset;
  170. mtk_drm_fb_pan_display(&debug_info->var, debug_info);
  171. }
  172. DDPMSG("%s, %d--\n", __func__, __LINE__);
  173. return 0;
  174. }
  175. #define MTK_LEGACY_FB_MAP
  176. #ifndef MTK_LEGACY_FB_MAP
  177. static int mtk_drm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
  178. {
  179. struct drm_fb_helper *helper = info->par;
  180. struct mtk_drm_private *private = helper->dev->dev_private;
  181. debug_info = info;
  182. return mtk_drm_gem_mmap_buf(private->fbdev_bo, vma);
  183. }
  184. #endif
  185. static struct fb_ops mtk_fbdev_ops = {
  186. .owner = THIS_MODULE,
  187. .fb_fillrect = drm_fb_helper_cfb_fillrect,
  188. .fb_copyarea = drm_fb_helper_cfb_copyarea,
  189. .fb_imageblit = drm_fb_helper_cfb_imageblit,
  190. .fb_check_var = drm_fb_helper_check_var,
  191. .fb_set_par = drm_fb_helper_set_par,
  192. .fb_blank = drm_fb_helper_blank,
  193. .fb_pan_display = mtk_drm_fb_pan_display,
  194. .fb_setcmap = drm_fb_helper_setcmap,
  195. #ifndef MTK_LEGACY_FB_MAP
  196. .fb_mmap = mtk_drm_fbdev_mmap,
  197. #endif
  198. .fb_ioctl = mtk_drm_fb_ioctl,
  199. };
  200. bool mtk_drm_lcm_is_connect(void)
  201. {
  202. struct device_node *chosen_node;
  203. chosen_node = of_find_node_by_path("/chosen");
  204. if (chosen_node) {
  205. struct tag_videolfb *videolfb_tag = NULL;
  206. unsigned long size = 0;
  207. videolfb_tag = (struct tag_videolfb *)of_get_property(
  208. chosen_node,
  209. "atag,videolfb", (int *)&size);
  210. if (videolfb_tag)
  211. return videolfb_tag->islcmfound;
  212. DDPINFO("[DT][videolfb] videolfb_tag not found\n");
  213. } else {
  214. DDPINFO("[DT][videolfb] of_chosen not found\n");
  215. }
  216. return false;
  217. }
  218. int _parse_tag_videolfb(unsigned int *vramsize, phys_addr_t *fb_base,
  219. unsigned int *fps)
  220. {
  221. struct device_node *chosen_node;
  222. *fps = 6000;
  223. chosen_node = of_find_node_by_path("/chosen");
  224. if (chosen_node) {
  225. struct tag_videolfb *videolfb_tag = NULL;
  226. unsigned long size = 0;
  227. videolfb_tag = (struct tag_videolfb *)of_get_property(
  228. chosen_node, "atag,videolfb", (int *)&size);
  229. if (videolfb_tag) {
  230. *vramsize = videolfb_tag->vram;
  231. *fb_base = videolfb_tag->fb_base;
  232. *fps = videolfb_tag->fps;
  233. if (*fps == 0)
  234. *fps = 6000;
  235. return 0;
  236. }
  237. DDPINFO("[DT][videolfb] videolfb_tag not found\n");
  238. goto found;
  239. } else {
  240. DDPINFO("[DT][videolfb] of_chosen not found\n");
  241. }
  242. return -1;
  243. found:
  244. DDPINFO("[DT][videolfb] fb_base = 0x%lx\n", (unsigned long)*fb_base);
  245. DDPINFO("[DT][videolfb] vram = 0x%x (%d)\n", *vramsize,
  246. *vramsize);
  247. DDPINFO("[DT][videolfb] fps = %d\n", *fps);
  248. return 0;
  249. }
  250. int free_fb_buf(void)
  251. {
  252. unsigned long va_start = 0;
  253. unsigned long va_end = 0;
  254. phys_addr_t fb_base;
  255. unsigned int vramsize, fps;
  256. _parse_tag_videolfb(&vramsize, &fb_base, &fps);
  257. if (!fb_base) {
  258. DDPINFO("%s:get fb pa error\n", __func__);
  259. return -1;
  260. }
  261. va_start = (unsigned long)__va(fb_base);
  262. va_end = (unsigned long)__va(fb_base + (unsigned long)vramsize);
  263. if (va_start)
  264. free_reserved_area((void *)va_start,
  265. (void *)va_end, 0xff, "fbmem");
  266. else
  267. DDPINFO("%s:va invalid\n", __func__);
  268. return 0;
  269. }
  270. static int mtk_fbdev_probe(struct drm_fb_helper *helper,
  271. struct drm_fb_helper_surface_size *sizes)
  272. {
  273. struct drm_device *dev = helper->dev;
  274. struct mtk_drm_private *private = helper->dev->dev_private;
  275. struct drm_mode_fb_cmd2 mode = {0};
  276. struct mtk_drm_gem_obj *mtk_gem;
  277. struct fb_info *info;
  278. struct drm_framebuffer *fb;
  279. unsigned int bytes_per_pixel, vramsize = 0, fps = 0;
  280. size_t size;
  281. int err;
  282. phys_addr_t fb_base = 0;
  283. DDPMSG("%s+\n", __func__);
  284. bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
  285. mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
  286. sizes->surface_depth);
  287. if (_parse_tag_videolfb(&vramsize, &fb_base, &fps) < 0) {
  288. DDPINFO("[DT][videolfb] fb_base = 0x%lx\n",
  289. (unsigned long)fb_base);
  290. DDPINFO("[DT][videolfb] vram = 0x%x (%d)\n",
  291. vramsize, vramsize);
  292. DDPINFO("[DT][videolfb] fps = %d\n", fps);
  293. mode.width = sizes->surface_width;
  294. mode.height = sizes->surface_height;
  295. mode.pitches[0] = sizes->surface_width * bytes_per_pixel;
  296. size = mode.pitches[0] * mode.height;
  297. mtk_gem = mtk_drm_gem_create(dev, size, true);
  298. if (IS_ERR(mtk_gem))
  299. return PTR_ERR(mtk_gem);
  300. } else {
  301. mode.width = ALIGN_TO_32(sizes->surface_width);
  302. /* LK pre-allocate triple buffer */
  303. mode.height = ALIGN_TO_32(sizes->surface_height) * 3;
  304. mode.pitches[0] =
  305. ALIGN_TO_32(sizes->surface_width) * bytes_per_pixel;
  306. size = mode.pitches[0] * mode.height;
  307. mtk_gem = mtk_drm_fb_gem_insert(dev, size, fb_base, vramsize);
  308. if (IS_ERR(mtk_gem))
  309. return PTR_ERR(mtk_gem);
  310. kmemleak_ignore(mtk_gem);
  311. }
  312. private->fbdev_bo = &mtk_gem->base;
  313. info = drm_fb_helper_alloc_fbi(helper);
  314. if (IS_ERR(info)) {
  315. err = PTR_ERR(info);
  316. dev_err(dev->dev, "failed to allocate framebuffer info, %d\n",
  317. err);
  318. goto err_gem_free_object;
  319. }
  320. fb = mtk_drm_framebuffer_create(dev, &mode, private->fbdev_bo);
  321. if (IS_ERR(fb)) {
  322. err = PTR_ERR(fb);
  323. dev_err(dev->dev, "failed to allocate DRM framebuffer, %d\n",
  324. err);
  325. goto err_release_fbi;
  326. }
  327. helper->fb = fb;
  328. info->par = helper;
  329. info->flags = FBINFO_FLAG_DEFAULT;
  330. info->fbops = &mtk_fbdev_ops;
  331. drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
  332. drm_fb_helper_fill_var(info, helper, sizes->fb_width, sizes->fb_height);
  333. dev->mode_config.fb_base = fb_base;
  334. info->screen_base = mtk_gem->kvaddr;
  335. info->screen_size = size;
  336. info->fix.smem_len = size;
  337. info->fix.smem_start = fb_base;
  338. debug_info = info;
  339. #if !defined(CONFIG_DRM_MTK_DISABLE_AEE_LAYER)
  340. mtk_drm_assert_fb_init(dev,
  341. sizes->surface_width, sizes->surface_height);
  342. #endif
  343. DRM_DEBUG_KMS("FB [%ux%u]-%u size=%zd\n", fb->width,
  344. fb->height, fb->format->depth, size);
  345. info->skip_vt_switch = true;
  346. DDPMSG("%s-\n", __func__);
  347. return 0;
  348. err_release_fbi:
  349. err_gem_free_object:
  350. mtk_drm_gem_free_object(&mtk_gem->base);
  351. return err;
  352. }
  353. static const struct drm_fb_helper_funcs mtk_drm_fb_helper_funcs = {
  354. .fb_probe = mtk_fbdev_probe,
  355. };
  356. static int mtk_drm_fb_add_one_connector(struct drm_device *dev,
  357. struct drm_fb_helper *helper)
  358. {
  359. struct drm_connector *connector;
  360. struct drm_connector_list_iter conn_iter;
  361. struct drm_encoder *encoder;
  362. const struct drm_connector_helper_funcs *helper_private;
  363. int ret = 0;
  364. drm_connector_list_iter_begin(dev, &conn_iter);
  365. drm_for_each_connector_iter(connector, &conn_iter) {
  366. helper_private = connector->helper_private;
  367. if (helper_private->best_encoder)
  368. encoder = helper_private->best_encoder(connector);
  369. else
  370. encoder = drm_atomic_helper_best_encoder(connector);
  371. if (encoder && (encoder->possible_crtcs & 0x1)) {
  372. ret = drm_fb_helper_add_one_connector(
  373. helper, connector);
  374. break;
  375. }
  376. }
  377. drm_connector_list_iter_end(&conn_iter);
  378. return ret;
  379. }
  380. int mtk_fbdev_init(struct drm_device *dev)
  381. {
  382. struct mtk_drm_private *priv = dev->dev_private;
  383. struct drm_fb_helper *helper = &priv->fb_helper;
  384. int ret;
  385. DDPMSG("%s+\n", __func__);
  386. if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
  387. return -EINVAL;
  388. drm_fb_helper_prepare(dev, helper, &mtk_drm_fb_helper_funcs);
  389. ret = drm_fb_helper_init(dev, helper, 1);
  390. if (ret) {
  391. dev_err(dev->dev, "failed to initialize DRM FB helper, %d\n",
  392. ret);
  393. goto fini;
  394. }
  395. ret = mtk_drm_fb_add_one_connector(dev, helper);
  396. if (ret) {
  397. dev_err(dev->dev, "failed to add connectors, %d\n", ret);
  398. goto fini;
  399. }
  400. ret = drm_fb_helper_initial_config(helper, 32);
  401. if (ret) {
  402. dev_err(dev->dev, "failed to set initial configuration, %d\n",
  403. ret);
  404. goto fini;
  405. }
  406. DDPMSG("%s-\n", __func__);
  407. return 0;
  408. fini:
  409. drm_fb_helper_fini(helper);
  410. return ret;
  411. }
  412. void mtk_fbdev_fini(struct drm_device *dev)
  413. {
  414. struct mtk_drm_private *priv = dev->dev_private;
  415. struct drm_fb_helper *helper = &priv->fb_helper;
  416. drm_fb_helper_unregister_fbi(helper);
  417. if (helper->fb) {
  418. drm_framebuffer_unregister_private(helper->fb);
  419. drm_framebuffer_remove(helper->fb);
  420. }
  421. drm_fb_helper_fini(helper);
  422. }