1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 28bb0daffSRob Clark /* 31b409fdaSAlexander A. Klimov * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ 48bb0daffSRob Clark * Author: Rob Clark <rob.clark@linaro.org> 58bb0daffSRob Clark */ 68bb0daffSRob Clark 7c423bc85STomi Valkeinen #include <drm/drm_atomic.h> 869a12263SLaurent Pinchart #include <drm/drm_atomic_helper.h> 9942d8344SDaniel Vetter #include <drm/drm_gem_atomic_helper.h> 10de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h> 112e54ff0eSBenoit Parrot #include <drm/drm_fourcc.h> 12*720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h> 1369a12263SLaurent Pinchart 148bb0daffSRob Clark #include "omap_dmm_tiler.h" 152d278f54SLaurent Pinchart #include "omap_drv.h" 168bb0daffSRob Clark 178bb0daffSRob Clark /* 188bb0daffSRob Clark * plane funcs 198bb0daffSRob Clark */ 208bb0daffSRob Clark 213c265d92SBenoit Parrot #define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base) 223c265d92SBenoit Parrot 233c265d92SBenoit Parrot struct omap_plane_state { 243c265d92SBenoit Parrot /* Must be first. */ 253c265d92SBenoit Parrot struct drm_plane_state base; 262e54ff0eSBenoit Parrot 272e54ff0eSBenoit Parrot struct omap_hw_overlay *overlay; 28e02b5cc9SBenoit Parrot struct omap_hw_overlay *r_overlay; /* right overlay */ 293c265d92SBenoit Parrot }; 303c265d92SBenoit Parrot 318bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base) 328bb0daffSRob Clark 338bb0daffSRob Clark struct omap_plane { 348bb0daffSRob Clark struct drm_plane base; 35694c99cfSJyri Sarha enum omap_plane_id id; 368bb0daffSRob Clark }; 378bb0daffSRob Clark 38e02b5cc9SBenoit Parrot bool is_omap_plane_dual_overlay(struct drm_plane_state *state) 39e02b5cc9SBenoit Parrot { 40e02b5cc9SBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(state); 41e02b5cc9SBenoit Parrot 42e02b5cc9SBenoit Parrot return !!omap_state->r_overlay; 43e02b5cc9SBenoit Parrot } 44e02b5cc9SBenoit Parrot 4511ffd031STomi Valkeinen static int omap_plane_prepare_fb(struct drm_plane *plane, 461832040dSChris Wilson struct drm_plane_state *new_state) 4711ffd031STomi Valkeinen { 48844f9111SMaarten Lankhorst if (!new_state->fb) 49844f9111SMaarten Lankhorst return 0; 50844f9111SMaarten Lankhorst 51942d8344SDaniel Vetter drm_gem_plane_helper_prepare_fb(plane, new_state); 52942d8344SDaniel Vetter 53844f9111SMaarten Lankhorst return omap_framebuffer_pin(new_state->fb); 5411ffd031STomi Valkeinen } 5511ffd031STomi Valkeinen 5611ffd031STomi Valkeinen static void omap_plane_cleanup_fb(struct drm_plane *plane, 571832040dSChris Wilson struct drm_plane_state *old_state) 5811ffd031STomi Valkeinen { 59844f9111SMaarten Lankhorst if (old_state->fb) 60844f9111SMaarten Lankhorst omap_framebuffer_unpin(old_state->fb); 6111ffd031STomi Valkeinen } 6211ffd031STomi Valkeinen 6311ffd031STomi Valkeinen static void omap_plane_atomic_update(struct drm_plane *plane, 64977697e2SMaxime Ripard struct drm_atomic_state *state) 65afc34932SLaurent Pinchart { 669f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 6737418bf1SMaxime Ripard struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 6837418bf1SMaxime Ripard plane); 692e54ff0eSBenoit Parrot struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 702e54ff0eSBenoit Parrot plane); 712e54ff0eSBenoit Parrot struct omap_plane_state *new_omap_state; 722e54ff0eSBenoit Parrot struct omap_plane_state *old_omap_state; 73e02b5cc9SBenoit Parrot struct omap_overlay_info info, r_info; 74e02b5cc9SBenoit Parrot enum omap_plane_id ovl_id, r_ovl_id; 758bb0daffSRob Clark int ret; 76e02b5cc9SBenoit Parrot bool dual_ovl; 778bb0daffSRob Clark 782e54ff0eSBenoit Parrot new_omap_state = to_omap_plane_state(new_state); 792e54ff0eSBenoit Parrot old_omap_state = to_omap_plane_state(old_state); 802e54ff0eSBenoit Parrot 81e02b5cc9SBenoit Parrot dual_ovl = is_omap_plane_dual_overlay(new_state); 82e02b5cc9SBenoit Parrot 832e54ff0eSBenoit Parrot /* Cleanup previously held overlay if needed */ 842e54ff0eSBenoit Parrot if (old_omap_state->overlay) 852e54ff0eSBenoit Parrot omap_overlay_update_state(priv, old_omap_state->overlay); 86e02b5cc9SBenoit Parrot if (old_omap_state->r_overlay) 87e02b5cc9SBenoit Parrot omap_overlay_update_state(priv, old_omap_state->r_overlay); 882e54ff0eSBenoit Parrot 892e54ff0eSBenoit Parrot if (!new_omap_state->overlay) { 902e54ff0eSBenoit Parrot DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name); 912e54ff0eSBenoit Parrot return; 922e54ff0eSBenoit Parrot } 932e54ff0eSBenoit Parrot 942e54ff0eSBenoit Parrot ovl_id = new_omap_state->overlay->id; 95c8fa1e73SBenoit Parrot DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc, 9641016fe1SMaxime Ripard new_state->fb); 978bb0daffSRob Clark 98fb730c9bSLaurent Pinchart memset(&info, 0, sizeof(info)); 99517a8a95STomi Valkeinen info.rotation_type = OMAP_DSS_ROT_NONE; 1000bd97c42STomi Valkeinen info.rotation = DRM_MODE_ROTATE_0; 10141016fe1SMaxime Ripard info.global_alpha = new_state->alpha >> 8; 10241016fe1SMaxime Ripard info.zorder = new_state->normalized_zpos; 10341016fe1SMaxime Ripard if (new_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 1043037e0c5SJean-Jacques Hiblot info.pre_mult_alpha = 1; 1053037e0c5SJean-Jacques Hiblot else 1063037e0c5SJean-Jacques Hiblot info.pre_mult_alpha = 0; 10741016fe1SMaxime Ripard info.color_encoding = new_state->color_encoding; 10841016fe1SMaxime Ripard info.color_range = new_state->color_range; 109fb730c9bSLaurent Pinchart 110e02b5cc9SBenoit Parrot r_info = info; 111e02b5cc9SBenoit Parrot 1128bb0daffSRob Clark /* update scanout: */ 113e02b5cc9SBenoit Parrot omap_framebuffer_update_scanout(new_state->fb, new_state, &info, 114e02b5cc9SBenoit Parrot dual_ovl ? &r_info : NULL); 1158bb0daffSRob Clark 1162e54ff0eSBenoit Parrot DBG("%s: %dx%d -> %dx%d (%d)", 1172e54ff0eSBenoit Parrot new_omap_state->overlay->name, info.width, info.height, 1182e54ff0eSBenoit Parrot info.out_width, info.out_height, info.screen_width); 119fb730c9bSLaurent Pinchart DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 120fb730c9bSLaurent Pinchart &info.paddr, &info.p_uv_addr); 1218bb0daffSRob Clark 122e02b5cc9SBenoit Parrot if (dual_ovl) { 123e02b5cc9SBenoit Parrot r_ovl_id = new_omap_state->r_overlay->id; 124e02b5cc9SBenoit Parrot /* 125e02b5cc9SBenoit Parrot * If the current plane uses 2 hw planes the very next 126e02b5cc9SBenoit Parrot * zorder is used by the r_overlay so we just use the 127e02b5cc9SBenoit Parrot * main overlay zorder + 1 128e02b5cc9SBenoit Parrot */ 129e02b5cc9SBenoit Parrot r_info.zorder = info.zorder + 1; 130e02b5cc9SBenoit Parrot 131e02b5cc9SBenoit Parrot DBG("%s: %dx%d -> %dx%d (%d)", 132e02b5cc9SBenoit Parrot new_omap_state->r_overlay->name, 133e02b5cc9SBenoit Parrot r_info.width, r_info.height, 134e02b5cc9SBenoit Parrot r_info.out_width, r_info.out_height, r_info.screen_width); 135e02b5cc9SBenoit Parrot DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y, 136e02b5cc9SBenoit Parrot &r_info.paddr, &r_info.p_uv_addr); 137e02b5cc9SBenoit Parrot } 138e02b5cc9SBenoit Parrot 1398bb0daffSRob Clark /* and finally, update omapdss: */ 140c8fa1e73SBenoit Parrot ret = dispc_ovl_setup(priv->dispc, ovl_id, &info, 14141016fe1SMaxime Ripard omap_crtc_timings(new_state->crtc), false, 14241016fe1SMaxime Ripard omap_crtc_channel(new_state->crtc)); 143cfb73f20STomi Valkeinen if (ret) { 144cfb73f20STomi Valkeinen dev_err(plane->dev->dev, "Failed to setup plane %s\n", 145c8fa1e73SBenoit Parrot plane->name); 146c8fa1e73SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, false); 147d9157dfdSTomi Valkeinen return; 148794a65ffSTomi Valkeinen } 1498bb0daffSRob Clark 150c8fa1e73SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, true); 151e02b5cc9SBenoit Parrot 152e02b5cc9SBenoit Parrot if (dual_ovl) { 153e02b5cc9SBenoit Parrot ret = dispc_ovl_setup(priv->dispc, r_ovl_id, &r_info, 154e02b5cc9SBenoit Parrot omap_crtc_timings(new_state->crtc), false, 155e02b5cc9SBenoit Parrot omap_crtc_channel(new_state->crtc)); 156e02b5cc9SBenoit Parrot if (ret) { 157e02b5cc9SBenoit Parrot dev_err(plane->dev->dev, "Failed to setup plane right-overlay %s\n", 158e02b5cc9SBenoit Parrot plane->name); 159e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, r_ovl_id, false); 160e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, false); 161e02b5cc9SBenoit Parrot return; 162e02b5cc9SBenoit Parrot } 163e02b5cc9SBenoit Parrot 164e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, r_ovl_id, true); 165e02b5cc9SBenoit Parrot } 166de8e4100SLaurent Pinchart } 167de8e4100SLaurent Pinchart 168de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane, 169977697e2SMaxime Ripard struct drm_atomic_state *state) 1708bb0daffSRob Clark { 1719f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 1728bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 1732e54ff0eSBenoit Parrot struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 1742e54ff0eSBenoit Parrot plane); 1752e54ff0eSBenoit Parrot struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 1762e54ff0eSBenoit Parrot plane); 1772e54ff0eSBenoit Parrot struct omap_plane_state *new_omap_state; 1782e54ff0eSBenoit Parrot struct omap_plane_state *old_omap_state; 1792e54ff0eSBenoit Parrot 1802e54ff0eSBenoit Parrot new_omap_state = to_omap_plane_state(new_state); 1812e54ff0eSBenoit Parrot old_omap_state = to_omap_plane_state(old_state); 1822e54ff0eSBenoit Parrot 1832e54ff0eSBenoit Parrot if (!old_omap_state->overlay) 1842e54ff0eSBenoit Parrot return; 1852debab97SLaurent Pinchart 186e05162c0SMaxime Ripard new_state->rotation = DRM_MODE_ROTATE_0; 187e05162c0SMaxime Ripard new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id; 18882e58855SLaurent Pinchart 1892e54ff0eSBenoit Parrot omap_overlay_update_state(priv, old_omap_state->overlay); 1902e54ff0eSBenoit Parrot new_omap_state->overlay = NULL; 191e02b5cc9SBenoit Parrot 192e02b5cc9SBenoit Parrot if (is_omap_plane_dual_overlay(old_state)) { 193e02b5cc9SBenoit Parrot omap_overlay_update_state(priv, old_omap_state->r_overlay); 194e02b5cc9SBenoit Parrot new_omap_state->r_overlay = NULL; 195e02b5cc9SBenoit Parrot } 1968bb0daffSRob Clark } 1978bb0daffSRob Clark 198c21134b0SNeil Armstrong #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 199c21134b0SNeil Armstrong 200c423bc85STomi Valkeinen static int omap_plane_atomic_check(struct drm_plane *plane, 2017c11b99aSMaxime Ripard struct drm_atomic_state *state) 202c423bc85STomi Valkeinen { 2037c11b99aSMaxime Ripard struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 2047c11b99aSMaxime Ripard plane); 2052e54ff0eSBenoit Parrot struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, 2062e54ff0eSBenoit Parrot plane); 207d484c20dSBenoit Parrot struct omap_drm_private *priv = plane->dev->dev_private; 2082e54ff0eSBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state); 2092e54ff0eSBenoit Parrot struct omap_global_state *omap_overlay_global_state; 210c423bc85STomi Valkeinen struct drm_crtc_state *crtc_state; 211e02b5cc9SBenoit Parrot bool new_r_hw_overlay = false; 2122e54ff0eSBenoit Parrot bool new_hw_overlay = false; 213d484c20dSBenoit Parrot u32 max_width, max_height; 2142e54ff0eSBenoit Parrot struct drm_crtc *crtc; 215d484c20dSBenoit Parrot u16 width, height; 2162e54ff0eSBenoit Parrot u32 caps = 0; 2172e54ff0eSBenoit Parrot u32 fourcc; 218c21134b0SNeil Armstrong int ret; 219c423bc85STomi Valkeinen 2202e54ff0eSBenoit Parrot omap_overlay_global_state = omap_get_global_state(state); 2212e54ff0eSBenoit Parrot if (IS_ERR(omap_overlay_global_state)) 2222e54ff0eSBenoit Parrot return PTR_ERR(omap_overlay_global_state); 223c423bc85STomi Valkeinen 224d484c20dSBenoit Parrot dispc_ovl_get_max_size(priv->dispc, &width, &height); 225d484c20dSBenoit Parrot max_width = width << 16; 226d484c20dSBenoit Parrot max_height = height << 16; 227d484c20dSBenoit Parrot 2282e54ff0eSBenoit Parrot crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc; 2292e54ff0eSBenoit Parrot if (!crtc) 23070dd2a62STomi Valkeinen return 0; 23170dd2a62STomi Valkeinen 2322e54ff0eSBenoit Parrot crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); 23370dd2a62STomi Valkeinen /* we should have a crtc state if the plane is attached to a crtc */ 23470dd2a62STomi Valkeinen if (WARN_ON(!crtc_state)) 23570dd2a62STomi Valkeinen return 0; 236c423bc85STomi Valkeinen 237c21134b0SNeil Armstrong /* 238c21134b0SNeil Armstrong * Note: these are just sanity checks to filter out totally bad scaling 239c21134b0SNeil Armstrong * factors. The real limits must be calculated case by case, and 240c21134b0SNeil Armstrong * unfortunately we currently do those checks only at the commit 241c21134b0SNeil Armstrong * phase in dispc. 242c21134b0SNeil Armstrong */ 243c21134b0SNeil Armstrong ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 244c21134b0SNeil Armstrong FRAC_16_16(1, 8), FRAC_16_16(8, 1), 245c21134b0SNeil Armstrong true, true); 246c21134b0SNeil Armstrong if (ret) 247c21134b0SNeil Armstrong return ret; 248c21134b0SNeil Armstrong 2492e54ff0eSBenoit Parrot DBG("%s: visible %d -> %d", plane->name, 2502e54ff0eSBenoit Parrot old_plane_state->visible, new_plane_state->visible); 2512e54ff0eSBenoit Parrot 2522e54ff0eSBenoit Parrot if (!new_plane_state->visible) { 2532e54ff0eSBenoit Parrot omap_overlay_release(state, omap_state->overlay); 254e02b5cc9SBenoit Parrot omap_overlay_release(state, omap_state->r_overlay); 2552e54ff0eSBenoit Parrot omap_state->overlay = NULL; 256e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 2572e54ff0eSBenoit Parrot return 0; 2582e54ff0eSBenoit Parrot } 2592e54ff0eSBenoit Parrot 260ba5c1649SMaxime Ripard if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0) 261c423bc85STomi Valkeinen return -EINVAL; 262c423bc85STomi Valkeinen 263ba5c1649SMaxime Ripard if (new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->adjusted_mode.hdisplay) 264c423bc85STomi Valkeinen return -EINVAL; 265c423bc85STomi Valkeinen 266ba5c1649SMaxime Ripard if (new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->adjusted_mode.vdisplay) 267c423bc85STomi Valkeinen return -EINVAL; 268c423bc85STomi Valkeinen 269d484c20dSBenoit Parrot /* Make sure dimensions are within bounds. */ 270d484c20dSBenoit Parrot if (new_plane_state->src_h > max_height || new_plane_state->crtc_h > height) 271d484c20dSBenoit Parrot return -EINVAL; 272d484c20dSBenoit Parrot 273e02b5cc9SBenoit Parrot 274e02b5cc9SBenoit Parrot if (new_plane_state->src_w > max_width || new_plane_state->crtc_w > width) { 275e02b5cc9SBenoit Parrot bool is_fourcc_yuv = new_plane_state->fb->format->is_yuv; 276e02b5cc9SBenoit Parrot 277e02b5cc9SBenoit Parrot if (is_fourcc_yuv && (((new_plane_state->src_w >> 16) / 2 & 1) || 278e02b5cc9SBenoit Parrot new_plane_state->crtc_w / 2 & 1)) { 279e02b5cc9SBenoit Parrot /* 280e02b5cc9SBenoit Parrot * When calculating the split overlay width 281e02b5cc9SBenoit Parrot * and it yield an odd value we will need to adjust 282e02b5cc9SBenoit Parrot * the indivual width +/- 1. So make sure it fits 283e02b5cc9SBenoit Parrot */ 284e02b5cc9SBenoit Parrot if (new_plane_state->src_w <= ((2 * width - 1) << 16) && 285e02b5cc9SBenoit Parrot new_plane_state->crtc_w <= (2 * width - 1)) 286e02b5cc9SBenoit Parrot new_r_hw_overlay = true; 287e02b5cc9SBenoit Parrot else 288d484c20dSBenoit Parrot return -EINVAL; 289e02b5cc9SBenoit Parrot } else { 290e02b5cc9SBenoit Parrot if (new_plane_state->src_w <= (2 * max_width) && 291e02b5cc9SBenoit Parrot new_plane_state->crtc_w <= (2 * width)) 292e02b5cc9SBenoit Parrot new_r_hw_overlay = true; 293e02b5cc9SBenoit Parrot else 294e02b5cc9SBenoit Parrot return -EINVAL; 295e02b5cc9SBenoit Parrot } 296e02b5cc9SBenoit Parrot } 297d484c20dSBenoit Parrot 298ba5c1649SMaxime Ripard if (new_plane_state->rotation != DRM_MODE_ROTATE_0 && 299ba5c1649SMaxime Ripard !omap_framebuffer_supports_rotation(new_plane_state->fb)) 300bfeece55STomi Valkeinen return -EINVAL; 301bfeece55STomi Valkeinen 3022e54ff0eSBenoit Parrot if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w || 3032e54ff0eSBenoit Parrot (new_plane_state->src_h >> 16) != new_plane_state->crtc_h) 3042e54ff0eSBenoit Parrot caps |= OMAP_DSS_OVL_CAP_SCALE; 3052e54ff0eSBenoit Parrot 3062e54ff0eSBenoit Parrot fourcc = new_plane_state->fb->format->format; 3072e54ff0eSBenoit Parrot 3082e54ff0eSBenoit Parrot /* 3092e54ff0eSBenoit Parrot * (re)allocate hw overlay if we don't have one or 3102e54ff0eSBenoit Parrot * there is a caps mismatch 3112e54ff0eSBenoit Parrot */ 3122e54ff0eSBenoit Parrot if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) { 3132e54ff0eSBenoit Parrot new_hw_overlay = true; 3142e54ff0eSBenoit Parrot } else { 3152e54ff0eSBenoit Parrot /* check supported format */ 3162e54ff0eSBenoit Parrot if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id, 3172e54ff0eSBenoit Parrot fourcc)) 3182e54ff0eSBenoit Parrot new_hw_overlay = true; 3192e54ff0eSBenoit Parrot } 3202e54ff0eSBenoit Parrot 321e02b5cc9SBenoit Parrot /* 322e02b5cc9SBenoit Parrot * check if we need two overlays and only have 1 or 323e02b5cc9SBenoit Parrot * if we had 2 overlays but will only need 1 324e02b5cc9SBenoit Parrot */ 325e02b5cc9SBenoit Parrot if ((new_r_hw_overlay && !omap_state->r_overlay) || 326e02b5cc9SBenoit Parrot (!new_r_hw_overlay && omap_state->r_overlay)) 327e02b5cc9SBenoit Parrot new_hw_overlay = true; 328e02b5cc9SBenoit Parrot 3292e54ff0eSBenoit Parrot if (new_hw_overlay) { 3302e54ff0eSBenoit Parrot struct omap_hw_overlay *old_ovl = omap_state->overlay; 331e02b5cc9SBenoit Parrot struct omap_hw_overlay *old_r_ovl = omap_state->r_overlay; 3322e54ff0eSBenoit Parrot struct omap_hw_overlay *new_ovl = NULL; 333e02b5cc9SBenoit Parrot struct omap_hw_overlay *new_r_ovl = NULL; 3342e54ff0eSBenoit Parrot 3352e54ff0eSBenoit Parrot omap_overlay_release(state, old_ovl); 336e02b5cc9SBenoit Parrot omap_overlay_release(state, old_r_ovl); 3372e54ff0eSBenoit Parrot 338e02b5cc9SBenoit Parrot ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl, 339e02b5cc9SBenoit Parrot new_r_hw_overlay ? &new_r_ovl : NULL); 3402e54ff0eSBenoit Parrot if (ret) { 3412e54ff0eSBenoit Parrot DBG("%s: failed to assign hw_overlay", plane->name); 3422e54ff0eSBenoit Parrot omap_state->overlay = NULL; 343e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 3442e54ff0eSBenoit Parrot return ret; 3452e54ff0eSBenoit Parrot } 3462e54ff0eSBenoit Parrot 3472e54ff0eSBenoit Parrot omap_state->overlay = new_ovl; 348e02b5cc9SBenoit Parrot if (new_r_hw_overlay) 349e02b5cc9SBenoit Parrot omap_state->r_overlay = new_r_ovl; 350e02b5cc9SBenoit Parrot else 351e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 3522e54ff0eSBenoit Parrot } 3532e54ff0eSBenoit Parrot 3542e54ff0eSBenoit Parrot DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id); 3552e54ff0eSBenoit Parrot 356e02b5cc9SBenoit Parrot if (omap_state->r_overlay) 357e02b5cc9SBenoit Parrot DBG("plane: %s r_overlay_id: %d", plane->name, omap_state->r_overlay->id); 358e02b5cc9SBenoit Parrot 359c423bc85STomi Valkeinen return 0; 360c423bc85STomi Valkeinen } 361c423bc85STomi Valkeinen 362de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 363de8e4100SLaurent Pinchart .prepare_fb = omap_plane_prepare_fb, 364de8e4100SLaurent Pinchart .cleanup_fb = omap_plane_cleanup_fb, 365c423bc85STomi Valkeinen .atomic_check = omap_plane_atomic_check, 366de8e4100SLaurent Pinchart .atomic_update = omap_plane_atomic_update, 367de8e4100SLaurent Pinchart .atomic_disable = omap_plane_atomic_disable, 368de8e4100SLaurent Pinchart }; 369de8e4100SLaurent Pinchart 3708bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane) 3718bb0daffSRob Clark { 3728bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 3738bb0daffSRob Clark 374c8fa1e73SBenoit Parrot DBG("%s", plane->name); 3758bb0daffSRob Clark 3768bb0daffSRob Clark drm_plane_cleanup(plane); 3778bb0daffSRob Clark 3788bb0daffSRob Clark kfree(omap_plane); 3798bb0daffSRob Clark } 3808bb0daffSRob Clark 3818bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */ 3828bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane, 3838bb0daffSRob Clark struct drm_mode_object *obj) 3848bb0daffSRob Clark { 3858bb0daffSRob Clark struct drm_device *dev = plane->dev; 3868bb0daffSRob Clark struct omap_drm_private *priv = dev->dev_private; 3878bb0daffSRob Clark 3888bb0daffSRob Clark if (priv->has_dmm) { 3890da88db1SVille Syrjälä if (!plane->rotation_property) 3900da88db1SVille Syrjälä drm_plane_create_rotation_property(plane, 391c2c446adSRobert Foss DRM_MODE_ROTATE_0, 392c2c446adSRobert Foss DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | 393c2c446adSRobert Foss DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | 394c2c446adSRobert Foss DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); 395e2cd09b2SLaurent Pinchart 3960da88db1SVille Syrjälä /* Attach the rotation property also to the crtc object */ 3970da88db1SVille Syrjälä if (plane->rotation_property && obj != &plane->base) 3980da88db1SVille Syrjälä drm_object_attach_property(obj, plane->rotation_property, 399c2c446adSRobert Foss DRM_MODE_ROTATE_0); 4008bb0daffSRob Clark } 4018bb0daffSRob Clark 402e2cd09b2SLaurent Pinchart drm_object_attach_property(obj, priv->zorder_prop, 0); 4038bb0daffSRob Clark } 4048bb0daffSRob Clark 405e07323cfSTomi Valkeinen static void omap_plane_reset(struct drm_plane *plane) 406e07323cfSTomi Valkeinen { 4073c265d92SBenoit Parrot struct omap_plane_state *omap_state; 408e07323cfSTomi Valkeinen 4093c265d92SBenoit Parrot if (plane->state) 4103c265d92SBenoit Parrot drm_atomic_helper_plane_destroy_state(plane, plane->state); 4113c265d92SBenoit Parrot 4123c265d92SBenoit Parrot omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL); 4133c265d92SBenoit Parrot if (!omap_state) 414e07323cfSTomi Valkeinen return; 415e07323cfSTomi Valkeinen 4163c265d92SBenoit Parrot __drm_atomic_helper_plane_reset(plane, &omap_state->base); 417e07323cfSTomi Valkeinen } 418e07323cfSTomi Valkeinen 4193c265d92SBenoit Parrot static struct drm_plane_state * 4203c265d92SBenoit Parrot omap_plane_atomic_duplicate_state(struct drm_plane *plane) 4213c265d92SBenoit Parrot { 4222e54ff0eSBenoit Parrot struct omap_plane_state *state, *current_state; 4233c265d92SBenoit Parrot 4243c265d92SBenoit Parrot if (WARN_ON(!plane->state)) 4253c265d92SBenoit Parrot return NULL; 4263c265d92SBenoit Parrot 4272e54ff0eSBenoit Parrot current_state = to_omap_plane_state(plane->state); 4282e54ff0eSBenoit Parrot 4293c265d92SBenoit Parrot state = kmalloc(sizeof(*state), GFP_KERNEL); 4303c265d92SBenoit Parrot if (!state) 4313c265d92SBenoit Parrot return NULL; 4323c265d92SBenoit Parrot 4333c265d92SBenoit Parrot __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 4343c265d92SBenoit Parrot 4352e54ff0eSBenoit Parrot state->overlay = current_state->overlay; 436e02b5cc9SBenoit Parrot state->r_overlay = current_state->r_overlay; 4372e54ff0eSBenoit Parrot 4383c265d92SBenoit Parrot return &state->base; 4393c265d92SBenoit Parrot } 4403c265d92SBenoit Parrot 44119e2d266SBenoit Parrot static void omap_plane_atomic_print_state(struct drm_printer *p, 44219e2d266SBenoit Parrot const struct drm_plane_state *state) 44319e2d266SBenoit Parrot { 44419e2d266SBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(state); 44519e2d266SBenoit Parrot 44619e2d266SBenoit Parrot if (omap_state->overlay) 44719e2d266SBenoit Parrot drm_printf(p, "\toverlay=%s (caps=0x%x)\n", 44819e2d266SBenoit Parrot omap_state->overlay->name, 44919e2d266SBenoit Parrot omap_state->overlay->caps); 45019e2d266SBenoit Parrot else 45119e2d266SBenoit Parrot drm_printf(p, "\toverlay=None\n"); 452e02b5cc9SBenoit Parrot if (omap_state->r_overlay) 453e02b5cc9SBenoit Parrot drm_printf(p, "\tr_overlay=%s (caps=0x%x)\n", 454e02b5cc9SBenoit Parrot omap_state->r_overlay->name, 455e02b5cc9SBenoit Parrot omap_state->r_overlay->caps); 456e02b5cc9SBenoit Parrot else 457e02b5cc9SBenoit Parrot drm_printf(p, "\tr_overlay=None\n"); 45819e2d266SBenoit Parrot } 45919e2d266SBenoit Parrot 460afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane, 461afc34932SLaurent Pinchart struct drm_plane_state *state, 462afc34932SLaurent Pinchart struct drm_property *property, 463dfe9cfccSLaurent Pinchart u64 val) 464afc34932SLaurent Pinchart { 465afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 466afc34932SLaurent Pinchart 467afc34932SLaurent Pinchart if (property == priv->zorder_prop) 468ba527c13SLaurent Pinchart state->zpos = val; 469afc34932SLaurent Pinchart else 470afc34932SLaurent Pinchart return -EINVAL; 471afc34932SLaurent Pinchart 472a42133a7SLaurent Pinchart return 0; 473afc34932SLaurent Pinchart } 474a42133a7SLaurent Pinchart 475afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane, 476afc34932SLaurent Pinchart const struct drm_plane_state *state, 477afc34932SLaurent Pinchart struct drm_property *property, 478dfe9cfccSLaurent Pinchart u64 *val) 479afc34932SLaurent Pinchart { 480afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 481a42133a7SLaurent Pinchart 482afc34932SLaurent Pinchart if (property == priv->zorder_prop) 483ba527c13SLaurent Pinchart *val = state->zpos; 484afc34932SLaurent Pinchart else 485afc34932SLaurent Pinchart return -EINVAL; 486afc34932SLaurent Pinchart 487afc34932SLaurent Pinchart return 0; 4888bb0daffSRob Clark } 4898bb0daffSRob Clark 4908bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = { 491cef77d40SLaurent Pinchart .update_plane = drm_atomic_helper_update_plane, 492cef77d40SLaurent Pinchart .disable_plane = drm_atomic_helper_disable_plane, 493afc34932SLaurent Pinchart .reset = omap_plane_reset, 4948bb0daffSRob Clark .destroy = omap_plane_destroy, 4953c265d92SBenoit Parrot .atomic_duplicate_state = omap_plane_atomic_duplicate_state, 496d980278bSLaurent Pinchart .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 497afc34932SLaurent Pinchart .atomic_set_property = omap_plane_atomic_set_property, 498afc34932SLaurent Pinchart .atomic_get_property = omap_plane_atomic_get_property, 49919e2d266SBenoit Parrot .atomic_print_state = omap_plane_atomic_print_state, 5008bb0daffSRob Clark }; 5018bb0daffSRob Clark 50264ff1891SJyri Sarha static bool omap_plane_supports_yuv(struct drm_plane *plane) 50364ff1891SJyri Sarha { 50464ff1891SJyri Sarha struct omap_drm_private *priv = plane->dev->dev_private; 50564ff1891SJyri Sarha struct omap_plane *omap_plane = to_omap_plane(plane); 506dac62bcaSTomi Valkeinen const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id); 50764ff1891SJyri Sarha u32 i; 50864ff1891SJyri Sarha 50964ff1891SJyri Sarha for (i = 0; formats[i]; i++) 51064ff1891SJyri Sarha if (formats[i] == DRM_FORMAT_YUYV || 51164ff1891SJyri Sarha formats[i] == DRM_FORMAT_UYVY || 51264ff1891SJyri Sarha formats[i] == DRM_FORMAT_NV12) 51364ff1891SJyri Sarha return true; 51464ff1891SJyri Sarha 51564ff1891SJyri Sarha return false; 51664ff1891SJyri Sarha } 51764ff1891SJyri Sarha 5188bb0daffSRob Clark /* initialize plane */ 5198bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev, 520e8e13b15SJyri Sarha int idx, enum drm_plane_type type, 521e43f2c33STomi Valkeinen u32 possible_crtcs) 5228bb0daffSRob Clark { 5239f759225STomi Valkeinen struct omap_drm_private *priv = dev->dev_private; 524dac62bcaSTomi Valkeinen unsigned int num_planes = dispc_get_num_ovls(priv->dispc); 525ef6b0e02SLaurent Pinchart struct drm_plane *plane; 5268bb0daffSRob Clark struct omap_plane *omap_plane; 527f6e63222SMaxime Ripard unsigned int zpos; 528ef6b0e02SLaurent Pinchart int ret; 529eecad437STomi Valkeinen u32 nformats; 530eecad437STomi Valkeinen const u32 *formats; 5318bb0daffSRob Clark 532c8fa1e73SBenoit Parrot if (WARN_ON(idx >= num_planes)) 533e8e13b15SJyri Sarha return ERR_PTR(-EINVAL); 534e8e13b15SJyri Sarha 5358bb0daffSRob Clark omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 536fffddfd6SLinus Torvalds if (!omap_plane) 537fb9a35f8SLaurent Pinchart return ERR_PTR(-ENOMEM); 5388bb0daffSRob Clark 539c8fa1e73SBenoit Parrot omap_plane->id = idx; 540c8fa1e73SBenoit Parrot 541c8fa1e73SBenoit Parrot DBG("%d: type=%d", omap_plane->id, type); 542c8fa1e73SBenoit Parrot DBG(" crtc_mask: 0x%04x", possible_crtcs); 543c8fa1e73SBenoit Parrot 5442e54ff0eSBenoit Parrot formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id); 545eecad437STomi Valkeinen for (nformats = 0; formats[nformats]; ++nformats) 546eecad437STomi Valkeinen ; 5478bb0daffSRob Clark 5488bb0daffSRob Clark plane = &omap_plane->base; 5498bb0daffSRob Clark 550e43f2c33STomi Valkeinen ret = drm_universal_plane_init(dev, plane, possible_crtcs, 551eecad437STomi Valkeinen &omap_plane_funcs, formats, 552e6fc3b68SBen Widawsky nformats, NULL, type, NULL); 553ef6b0e02SLaurent Pinchart if (ret < 0) 554ef6b0e02SLaurent Pinchart goto error; 5558bb0daffSRob Clark 556de8e4100SLaurent Pinchart drm_plane_helper_add(plane, &omap_plane_helper_funcs); 557de8e4100SLaurent Pinchart 5588bb0daffSRob Clark omap_plane_install_properties(plane, &plane->base); 559f6e63222SMaxime Ripard 560f6e63222SMaxime Ripard /* 561f6e63222SMaxime Ripard * Set the zpos default depending on whether we are a primary or overlay 562f6e63222SMaxime Ripard * plane. 563f6e63222SMaxime Ripard */ 564f6e63222SMaxime Ripard if (plane->type == DRM_PLANE_TYPE_PRIMARY) 565f6e63222SMaxime Ripard zpos = 0; 566f6e63222SMaxime Ripard else 567f6e63222SMaxime Ripard zpos = omap_plane->id; 568f6e63222SMaxime Ripard drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1); 5693037e0c5SJean-Jacques Hiblot drm_plane_create_alpha_property(plane); 5703037e0c5SJean-Jacques Hiblot drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) | 5713037e0c5SJean-Jacques Hiblot BIT(DRM_MODE_BLEND_COVERAGE)); 5728bb0daffSRob Clark 57364ff1891SJyri Sarha if (omap_plane_supports_yuv(plane)) 57464ff1891SJyri Sarha drm_plane_create_color_properties(plane, 57564ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_BT601) | 57664ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_BT709), 57764ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_FULL_RANGE) | 57864ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), 57964ff1891SJyri Sarha DRM_COLOR_YCBCR_BT601, 58064ff1891SJyri Sarha DRM_COLOR_YCBCR_FULL_RANGE); 58164ff1891SJyri Sarha 5828bb0daffSRob Clark return plane; 583ef6b0e02SLaurent Pinchart 584ef6b0e02SLaurent Pinchart error: 585c8fa1e73SBenoit Parrot dev_err(dev->dev, "%s(): could not create plane: %d\n", 586c8fa1e73SBenoit Parrot __func__, omap_plane->id); 587e8e13b15SJyri Sarha 588ef6b0e02SLaurent Pinchart kfree(omap_plane); 589ef6b0e02SLaurent Pinchart return NULL; 5908bb0daffSRob Clark } 591