sun8i_vi_layer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
  4. */
  5. #include <drm/drm_atomic.h>
  6. #include <drm/drm_atomic_helper.h>
  7. #include <drm/drm_crtc.h>
  8. #include <drm/drm_fb_cma_helper.h>
  9. #include <drm/drm_gem_cma_helper.h>
  10. #include <drm/drm_gem_framebuffer_helper.h>
  11. #include <drm/drm_plane_helper.h>
  12. #include <drm/drm_probe_helper.h>
  13. #include "sun8i_csc.h"
  14. #include "sun8i_mixer.h"
  15. #include "sun8i_vi_layer.h"
  16. #include "sun8i_vi_scaler.h"
  17. static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
  18. int overlay, bool enable, unsigned int zpos,
  19. unsigned int old_zpos)
  20. {
  21. u32 val, bld_base, ch_base;
  22. bld_base = sun8i_blender_base(mixer);
  23. ch_base = sun8i_channel_base(mixer, channel);
  24. DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
  25. enable ? "En" : "Dis", channel, overlay);
  26. if (enable)
  27. val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
  28. else
  29. val = 0;
  30. regmap_update_bits(mixer->engine.regs,
  31. SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
  32. SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
  33. if (!enable || zpos != old_zpos) {
  34. regmap_update_bits(mixer->engine.regs,
  35. SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  36. SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
  37. 0);
  38. regmap_update_bits(mixer->engine.regs,
  39. SUN8I_MIXER_BLEND_ROUTE(bld_base),
  40. SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
  41. 0);
  42. }
  43. if (enable) {
  44. val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
  45. regmap_update_bits(mixer->engine.regs,
  46. SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  47. val, val);
  48. val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
  49. regmap_update_bits(mixer->engine.regs,
  50. SUN8I_MIXER_BLEND_ROUTE(bld_base),
  51. SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
  52. val);
  53. }
  54. }
  55. static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
  56. int overlay, struct drm_plane *plane,
  57. unsigned int zpos)
  58. {
  59. struct drm_plane_state *state = plane->state;
  60. const struct drm_format_info *format = state->fb->format;
  61. u32 src_w, src_h, dst_w, dst_h;
  62. u32 bld_base, ch_base;
  63. u32 outsize, insize;
  64. u32 hphase, vphase;
  65. u32 hn = 0, hm = 0;
  66. u32 vn = 0, vm = 0;
  67. bool subsampled;
  68. DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
  69. channel, overlay);
  70. bld_base = sun8i_blender_base(mixer);
  71. ch_base = sun8i_channel_base(mixer, channel);
  72. src_w = drm_rect_width(&state->src) >> 16;
  73. src_h = drm_rect_height(&state->src) >> 16;
  74. dst_w = drm_rect_width(&state->dst);
  75. dst_h = drm_rect_height(&state->dst);
  76. hphase = state->src.x1 & 0xffff;
  77. vphase = state->src.y1 & 0xffff;
  78. /* make coordinates dividable by subsampling factor */
  79. if (format->hsub > 1) {
  80. int mask, remainder;
  81. mask = format->hsub - 1;
  82. remainder = (state->src.x1 >> 16) & mask;
  83. src_w = (src_w + remainder) & ~mask;
  84. hphase += remainder << 16;
  85. }
  86. if (format->vsub > 1) {
  87. int mask, remainder;
  88. mask = format->vsub - 1;
  89. remainder = (state->src.y1 >> 16) & mask;
  90. src_h = (src_h + remainder) & ~mask;
  91. vphase += remainder << 16;
  92. }
  93. insize = SUN8I_MIXER_SIZE(src_w, src_h);
  94. outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
  95. /* Set height and width */
  96. DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
  97. (state->src.x1 >> 16) & ~(format->hsub - 1),
  98. (state->src.y1 >> 16) & ~(format->vsub - 1));
  99. DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
  100. regmap_write(mixer->engine.regs,
  101. SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
  102. insize);
  103. regmap_write(mixer->engine.regs,
  104. SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
  105. insize);
  106. /*
  107. * Scaler must be enabled for subsampled formats, so it scales
  108. * chroma to same size as luma.
  109. */
  110. subsampled = format->hsub > 1 || format->vsub > 1;
  111. if (insize != outsize || subsampled || hphase || vphase) {
  112. unsigned int scanline, required;
  113. struct drm_display_mode *mode;
  114. u32 hscale, vscale, fps;
  115. u64 ability;
  116. DRM_DEBUG_DRIVER("HW scaling is enabled\n");
  117. mode = &plane->state->crtc->state->mode;
  118. fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
  119. ability = clk_get_rate(mixer->mod_clk);
  120. /* BSP algorithm assumes 80% efficiency of VI scaler unit */
  121. ability *= 80;
  122. do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));
  123. required = src_h * 100 / dst_h;
  124. if (ability < required) {
  125. DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
  126. vm = src_h;
  127. vn = (u32)ability * dst_h / 100;
  128. src_h = vn;
  129. }
  130. /* it seems that every RGB scaler has buffer for 2048 pixels */
  131. scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
  132. if (src_w > scanline) {
  133. DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
  134. hm = src_w;
  135. hn = scanline;
  136. src_w = hn;
  137. }
  138. hscale = (src_w << 16) / dst_w;
  139. vscale = (src_h << 16) / dst_h;
  140. sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  141. dst_h, hscale, vscale, hphase, vphase,
  142. format);
  143. sun8i_vi_scaler_enable(mixer, channel, true);
  144. } else {
  145. DRM_DEBUG_DRIVER("HW scaling is not needed\n");
  146. sun8i_vi_scaler_enable(mixer, channel, false);
  147. }
  148. regmap_write(mixer->engine.regs,
  149. SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
  150. SUN8I_MIXER_CHAN_VI_DS_N(hn) |
  151. SUN8I_MIXER_CHAN_VI_DS_M(hm));
  152. regmap_write(mixer->engine.regs,
  153. SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
  154. SUN8I_MIXER_CHAN_VI_DS_N(hn) |
  155. SUN8I_MIXER_CHAN_VI_DS_M(hm));
  156. regmap_write(mixer->engine.regs,
  157. SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
  158. SUN8I_MIXER_CHAN_VI_DS_N(vn) |
  159. SUN8I_MIXER_CHAN_VI_DS_M(vm));
  160. regmap_write(mixer->engine.regs,
  161. SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
  162. SUN8I_MIXER_CHAN_VI_DS_N(vn) |
  163. SUN8I_MIXER_CHAN_VI_DS_M(vm));
  164. /* Set base coordinates */
  165. DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
  166. state->dst.x1, state->dst.y1);
  167. DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
  168. regmap_write(mixer->engine.regs,
  169. SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
  170. SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
  171. regmap_write(mixer->engine.regs,
  172. SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
  173. outsize);
  174. return 0;
  175. }
  176. static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
  177. {
  178. if (!format->is_yuv)
  179. return SUN8I_CSC_MODE_OFF;
  180. switch (format->format) {
  181. case DRM_FORMAT_YVU411:
  182. case DRM_FORMAT_YVU420:
  183. case DRM_FORMAT_YVU422:
  184. case DRM_FORMAT_YVU444:
  185. return SUN8I_CSC_MODE_YVU2RGB;
  186. default:
  187. return SUN8I_CSC_MODE_YUV2RGB;
  188. }
  189. }
  190. static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
  191. int overlay, struct drm_plane *plane)
  192. {
  193. struct drm_plane_state *state = plane->state;
  194. u32 val, ch_base, csc_mode, hw_fmt;
  195. const struct drm_format_info *fmt;
  196. int ret;
  197. ch_base = sun8i_channel_base(mixer, channel);
  198. fmt = state->fb->format;
  199. ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
  200. if (ret) {
  201. DRM_DEBUG_DRIVER("Invalid format\n");
  202. return ret;
  203. }
  204. val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
  205. regmap_update_bits(mixer->engine.regs,
  206. SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
  207. SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
  208. csc_mode = sun8i_vi_layer_get_csc_mode(fmt);
  209. if (csc_mode != SUN8I_CSC_MODE_OFF) {
  210. sun8i_csc_set_ccsc_coefficients(mixer, channel, csc_mode,
  211. state->color_encoding,
  212. state->color_range);
  213. sun8i_csc_enable_ccsc(mixer, channel, true);
  214. } else {
  215. sun8i_csc_enable_ccsc(mixer, channel, false);
  216. }
  217. if (!fmt->is_yuv)
  218. val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
  219. else
  220. val = 0;
  221. regmap_update_bits(mixer->engine.regs,
  222. SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
  223. SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
  224. /* It seems that YUV formats use global alpha setting. */
  225. if (mixer->cfg->is_de3)
  226. regmap_update_bits(mixer->engine.regs,
  227. SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
  228. overlay),
  229. SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
  230. SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
  231. return 0;
  232. }
  233. static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
  234. int overlay, struct drm_plane *plane)
  235. {
  236. struct drm_plane_state *state = plane->state;
  237. struct drm_framebuffer *fb = state->fb;
  238. const struct drm_format_info *format = fb->format;
  239. struct drm_gem_cma_object *gem;
  240. u32 dx, dy, src_x, src_y;
  241. dma_addr_t paddr;
  242. u32 ch_base;
  243. int i;
  244. ch_base = sun8i_channel_base(mixer, channel);
  245. /* Adjust x and y to be dividable by subsampling factor */
  246. src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
  247. src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
  248. for (i = 0; i < format->num_planes; i++) {
  249. /* Get the physical address of the buffer in memory */
  250. gem = drm_fb_cma_get_gem_obj(fb, i);
  251. DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
  252. /* Compute the start of the displayed memory */
  253. paddr = gem->paddr + fb->offsets[i];
  254. dx = src_x;
  255. dy = src_y;
  256. if (i > 0) {
  257. dx /= format->hsub;
  258. dy /= format->vsub;
  259. }
  260. /* Fixup framebuffer address for src coordinates */
  261. paddr += dx * format->cpp[i];
  262. paddr += dy * fb->pitches[i];
  263. /* Set the line width */
  264. DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
  265. i + 1, fb->pitches[i]);
  266. regmap_write(mixer->engine.regs,
  267. SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
  268. overlay, i),
  269. fb->pitches[i]);
  270. DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
  271. i + 1, &paddr);
  272. regmap_write(mixer->engine.regs,
  273. SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
  274. overlay, i),
  275. lower_32_bits(paddr));
  276. }
  277. return 0;
  278. }
  279. static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
  280. struct drm_plane_state *state)
  281. {
  282. struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
  283. struct drm_crtc *crtc = state->crtc;
  284. struct drm_crtc_state *crtc_state;
  285. int min_scale, max_scale;
  286. if (!crtc)
  287. return 0;
  288. crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
  289. if (WARN_ON(!crtc_state))
  290. return -EINVAL;
  291. min_scale = DRM_PLANE_HELPER_NO_SCALING;
  292. max_scale = DRM_PLANE_HELPER_NO_SCALING;
  293. if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
  294. min_scale = SUN8I_VI_SCALER_SCALE_MIN;
  295. max_scale = SUN8I_VI_SCALER_SCALE_MAX;
  296. }
  297. return drm_atomic_helper_check_plane_state(state, crtc_state,
  298. min_scale, max_scale,
  299. true, true);
  300. }
  301. static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
  302. struct drm_plane_state *old_state)
  303. {
  304. struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
  305. unsigned int old_zpos = old_state->normalized_zpos;
  306. struct sun8i_mixer *mixer = layer->mixer;
  307. sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
  308. old_zpos);
  309. }
  310. static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
  311. struct drm_plane_state *old_state)
  312. {
  313. struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
  314. unsigned int zpos = plane->state->normalized_zpos;
  315. unsigned int old_zpos = old_state->normalized_zpos;
  316. struct sun8i_mixer *mixer = layer->mixer;
  317. if (!plane->state->visible) {
  318. sun8i_vi_layer_enable(mixer, layer->channel,
  319. layer->overlay, false, 0, old_zpos);
  320. return;
  321. }
  322. sun8i_vi_layer_update_coord(mixer, layer->channel,
  323. layer->overlay, plane, zpos);
  324. sun8i_vi_layer_update_formats(mixer, layer->channel,
  325. layer->overlay, plane);
  326. sun8i_vi_layer_update_buffer(mixer, layer->channel,
  327. layer->overlay, plane);
  328. sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
  329. true, zpos, old_zpos);
  330. }
  331. static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
  332. .prepare_fb = drm_gem_fb_prepare_fb,
  333. .atomic_check = sun8i_vi_layer_atomic_check,
  334. .atomic_disable = sun8i_vi_layer_atomic_disable,
  335. .atomic_update = sun8i_vi_layer_atomic_update,
  336. };
  337. static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
  338. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  339. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  340. .destroy = drm_plane_cleanup,
  341. .disable_plane = drm_atomic_helper_disable_plane,
  342. .reset = drm_atomic_helper_plane_reset,
  343. .update_plane = drm_atomic_helper_update_plane,
  344. };
  345. /*
  346. * While DE2 VI layer supports same RGB formats as UI layer, alpha
  347. * channel is ignored. This structure lists all unique variants
  348. * where alpha channel is replaced with "don't care" (X) channel.
  349. */
  350. static const u32 sun8i_vi_layer_formats[] = {
  351. DRM_FORMAT_BGR565,
  352. DRM_FORMAT_BGR888,
  353. DRM_FORMAT_BGRX4444,
  354. DRM_FORMAT_BGRX5551,
  355. DRM_FORMAT_BGRX8888,
  356. DRM_FORMAT_RGB565,
  357. DRM_FORMAT_RGB888,
  358. DRM_FORMAT_RGBX4444,
  359. DRM_FORMAT_RGBX5551,
  360. DRM_FORMAT_RGBX8888,
  361. DRM_FORMAT_XBGR1555,
  362. DRM_FORMAT_XBGR4444,
  363. DRM_FORMAT_XBGR8888,
  364. DRM_FORMAT_XRGB1555,
  365. DRM_FORMAT_XRGB4444,
  366. DRM_FORMAT_XRGB8888,
  367. DRM_FORMAT_NV16,
  368. DRM_FORMAT_NV12,
  369. DRM_FORMAT_NV21,
  370. DRM_FORMAT_NV61,
  371. DRM_FORMAT_UYVY,
  372. DRM_FORMAT_VYUY,
  373. DRM_FORMAT_YUYV,
  374. DRM_FORMAT_YVYU,
  375. DRM_FORMAT_YUV411,
  376. DRM_FORMAT_YUV420,
  377. DRM_FORMAT_YUV422,
  378. DRM_FORMAT_YVU411,
  379. DRM_FORMAT_YVU420,
  380. DRM_FORMAT_YVU422,
  381. };
  382. static const u32 sun8i_vi_layer_de3_formats[] = {
  383. DRM_FORMAT_ABGR1555,
  384. DRM_FORMAT_ABGR2101010,
  385. DRM_FORMAT_ABGR4444,
  386. DRM_FORMAT_ABGR8888,
  387. DRM_FORMAT_ARGB1555,
  388. DRM_FORMAT_ARGB2101010,
  389. DRM_FORMAT_ARGB4444,
  390. DRM_FORMAT_ARGB8888,
  391. DRM_FORMAT_BGR565,
  392. DRM_FORMAT_BGR888,
  393. DRM_FORMAT_BGRA1010102,
  394. DRM_FORMAT_BGRA5551,
  395. DRM_FORMAT_BGRA4444,
  396. DRM_FORMAT_BGRA8888,
  397. DRM_FORMAT_BGRX8888,
  398. DRM_FORMAT_RGB565,
  399. DRM_FORMAT_RGB888,
  400. DRM_FORMAT_RGBA1010102,
  401. DRM_FORMAT_RGBA4444,
  402. DRM_FORMAT_RGBA5551,
  403. DRM_FORMAT_RGBA8888,
  404. DRM_FORMAT_RGBX8888,
  405. DRM_FORMAT_XBGR8888,
  406. DRM_FORMAT_XRGB8888,
  407. DRM_FORMAT_NV16,
  408. DRM_FORMAT_NV12,
  409. DRM_FORMAT_NV21,
  410. DRM_FORMAT_NV61,
  411. DRM_FORMAT_P010,
  412. DRM_FORMAT_P210,
  413. DRM_FORMAT_UYVY,
  414. DRM_FORMAT_VYUY,
  415. DRM_FORMAT_YUYV,
  416. DRM_FORMAT_YVYU,
  417. DRM_FORMAT_YUV411,
  418. DRM_FORMAT_YUV420,
  419. DRM_FORMAT_YUV422,
  420. DRM_FORMAT_YVU411,
  421. DRM_FORMAT_YVU420,
  422. DRM_FORMAT_YVU422,
  423. };
  424. struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
  425. struct sun8i_mixer *mixer,
  426. int index)
  427. {
  428. u32 supported_encodings, supported_ranges;
  429. unsigned int plane_cnt, format_count;
  430. struct sun8i_vi_layer *layer;
  431. const u32 *formats;
  432. int ret;
  433. layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
  434. if (!layer)
  435. return ERR_PTR(-ENOMEM);
  436. if (mixer->cfg->is_de3) {
  437. formats = sun8i_vi_layer_de3_formats;
  438. format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
  439. } else {
  440. formats = sun8i_vi_layer_formats;
  441. format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
  442. }
  443. /* possible crtcs are set later */
  444. ret = drm_universal_plane_init(drm, &layer->plane, 0,
  445. &sun8i_vi_layer_funcs,
  446. formats, format_count,
  447. NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
  448. if (ret) {
  449. dev_err(drm->dev, "Couldn't initialize layer\n");
  450. return ERR_PTR(ret);
  451. }
  452. plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
  453. ret = drm_plane_create_zpos_property(&layer->plane, index,
  454. 0, plane_cnt - 1);
  455. if (ret) {
  456. dev_err(drm->dev, "Couldn't add zpos property\n");
  457. return ERR_PTR(ret);
  458. }
  459. supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
  460. BIT(DRM_COLOR_YCBCR_BT709);
  461. supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
  462. BIT(DRM_COLOR_YCBCR_FULL_RANGE);
  463. ret = drm_plane_create_color_properties(&layer->plane,
  464. supported_encodings,
  465. supported_ranges,
  466. DRM_COLOR_YCBCR_BT709,
  467. DRM_COLOR_YCBCR_LIMITED_RANGE);
  468. if (ret) {
  469. dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
  470. return ERR_PTR(ret);
  471. }
  472. drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
  473. layer->mixer = mixer;
  474. layer->channel = index;
  475. layer->overlay = 0;
  476. return layer;
  477. }