zx_plane.c 14 KB

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