zx_plane.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Copyright 2016 Linaro Ltd.
  3. * Copyright 2016 ZTE Corporation.
  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. */
  10. #include <drm/drm_atomic.h>
  11. #include <drm/drm_atomic_helper.h>
  12. #include <drm/drm_fb_cma_helper.h>
  13. #include <drm/drm_gem_cma_helper.h>
  14. #include <drm/drm_modeset_helper_vtables.h>
  15. #include <drm/drm_plane_helper.h>
  16. #include <drm/drmP.h>
  17. #include "zx_drm_drv.h"
  18. #include "zx_plane.h"
  19. #include "zx_plane_regs.h"
  20. #include "zx_vou.h"
  21. static const uint32_t gl_formats[] = {
  22. DRM_FORMAT_ARGB8888,
  23. DRM_FORMAT_XRGB8888,
  24. DRM_FORMAT_RGB888,
  25. DRM_FORMAT_RGB565,
  26. DRM_FORMAT_ARGB1555,
  27. DRM_FORMAT_ARGB4444,
  28. };
  29. static const uint32_t vl_formats[] = {
  30. DRM_FORMAT_NV12, /* Semi-planar YUV420 */
  31. DRM_FORMAT_YUV420, /* Planar YUV420 */
  32. DRM_FORMAT_YUYV, /* Packed YUV422 */
  33. DRM_FORMAT_YVYU,
  34. DRM_FORMAT_UYVY,
  35. DRM_FORMAT_VYUY,
  36. DRM_FORMAT_YUV444, /* YUV444 8bit */
  37. /*
  38. * TODO: add formats below that HW supports:
  39. * - YUV420 P010
  40. * - YUV420 Hantro
  41. * - YUV444 10bit
  42. */
  43. };
  44. #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
  45. static int zx_vl_plane_atomic_check(struct drm_plane *plane,
  46. struct drm_plane_state *plane_state)
  47. {
  48. struct drm_framebuffer *fb = plane_state->fb;
  49. struct drm_crtc *crtc = plane_state->crtc;
  50. struct drm_crtc_state *crtc_state;
  51. struct drm_rect clip;
  52. int min_scale = FRAC_16_16(1, 8);
  53. int max_scale = FRAC_16_16(8, 1);
  54. if (!crtc || !fb)
  55. return 0;
  56. crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
  57. crtc);
  58. if (WARN_ON(!crtc_state))
  59. return -EINVAL;
  60. /* nothing to check when disabling or disabled */
  61. if (!crtc_state->enable)
  62. return 0;
  63. /* plane must be enabled */
  64. if (!plane_state->crtc)
  65. return -EINVAL;
  66. clip.x1 = 0;
  67. clip.y1 = 0;
  68. clip.x2 = crtc_state->adjusted_mode.hdisplay;
  69. clip.y2 = crtc_state->adjusted_mode.vdisplay;
  70. return drm_plane_helper_check_state(plane_state, &clip,
  71. min_scale, max_scale,
  72. true, true);
  73. }
  74. static int zx_vl_get_fmt(uint32_t format)
  75. {
  76. switch (format) {
  77. case DRM_FORMAT_NV12:
  78. return VL_FMT_YUV420;
  79. case DRM_FORMAT_YUV420:
  80. return VL_YUV420_PLANAR | VL_FMT_YUV420;
  81. case DRM_FORMAT_YUYV:
  82. return VL_YUV422_YUYV | VL_FMT_YUV422;
  83. case DRM_FORMAT_YVYU:
  84. return VL_YUV422_YVYU | VL_FMT_YUV422;
  85. case DRM_FORMAT_UYVY:
  86. return VL_YUV422_UYVY | VL_FMT_YUV422;
  87. case DRM_FORMAT_VYUY:
  88. return VL_YUV422_VYUY | VL_FMT_YUV422;
  89. case DRM_FORMAT_YUV444:
  90. return VL_FMT_YUV444_8BIT;
  91. default:
  92. WARN_ONCE(1, "invalid pixel format %d\n", format);
  93. return -EINVAL;
  94. }
  95. }
  96. static inline void zx_vl_set_update(struct zx_plane *zplane)
  97. {
  98. void __iomem *layer = zplane->layer;
  99. zx_writel_mask(layer + VL_CTRL0, VL_UPDATE, VL_UPDATE);
  100. }
  101. static inline void zx_vl_rsz_set_update(struct zx_plane *zplane)
  102. {
  103. zx_writel(zplane->rsz + RSZ_VL_ENABLE_CFG, 1);
  104. }
  105. static int zx_vl_rsz_get_fmt(uint32_t format)
  106. {
  107. switch (format) {
  108. case DRM_FORMAT_NV12:
  109. case DRM_FORMAT_YUV420:
  110. return RSZ_VL_FMT_YCBCR420;
  111. case DRM_FORMAT_YUYV:
  112. case DRM_FORMAT_YVYU:
  113. case DRM_FORMAT_UYVY:
  114. case DRM_FORMAT_VYUY:
  115. return RSZ_VL_FMT_YCBCR422;
  116. case DRM_FORMAT_YUV444:
  117. return RSZ_VL_FMT_YCBCR444;
  118. default:
  119. WARN_ONCE(1, "invalid pixel format %d\n", format);
  120. return -EINVAL;
  121. }
  122. }
  123. static inline u32 rsz_step_value(u32 src, u32 dst)
  124. {
  125. u32 val = 0;
  126. if (src == dst)
  127. val = 0;
  128. else if (src < dst)
  129. val = RSZ_PARA_STEP((src << 16) / dst);
  130. else if (src > dst)
  131. val = RSZ_DATA_STEP(src / dst) |
  132. RSZ_PARA_STEP(((src << 16) / dst) & 0xffff);
  133. return val;
  134. }
  135. static void zx_vl_rsz_setup(struct zx_plane *zplane, uint32_t format,
  136. u32 src_w, u32 src_h, u32 dst_w, u32 dst_h)
  137. {
  138. void __iomem *rsz = zplane->rsz;
  139. u32 src_chroma_w = src_w;
  140. u32 src_chroma_h = src_h;
  141. int fmt;
  142. /* Set up source and destination resolution */
  143. zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
  144. zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
  145. /* Configure data format for VL RSZ */
  146. fmt = zx_vl_rsz_get_fmt(format);
  147. if (fmt >= 0)
  148. zx_writel_mask(rsz + RSZ_VL_CTRL_CFG, RSZ_VL_FMT_MASK, fmt);
  149. /* Calculate Chroma height and width */
  150. if (fmt == RSZ_VL_FMT_YCBCR420) {
  151. src_chroma_w = src_w >> 1;
  152. src_chroma_h = src_h >> 1;
  153. } else if (fmt == RSZ_VL_FMT_YCBCR422) {
  154. src_chroma_w = src_w >> 1;
  155. }
  156. /* Set up Luma and Chroma step registers */
  157. zx_writel(rsz + RSZ_VL_LUMA_HOR, rsz_step_value(src_w, dst_w));
  158. zx_writel(rsz + RSZ_VL_LUMA_VER, rsz_step_value(src_h, dst_h));
  159. zx_writel(rsz + RSZ_VL_CHROMA_HOR, rsz_step_value(src_chroma_w, dst_w));
  160. zx_writel(rsz + RSZ_VL_CHROMA_VER, rsz_step_value(src_chroma_h, dst_h));
  161. zx_vl_rsz_set_update(zplane);
  162. }
  163. static void zx_vl_plane_atomic_update(struct drm_plane *plane,
  164. struct drm_plane_state *old_state)
  165. {
  166. struct zx_plane *zplane = to_zx_plane(plane);
  167. struct drm_plane_state *state = plane->state;
  168. struct drm_framebuffer *fb = state->fb;
  169. struct drm_rect *src = &state->src;
  170. struct drm_rect *dst = &state->dst;
  171. struct drm_gem_cma_object *cma_obj;
  172. void __iomem *layer = zplane->layer;
  173. void __iomem *hbsc = zplane->hbsc;
  174. void __iomem *paddr_reg;
  175. dma_addr_t paddr;
  176. u32 src_x, src_y, src_w, src_h;
  177. u32 dst_x, dst_y, dst_w, dst_h;
  178. uint32_t format;
  179. int fmt;
  180. int num_planes;
  181. int i;
  182. if (!fb)
  183. return;
  184. format = fb->format->format;
  185. src_x = src->x1 >> 16;
  186. src_y = src->y1 >> 16;
  187. src_w = drm_rect_width(src) >> 16;
  188. src_h = drm_rect_height(src) >> 16;
  189. dst_x = dst->x1;
  190. dst_y = dst->y1;
  191. dst_w = drm_rect_width(dst);
  192. dst_h = drm_rect_height(dst);
  193. /* Set up data address registers for Y, Cb and Cr planes */
  194. num_planes = drm_format_num_planes(format);
  195. paddr_reg = layer + VL_Y;
  196. for (i = 0; i < num_planes; i++) {
  197. cma_obj = drm_fb_cma_get_gem_obj(fb, i);
  198. paddr = cma_obj->paddr + fb->offsets[i];
  199. paddr += src_y * fb->pitches[i];
  200. paddr += src_x * drm_format_plane_cpp(format, i);
  201. zx_writel(paddr_reg, paddr);
  202. paddr_reg += 4;
  203. }
  204. /* Set up source height/width register */
  205. zx_writel(layer + VL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
  206. /* Set up start position register */
  207. zx_writel(layer + VL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
  208. /* Set up end position register */
  209. zx_writel(layer + VL_POS_END,
  210. GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
  211. /* Strides of Cb and Cr planes should be identical */
  212. zx_writel(layer + VL_STRIDE, LUMA_STRIDE(fb->pitches[0]) |
  213. CHROMA_STRIDE(fb->pitches[1]));
  214. /* Set up video layer data format */
  215. fmt = zx_vl_get_fmt(format);
  216. if (fmt >= 0)
  217. zx_writel(layer + VL_CTRL1, fmt);
  218. /* Always use scaler since it exists (set for not bypass) */
  219. zx_writel_mask(layer + VL_CTRL2, VL_SCALER_BYPASS_MODE,
  220. VL_SCALER_BYPASS_MODE);
  221. zx_vl_rsz_setup(zplane, format, src_w, src_h, dst_w, dst_h);
  222. /* Enable HBSC block */
  223. zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
  224. zx_vou_layer_enable(plane);
  225. zx_vl_set_update(zplane);
  226. }
  227. static void zx_plane_atomic_disable(struct drm_plane *plane,
  228. struct drm_plane_state *old_state)
  229. {
  230. struct zx_plane *zplane = to_zx_plane(plane);
  231. void __iomem *hbsc = zplane->hbsc;
  232. zx_vou_layer_disable(plane);
  233. /* Disable HBSC block */
  234. zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, 0);
  235. }
  236. static const struct drm_plane_helper_funcs zx_vl_plane_helper_funcs = {
  237. .atomic_check = zx_vl_plane_atomic_check,
  238. .atomic_update = zx_vl_plane_atomic_update,
  239. .atomic_disable = zx_plane_atomic_disable,
  240. };
  241. static int zx_gl_plane_atomic_check(struct drm_plane *plane,
  242. struct drm_plane_state *plane_state)
  243. {
  244. struct drm_framebuffer *fb = plane_state->fb;
  245. struct drm_crtc *crtc = plane_state->crtc;
  246. struct drm_crtc_state *crtc_state;
  247. struct drm_rect clip;
  248. if (!crtc || !fb)
  249. return 0;
  250. crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
  251. crtc);
  252. if (WARN_ON(!crtc_state))
  253. return -EINVAL;
  254. /* nothing to check when disabling or disabled */
  255. if (!crtc_state->enable)
  256. return 0;
  257. /* plane must be enabled */
  258. if (!plane_state->crtc)
  259. return -EINVAL;
  260. clip.x1 = 0;
  261. clip.y1 = 0;
  262. clip.x2 = crtc_state->adjusted_mode.hdisplay;
  263. clip.y2 = crtc_state->adjusted_mode.vdisplay;
  264. return drm_plane_helper_check_state(plane_state, &clip,
  265. DRM_PLANE_HELPER_NO_SCALING,
  266. DRM_PLANE_HELPER_NO_SCALING,
  267. false, true);
  268. }
  269. static int zx_gl_get_fmt(uint32_t format)
  270. {
  271. switch (format) {
  272. case DRM_FORMAT_ARGB8888:
  273. case DRM_FORMAT_XRGB8888:
  274. return GL_FMT_ARGB8888;
  275. case DRM_FORMAT_RGB888:
  276. return GL_FMT_RGB888;
  277. case DRM_FORMAT_RGB565:
  278. return GL_FMT_RGB565;
  279. case DRM_FORMAT_ARGB1555:
  280. return GL_FMT_ARGB1555;
  281. case DRM_FORMAT_ARGB4444:
  282. return GL_FMT_ARGB4444;
  283. default:
  284. WARN_ONCE(1, "invalid pixel format %d\n", format);
  285. return -EINVAL;
  286. }
  287. }
  288. static inline void zx_gl_set_update(struct zx_plane *zplane)
  289. {
  290. void __iomem *layer = zplane->layer;
  291. zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
  292. }
  293. static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
  294. {
  295. zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
  296. }
  297. static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
  298. u32 dst_w, u32 dst_h)
  299. {
  300. void __iomem *rsz = zplane->rsz;
  301. zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
  302. zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
  303. zx_gl_rsz_set_update(zplane);
  304. }
  305. static void zx_gl_plane_atomic_update(struct drm_plane *plane,
  306. struct drm_plane_state *old_state)
  307. {
  308. struct zx_plane *zplane = to_zx_plane(plane);
  309. struct drm_framebuffer *fb = plane->state->fb;
  310. struct drm_gem_cma_object *cma_obj;
  311. void __iomem *layer = zplane->layer;
  312. void __iomem *csc = zplane->csc;
  313. void __iomem *hbsc = zplane->hbsc;
  314. u32 src_x, src_y, src_w, src_h;
  315. u32 dst_x, dst_y, dst_w, dst_h;
  316. unsigned int bpp;
  317. uint32_t format;
  318. dma_addr_t paddr;
  319. u32 stride;
  320. int fmt;
  321. if (!fb)
  322. return;
  323. format = fb->format->format;
  324. stride = fb->pitches[0];
  325. src_x = plane->state->src_x >> 16;
  326. src_y = plane->state->src_y >> 16;
  327. src_w = plane->state->src_w >> 16;
  328. src_h = plane->state->src_h >> 16;
  329. dst_x = plane->state->crtc_x;
  330. dst_y = plane->state->crtc_y;
  331. dst_w = plane->state->crtc_w;
  332. dst_h = plane->state->crtc_h;
  333. bpp = fb->format->cpp[0];
  334. cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
  335. paddr = cma_obj->paddr + fb->offsets[0];
  336. paddr += src_y * stride + src_x * bpp / 8;
  337. zx_writel(layer + GL_ADDR, paddr);
  338. /* Set up source height/width register */
  339. zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
  340. /* Set up start position register */
  341. zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
  342. /* Set up end position register */
  343. zx_writel(layer + GL_POS_END,
  344. GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
  345. /* Set up stride register */
  346. zx_writel(layer + GL_STRIDE, stride & 0xffff);
  347. /* Set up graphic layer data format */
  348. fmt = zx_gl_get_fmt(format);
  349. if (fmt >= 0)
  350. zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
  351. fmt << GL_DATA_FMT_SHIFT);
  352. /* Initialize global alpha with a sane value */
  353. zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
  354. 0xff << GL_GLOBAL_ALPHA_SHIFT);
  355. /* Setup CSC for the GL */
  356. if (dst_h > 720)
  357. zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
  358. CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
  359. else
  360. zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
  361. CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
  362. zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
  363. /* Always use scaler since it exists (set for not bypass) */
  364. zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
  365. GL_SCALER_BYPASS_MODE);
  366. zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
  367. /* Enable HBSC block */
  368. zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
  369. zx_vou_layer_enable(plane);
  370. zx_gl_set_update(zplane);
  371. }
  372. static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
  373. .atomic_check = zx_gl_plane_atomic_check,
  374. .atomic_update = zx_gl_plane_atomic_update,
  375. .atomic_disable = zx_plane_atomic_disable,
  376. };
  377. static void zx_plane_destroy(struct drm_plane *plane)
  378. {
  379. drm_plane_helper_disable(plane);
  380. drm_plane_cleanup(plane);
  381. }
  382. static const struct drm_plane_funcs zx_plane_funcs = {
  383. .update_plane = drm_atomic_helper_update_plane,
  384. .disable_plane = drm_atomic_helper_disable_plane,
  385. .destroy = zx_plane_destroy,
  386. .reset = drm_atomic_helper_plane_reset,
  387. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  388. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  389. };
  390. void zx_plane_set_update(struct drm_plane *plane)
  391. {
  392. struct zx_plane *zplane = to_zx_plane(plane);
  393. /* Do nothing if the plane is not enabled */
  394. if (!plane->state->crtc)
  395. return;
  396. switch (plane->type) {
  397. case DRM_PLANE_TYPE_PRIMARY:
  398. zx_gl_rsz_set_update(zplane);
  399. zx_gl_set_update(zplane);
  400. break;
  401. case DRM_PLANE_TYPE_OVERLAY:
  402. zx_vl_rsz_set_update(zplane);
  403. zx_vl_set_update(zplane);
  404. break;
  405. default:
  406. WARN_ONCE(1, "unsupported plane type %d\n", plane->type);
  407. }
  408. }
  409. static void zx_plane_hbsc_init(struct zx_plane *zplane)
  410. {
  411. void __iomem *hbsc = zplane->hbsc;
  412. /*
  413. * Initialize HBSC block with a sane configuration per recommedation
  414. * from ZTE BSP code.
  415. */
  416. zx_writel(hbsc + HBSC_SATURATION, 0x200);
  417. zx_writel(hbsc + HBSC_HUE, 0x0);
  418. zx_writel(hbsc + HBSC_BRIGHT, 0x0);
  419. zx_writel(hbsc + HBSC_CONTRAST, 0x200);
  420. zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
  421. zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
  422. zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
  423. }
  424. int zx_plane_init(struct drm_device *drm, struct zx_plane *zplane,
  425. enum drm_plane_type type)
  426. {
  427. const struct drm_plane_helper_funcs *helper;
  428. struct drm_plane *plane = &zplane->plane;
  429. struct device *dev = zplane->dev;
  430. const uint32_t *formats;
  431. unsigned int format_count;
  432. int ret;
  433. zx_plane_hbsc_init(zplane);
  434. switch (type) {
  435. case DRM_PLANE_TYPE_PRIMARY:
  436. helper = &zx_gl_plane_helper_funcs;
  437. formats = gl_formats;
  438. format_count = ARRAY_SIZE(gl_formats);
  439. break;
  440. case DRM_PLANE_TYPE_OVERLAY:
  441. helper = &zx_vl_plane_helper_funcs;
  442. formats = vl_formats;
  443. format_count = ARRAY_SIZE(vl_formats);
  444. break;
  445. default:
  446. return -ENODEV;
  447. }
  448. ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
  449. &zx_plane_funcs, formats, format_count,
  450. type, NULL);
  451. if (ret) {
  452. DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
  453. return ret;
  454. }
  455. drm_plane_helper_add(plane, helper);
  456. return 0;
  457. }