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> 9*90bb087fSVille Syrjälä #include <drm/drm_blend.h> 10942d8344SDaniel Vetter #include <drm/drm_gem_atomic_helper.h> 11de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h> 122e54ff0eSBenoit Parrot #include <drm/drm_fourcc.h> 13720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h> 1469a12263SLaurent Pinchart 158bb0daffSRob Clark #include "omap_dmm_tiler.h" 162d278f54SLaurent Pinchart #include "omap_drv.h" 178bb0daffSRob Clark 188bb0daffSRob Clark /* 198bb0daffSRob Clark * plane funcs 208bb0daffSRob Clark */ 218bb0daffSRob Clark 223c265d92SBenoit Parrot #define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base) 233c265d92SBenoit Parrot 243c265d92SBenoit Parrot struct omap_plane_state { 253c265d92SBenoit Parrot /* Must be first. */ 263c265d92SBenoit Parrot struct drm_plane_state base; 272e54ff0eSBenoit Parrot 282e54ff0eSBenoit Parrot struct omap_hw_overlay *overlay; 29e02b5cc9SBenoit Parrot struct omap_hw_overlay *r_overlay; /* right overlay */ 303c265d92SBenoit Parrot }; 313c265d92SBenoit Parrot 328bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base) 338bb0daffSRob Clark 348bb0daffSRob Clark struct omap_plane { 358bb0daffSRob Clark struct drm_plane base; 36694c99cfSJyri Sarha enum omap_plane_id id; 378bb0daffSRob Clark }; 388bb0daffSRob Clark 39e02b5cc9SBenoit Parrot bool is_omap_plane_dual_overlay(struct drm_plane_state *state) 40e02b5cc9SBenoit Parrot { 41e02b5cc9SBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(state); 42e02b5cc9SBenoit Parrot 43e02b5cc9SBenoit Parrot return !!omap_state->r_overlay; 44e02b5cc9SBenoit Parrot } 45e02b5cc9SBenoit Parrot 4611ffd031STomi Valkeinen static int omap_plane_prepare_fb(struct drm_plane *plane, 471832040dSChris Wilson struct drm_plane_state *new_state) 4811ffd031STomi Valkeinen { 49844f9111SMaarten Lankhorst if (!new_state->fb) 50844f9111SMaarten Lankhorst return 0; 51844f9111SMaarten Lankhorst 52942d8344SDaniel Vetter drm_gem_plane_helper_prepare_fb(plane, new_state); 53942d8344SDaniel Vetter 54844f9111SMaarten Lankhorst return omap_framebuffer_pin(new_state->fb); 5511ffd031STomi Valkeinen } 5611ffd031STomi Valkeinen 5711ffd031STomi Valkeinen static void omap_plane_cleanup_fb(struct drm_plane *plane, 581832040dSChris Wilson struct drm_plane_state *old_state) 5911ffd031STomi Valkeinen { 60844f9111SMaarten Lankhorst if (old_state->fb) 61844f9111SMaarten Lankhorst omap_framebuffer_unpin(old_state->fb); 6211ffd031STomi Valkeinen } 6311ffd031STomi Valkeinen 6411ffd031STomi Valkeinen static void omap_plane_atomic_update(struct drm_plane *plane, 65977697e2SMaxime Ripard struct drm_atomic_state *state) 66afc34932SLaurent Pinchart { 679f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 6837418bf1SMaxime Ripard struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 6937418bf1SMaxime Ripard plane); 702e54ff0eSBenoit Parrot struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 712e54ff0eSBenoit Parrot plane); 722e54ff0eSBenoit Parrot struct omap_plane_state *new_omap_state; 732e54ff0eSBenoit Parrot struct omap_plane_state *old_omap_state; 74e02b5cc9SBenoit Parrot struct omap_overlay_info info, r_info; 75e02b5cc9SBenoit Parrot enum omap_plane_id ovl_id, r_ovl_id; 768bb0daffSRob Clark int ret; 77e02b5cc9SBenoit Parrot bool dual_ovl; 788bb0daffSRob Clark 792e54ff0eSBenoit Parrot new_omap_state = to_omap_plane_state(new_state); 802e54ff0eSBenoit Parrot old_omap_state = to_omap_plane_state(old_state); 812e54ff0eSBenoit Parrot 82e02b5cc9SBenoit Parrot dual_ovl = is_omap_plane_dual_overlay(new_state); 83e02b5cc9SBenoit Parrot 842e54ff0eSBenoit Parrot /* Cleanup previously held overlay if needed */ 852e54ff0eSBenoit Parrot if (old_omap_state->overlay) 862e54ff0eSBenoit Parrot omap_overlay_update_state(priv, old_omap_state->overlay); 87e02b5cc9SBenoit Parrot if (old_omap_state->r_overlay) 88e02b5cc9SBenoit Parrot omap_overlay_update_state(priv, old_omap_state->r_overlay); 892e54ff0eSBenoit Parrot 902e54ff0eSBenoit Parrot if (!new_omap_state->overlay) { 912e54ff0eSBenoit Parrot DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name); 922e54ff0eSBenoit Parrot return; 932e54ff0eSBenoit Parrot } 942e54ff0eSBenoit Parrot 952e54ff0eSBenoit Parrot ovl_id = new_omap_state->overlay->id; 96c8fa1e73SBenoit Parrot DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc, 9741016fe1SMaxime Ripard new_state->fb); 988bb0daffSRob Clark 99fb730c9bSLaurent Pinchart memset(&info, 0, sizeof(info)); 100517a8a95STomi Valkeinen info.rotation_type = OMAP_DSS_ROT_NONE; 1010bd97c42STomi Valkeinen info.rotation = DRM_MODE_ROTATE_0; 10241016fe1SMaxime Ripard info.global_alpha = new_state->alpha >> 8; 10341016fe1SMaxime Ripard info.zorder = new_state->normalized_zpos; 10441016fe1SMaxime Ripard if (new_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 1053037e0c5SJean-Jacques Hiblot info.pre_mult_alpha = 1; 1063037e0c5SJean-Jacques Hiblot else 1073037e0c5SJean-Jacques Hiblot info.pre_mult_alpha = 0; 10841016fe1SMaxime Ripard info.color_encoding = new_state->color_encoding; 10941016fe1SMaxime Ripard info.color_range = new_state->color_range; 110fb730c9bSLaurent Pinchart 111e02b5cc9SBenoit Parrot r_info = info; 112e02b5cc9SBenoit Parrot 1138bb0daffSRob Clark /* update scanout: */ 114e02b5cc9SBenoit Parrot omap_framebuffer_update_scanout(new_state->fb, new_state, &info, 115e02b5cc9SBenoit Parrot dual_ovl ? &r_info : NULL); 1168bb0daffSRob Clark 1172e54ff0eSBenoit Parrot DBG("%s: %dx%d -> %dx%d (%d)", 1182e54ff0eSBenoit Parrot new_omap_state->overlay->name, info.width, info.height, 1192e54ff0eSBenoit Parrot info.out_width, info.out_height, info.screen_width); 120fb730c9bSLaurent Pinchart DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 121fb730c9bSLaurent Pinchart &info.paddr, &info.p_uv_addr); 1228bb0daffSRob Clark 123e02b5cc9SBenoit Parrot if (dual_ovl) { 124e02b5cc9SBenoit Parrot r_ovl_id = new_omap_state->r_overlay->id; 125e02b5cc9SBenoit Parrot /* 126e02b5cc9SBenoit Parrot * If the current plane uses 2 hw planes the very next 127e02b5cc9SBenoit Parrot * zorder is used by the r_overlay so we just use the 128e02b5cc9SBenoit Parrot * main overlay zorder + 1 129e02b5cc9SBenoit Parrot */ 130e02b5cc9SBenoit Parrot r_info.zorder = info.zorder + 1; 131e02b5cc9SBenoit Parrot 132e02b5cc9SBenoit Parrot DBG("%s: %dx%d -> %dx%d (%d)", 133e02b5cc9SBenoit Parrot new_omap_state->r_overlay->name, 134e02b5cc9SBenoit Parrot r_info.width, r_info.height, 135e02b5cc9SBenoit Parrot r_info.out_width, r_info.out_height, r_info.screen_width); 136e02b5cc9SBenoit Parrot DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y, 137e02b5cc9SBenoit Parrot &r_info.paddr, &r_info.p_uv_addr); 138e02b5cc9SBenoit Parrot } 139e02b5cc9SBenoit Parrot 1408bb0daffSRob Clark /* and finally, update omapdss: */ 141c8fa1e73SBenoit Parrot ret = dispc_ovl_setup(priv->dispc, ovl_id, &info, 14241016fe1SMaxime Ripard omap_crtc_timings(new_state->crtc), false, 14341016fe1SMaxime Ripard omap_crtc_channel(new_state->crtc)); 144cfb73f20STomi Valkeinen if (ret) { 145cfb73f20STomi Valkeinen dev_err(plane->dev->dev, "Failed to setup plane %s\n", 146c8fa1e73SBenoit Parrot plane->name); 147c8fa1e73SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, false); 148d9157dfdSTomi Valkeinen return; 149794a65ffSTomi Valkeinen } 1508bb0daffSRob Clark 151c8fa1e73SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, true); 152e02b5cc9SBenoit Parrot 153e02b5cc9SBenoit Parrot if (dual_ovl) { 154e02b5cc9SBenoit Parrot ret = dispc_ovl_setup(priv->dispc, r_ovl_id, &r_info, 155e02b5cc9SBenoit Parrot omap_crtc_timings(new_state->crtc), false, 156e02b5cc9SBenoit Parrot omap_crtc_channel(new_state->crtc)); 157e02b5cc9SBenoit Parrot if (ret) { 158e02b5cc9SBenoit Parrot dev_err(plane->dev->dev, "Failed to setup plane right-overlay %s\n", 159e02b5cc9SBenoit Parrot plane->name); 160e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, r_ovl_id, false); 161e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, ovl_id, false); 162e02b5cc9SBenoit Parrot return; 163e02b5cc9SBenoit Parrot } 164e02b5cc9SBenoit Parrot 165e02b5cc9SBenoit Parrot dispc_ovl_enable(priv->dispc, r_ovl_id, true); 166e02b5cc9SBenoit Parrot } 167de8e4100SLaurent Pinchart } 168de8e4100SLaurent Pinchart 169de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane, 170977697e2SMaxime Ripard struct drm_atomic_state *state) 1718bb0daffSRob Clark { 1729f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 1738bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 1742e54ff0eSBenoit Parrot struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 1752e54ff0eSBenoit Parrot plane); 1762e54ff0eSBenoit Parrot struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 1772e54ff0eSBenoit Parrot plane); 1782e54ff0eSBenoit Parrot struct omap_plane_state *new_omap_state; 1792e54ff0eSBenoit Parrot struct omap_plane_state *old_omap_state; 1802e54ff0eSBenoit Parrot 1812e54ff0eSBenoit Parrot new_omap_state = to_omap_plane_state(new_state); 1822e54ff0eSBenoit Parrot old_omap_state = to_omap_plane_state(old_state); 1832e54ff0eSBenoit Parrot 1842e54ff0eSBenoit Parrot if (!old_omap_state->overlay) 1852e54ff0eSBenoit Parrot return; 1862debab97SLaurent Pinchart 187e05162c0SMaxime Ripard new_state->rotation = DRM_MODE_ROTATE_0; 188e05162c0SMaxime Ripard new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id; 18982e58855SLaurent Pinchart 1902e54ff0eSBenoit Parrot omap_overlay_update_state(priv, old_omap_state->overlay); 1912e54ff0eSBenoit Parrot new_omap_state->overlay = NULL; 192e02b5cc9SBenoit Parrot 193e02b5cc9SBenoit Parrot if (is_omap_plane_dual_overlay(old_state)) { 194e02b5cc9SBenoit Parrot omap_overlay_update_state(priv, old_omap_state->r_overlay); 195e02b5cc9SBenoit Parrot new_omap_state->r_overlay = NULL; 196e02b5cc9SBenoit Parrot } 1978bb0daffSRob Clark } 1988bb0daffSRob Clark 199c21134b0SNeil Armstrong #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 200c21134b0SNeil Armstrong 201c423bc85STomi Valkeinen static int omap_plane_atomic_check(struct drm_plane *plane, 2027c11b99aSMaxime Ripard struct drm_atomic_state *state) 203c423bc85STomi Valkeinen { 2047c11b99aSMaxime Ripard struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 2057c11b99aSMaxime Ripard plane); 2062e54ff0eSBenoit Parrot struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, 2072e54ff0eSBenoit Parrot plane); 208d484c20dSBenoit Parrot struct omap_drm_private *priv = plane->dev->dev_private; 2092e54ff0eSBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state); 2102e54ff0eSBenoit Parrot struct omap_global_state *omap_overlay_global_state; 211c423bc85STomi Valkeinen struct drm_crtc_state *crtc_state; 212e02b5cc9SBenoit Parrot bool new_r_hw_overlay = false; 2132e54ff0eSBenoit Parrot bool new_hw_overlay = false; 214d484c20dSBenoit Parrot u32 max_width, max_height; 2152e54ff0eSBenoit Parrot struct drm_crtc *crtc; 216d484c20dSBenoit Parrot u16 width, height; 2172e54ff0eSBenoit Parrot u32 caps = 0; 2182e54ff0eSBenoit Parrot u32 fourcc; 219c21134b0SNeil Armstrong int ret; 220c423bc85STomi Valkeinen 2212e54ff0eSBenoit Parrot omap_overlay_global_state = omap_get_global_state(state); 2222e54ff0eSBenoit Parrot if (IS_ERR(omap_overlay_global_state)) 2232e54ff0eSBenoit Parrot return PTR_ERR(omap_overlay_global_state); 224c423bc85STomi Valkeinen 225d484c20dSBenoit Parrot dispc_ovl_get_max_size(priv->dispc, &width, &height); 226d484c20dSBenoit Parrot max_width = width << 16; 227d484c20dSBenoit Parrot max_height = height << 16; 228d484c20dSBenoit Parrot 2292e54ff0eSBenoit Parrot crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc; 2302e54ff0eSBenoit Parrot if (!crtc) 23170dd2a62STomi Valkeinen return 0; 23270dd2a62STomi Valkeinen 2332e54ff0eSBenoit Parrot crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); 23470dd2a62STomi Valkeinen /* we should have a crtc state if the plane is attached to a crtc */ 23570dd2a62STomi Valkeinen if (WARN_ON(!crtc_state)) 23670dd2a62STomi Valkeinen return 0; 237c423bc85STomi Valkeinen 238c21134b0SNeil Armstrong /* 239c21134b0SNeil Armstrong * Note: these are just sanity checks to filter out totally bad scaling 240c21134b0SNeil Armstrong * factors. The real limits must be calculated case by case, and 241c21134b0SNeil Armstrong * unfortunately we currently do those checks only at the commit 242c21134b0SNeil Armstrong * phase in dispc. 243c21134b0SNeil Armstrong */ 244c21134b0SNeil Armstrong ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 245c21134b0SNeil Armstrong FRAC_16_16(1, 8), FRAC_16_16(8, 1), 246c21134b0SNeil Armstrong true, true); 247c21134b0SNeil Armstrong if (ret) 248c21134b0SNeil Armstrong return ret; 249c21134b0SNeil Armstrong 2502e54ff0eSBenoit Parrot DBG("%s: visible %d -> %d", plane->name, 2512e54ff0eSBenoit Parrot old_plane_state->visible, new_plane_state->visible); 2522e54ff0eSBenoit Parrot 2532e54ff0eSBenoit Parrot if (!new_plane_state->visible) { 2542e54ff0eSBenoit Parrot omap_overlay_release(state, omap_state->overlay); 255e02b5cc9SBenoit Parrot omap_overlay_release(state, omap_state->r_overlay); 2562e54ff0eSBenoit Parrot omap_state->overlay = NULL; 257e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 2582e54ff0eSBenoit Parrot return 0; 2592e54ff0eSBenoit Parrot } 2602e54ff0eSBenoit Parrot 261ba5c1649SMaxime Ripard if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0) 262c423bc85STomi Valkeinen return -EINVAL; 263c423bc85STomi Valkeinen 264ba5c1649SMaxime Ripard if (new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->adjusted_mode.hdisplay) 265c423bc85STomi Valkeinen return -EINVAL; 266c423bc85STomi Valkeinen 267ba5c1649SMaxime Ripard if (new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->adjusted_mode.vdisplay) 268c423bc85STomi Valkeinen return -EINVAL; 269c423bc85STomi Valkeinen 270d484c20dSBenoit Parrot /* Make sure dimensions are within bounds. */ 271d484c20dSBenoit Parrot if (new_plane_state->src_h > max_height || new_plane_state->crtc_h > height) 272d484c20dSBenoit Parrot return -EINVAL; 273d484c20dSBenoit Parrot 274e02b5cc9SBenoit Parrot 275e02b5cc9SBenoit Parrot if (new_plane_state->src_w > max_width || new_plane_state->crtc_w > width) { 276e02b5cc9SBenoit Parrot bool is_fourcc_yuv = new_plane_state->fb->format->is_yuv; 277e02b5cc9SBenoit Parrot 278e02b5cc9SBenoit Parrot if (is_fourcc_yuv && (((new_plane_state->src_w >> 16) / 2 & 1) || 279e02b5cc9SBenoit Parrot new_plane_state->crtc_w / 2 & 1)) { 280e02b5cc9SBenoit Parrot /* 281e02b5cc9SBenoit Parrot * When calculating the split overlay width 282e02b5cc9SBenoit Parrot * and it yield an odd value we will need to adjust 283e02b5cc9SBenoit Parrot * the indivual width +/- 1. So make sure it fits 284e02b5cc9SBenoit Parrot */ 285e02b5cc9SBenoit Parrot if (new_plane_state->src_w <= ((2 * width - 1) << 16) && 286e02b5cc9SBenoit Parrot new_plane_state->crtc_w <= (2 * width - 1)) 287e02b5cc9SBenoit Parrot new_r_hw_overlay = true; 288e02b5cc9SBenoit Parrot else 289d484c20dSBenoit Parrot return -EINVAL; 290e02b5cc9SBenoit Parrot } else { 291e02b5cc9SBenoit Parrot if (new_plane_state->src_w <= (2 * max_width) && 292e02b5cc9SBenoit Parrot new_plane_state->crtc_w <= (2 * width)) 293e02b5cc9SBenoit Parrot new_r_hw_overlay = true; 294e02b5cc9SBenoit Parrot else 295e02b5cc9SBenoit Parrot return -EINVAL; 296e02b5cc9SBenoit Parrot } 297e02b5cc9SBenoit Parrot } 298d484c20dSBenoit Parrot 299ba5c1649SMaxime Ripard if (new_plane_state->rotation != DRM_MODE_ROTATE_0 && 300ba5c1649SMaxime Ripard !omap_framebuffer_supports_rotation(new_plane_state->fb)) 301bfeece55STomi Valkeinen return -EINVAL; 302bfeece55STomi Valkeinen 3032e54ff0eSBenoit Parrot if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w || 3042e54ff0eSBenoit Parrot (new_plane_state->src_h >> 16) != new_plane_state->crtc_h) 3052e54ff0eSBenoit Parrot caps |= OMAP_DSS_OVL_CAP_SCALE; 3062e54ff0eSBenoit Parrot 3072e54ff0eSBenoit Parrot fourcc = new_plane_state->fb->format->format; 3082e54ff0eSBenoit Parrot 3092e54ff0eSBenoit Parrot /* 3102e54ff0eSBenoit Parrot * (re)allocate hw overlay if we don't have one or 3112e54ff0eSBenoit Parrot * there is a caps mismatch 3122e54ff0eSBenoit Parrot */ 3132e54ff0eSBenoit Parrot if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) { 3142e54ff0eSBenoit Parrot new_hw_overlay = true; 3152e54ff0eSBenoit Parrot } else { 3162e54ff0eSBenoit Parrot /* check supported format */ 3172e54ff0eSBenoit Parrot if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id, 3182e54ff0eSBenoit Parrot fourcc)) 3192e54ff0eSBenoit Parrot new_hw_overlay = true; 3202e54ff0eSBenoit Parrot } 3212e54ff0eSBenoit Parrot 322e02b5cc9SBenoit Parrot /* 323e02b5cc9SBenoit Parrot * check if we need two overlays and only have 1 or 324e02b5cc9SBenoit Parrot * if we had 2 overlays but will only need 1 325e02b5cc9SBenoit Parrot */ 326e02b5cc9SBenoit Parrot if ((new_r_hw_overlay && !omap_state->r_overlay) || 327e02b5cc9SBenoit Parrot (!new_r_hw_overlay && omap_state->r_overlay)) 328e02b5cc9SBenoit Parrot new_hw_overlay = true; 329e02b5cc9SBenoit Parrot 3302e54ff0eSBenoit Parrot if (new_hw_overlay) { 3312e54ff0eSBenoit Parrot struct omap_hw_overlay *old_ovl = omap_state->overlay; 332e02b5cc9SBenoit Parrot struct omap_hw_overlay *old_r_ovl = omap_state->r_overlay; 3332e54ff0eSBenoit Parrot struct omap_hw_overlay *new_ovl = NULL; 334e02b5cc9SBenoit Parrot struct omap_hw_overlay *new_r_ovl = NULL; 3352e54ff0eSBenoit Parrot 3362e54ff0eSBenoit Parrot omap_overlay_release(state, old_ovl); 337e02b5cc9SBenoit Parrot omap_overlay_release(state, old_r_ovl); 3382e54ff0eSBenoit Parrot 339e02b5cc9SBenoit Parrot ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl, 340e02b5cc9SBenoit Parrot new_r_hw_overlay ? &new_r_ovl : NULL); 3412e54ff0eSBenoit Parrot if (ret) { 3422e54ff0eSBenoit Parrot DBG("%s: failed to assign hw_overlay", plane->name); 3432e54ff0eSBenoit Parrot omap_state->overlay = NULL; 344e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 3452e54ff0eSBenoit Parrot return ret; 3462e54ff0eSBenoit Parrot } 3472e54ff0eSBenoit Parrot 3482e54ff0eSBenoit Parrot omap_state->overlay = new_ovl; 349e02b5cc9SBenoit Parrot if (new_r_hw_overlay) 350e02b5cc9SBenoit Parrot omap_state->r_overlay = new_r_ovl; 351e02b5cc9SBenoit Parrot else 352e02b5cc9SBenoit Parrot omap_state->r_overlay = NULL; 3532e54ff0eSBenoit Parrot } 3542e54ff0eSBenoit Parrot 3552e54ff0eSBenoit Parrot DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id); 3562e54ff0eSBenoit Parrot 357e02b5cc9SBenoit Parrot if (omap_state->r_overlay) 358e02b5cc9SBenoit Parrot DBG("plane: %s r_overlay_id: %d", plane->name, omap_state->r_overlay->id); 359e02b5cc9SBenoit Parrot 360c423bc85STomi Valkeinen return 0; 361c423bc85STomi Valkeinen } 362c423bc85STomi Valkeinen 363de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 364de8e4100SLaurent Pinchart .prepare_fb = omap_plane_prepare_fb, 365de8e4100SLaurent Pinchart .cleanup_fb = omap_plane_cleanup_fb, 366c423bc85STomi Valkeinen .atomic_check = omap_plane_atomic_check, 367de8e4100SLaurent Pinchart .atomic_update = omap_plane_atomic_update, 368de8e4100SLaurent Pinchart .atomic_disable = omap_plane_atomic_disable, 369de8e4100SLaurent Pinchart }; 370de8e4100SLaurent Pinchart 3718bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane) 3728bb0daffSRob Clark { 3738bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 3748bb0daffSRob Clark 375c8fa1e73SBenoit Parrot DBG("%s", plane->name); 3768bb0daffSRob Clark 3778bb0daffSRob Clark drm_plane_cleanup(plane); 3788bb0daffSRob Clark 3798bb0daffSRob Clark kfree(omap_plane); 3808bb0daffSRob Clark } 3818bb0daffSRob Clark 3828bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */ 3838bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane, 3848bb0daffSRob Clark struct drm_mode_object *obj) 3858bb0daffSRob Clark { 3868bb0daffSRob Clark struct drm_device *dev = plane->dev; 3878bb0daffSRob Clark struct omap_drm_private *priv = dev->dev_private; 3888bb0daffSRob Clark 3898bb0daffSRob Clark if (priv->has_dmm) { 3900da88db1SVille Syrjälä if (!plane->rotation_property) 3910da88db1SVille Syrjälä drm_plane_create_rotation_property(plane, 392c2c446adSRobert Foss DRM_MODE_ROTATE_0, 393c2c446adSRobert Foss DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | 394c2c446adSRobert Foss DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | 395c2c446adSRobert Foss DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); 396e2cd09b2SLaurent Pinchart 3970da88db1SVille Syrjälä /* Attach the rotation property also to the crtc object */ 3980da88db1SVille Syrjälä if (plane->rotation_property && obj != &plane->base) 3990da88db1SVille Syrjälä drm_object_attach_property(obj, plane->rotation_property, 400c2c446adSRobert Foss DRM_MODE_ROTATE_0); 4018bb0daffSRob Clark } 4028bb0daffSRob Clark 403e2cd09b2SLaurent Pinchart drm_object_attach_property(obj, priv->zorder_prop, 0); 4048bb0daffSRob Clark } 4058bb0daffSRob Clark 406e07323cfSTomi Valkeinen static void omap_plane_reset(struct drm_plane *plane) 407e07323cfSTomi Valkeinen { 4083c265d92SBenoit Parrot struct omap_plane_state *omap_state; 409e07323cfSTomi Valkeinen 4103c265d92SBenoit Parrot if (plane->state) 4113c265d92SBenoit Parrot drm_atomic_helper_plane_destroy_state(plane, plane->state); 4123c265d92SBenoit Parrot 4133c265d92SBenoit Parrot omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL); 4143c265d92SBenoit Parrot if (!omap_state) 415e07323cfSTomi Valkeinen return; 416e07323cfSTomi Valkeinen 4173c265d92SBenoit Parrot __drm_atomic_helper_plane_reset(plane, &omap_state->base); 418e07323cfSTomi Valkeinen } 419e07323cfSTomi Valkeinen 4203c265d92SBenoit Parrot static struct drm_plane_state * 4213c265d92SBenoit Parrot omap_plane_atomic_duplicate_state(struct drm_plane *plane) 4223c265d92SBenoit Parrot { 4232e54ff0eSBenoit Parrot struct omap_plane_state *state, *current_state; 4243c265d92SBenoit Parrot 4253c265d92SBenoit Parrot if (WARN_ON(!plane->state)) 4263c265d92SBenoit Parrot return NULL; 4273c265d92SBenoit Parrot 4282e54ff0eSBenoit Parrot current_state = to_omap_plane_state(plane->state); 4292e54ff0eSBenoit Parrot 4303c265d92SBenoit Parrot state = kmalloc(sizeof(*state), GFP_KERNEL); 4313c265d92SBenoit Parrot if (!state) 4323c265d92SBenoit Parrot return NULL; 4333c265d92SBenoit Parrot 4343c265d92SBenoit Parrot __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 4353c265d92SBenoit Parrot 4362e54ff0eSBenoit Parrot state->overlay = current_state->overlay; 437e02b5cc9SBenoit Parrot state->r_overlay = current_state->r_overlay; 4382e54ff0eSBenoit Parrot 4393c265d92SBenoit Parrot return &state->base; 4403c265d92SBenoit Parrot } 4413c265d92SBenoit Parrot 44219e2d266SBenoit Parrot static void omap_plane_atomic_print_state(struct drm_printer *p, 44319e2d266SBenoit Parrot const struct drm_plane_state *state) 44419e2d266SBenoit Parrot { 44519e2d266SBenoit Parrot struct omap_plane_state *omap_state = to_omap_plane_state(state); 44619e2d266SBenoit Parrot 44719e2d266SBenoit Parrot if (omap_state->overlay) 44819e2d266SBenoit Parrot drm_printf(p, "\toverlay=%s (caps=0x%x)\n", 44919e2d266SBenoit Parrot omap_state->overlay->name, 45019e2d266SBenoit Parrot omap_state->overlay->caps); 45119e2d266SBenoit Parrot else 45219e2d266SBenoit Parrot drm_printf(p, "\toverlay=None\n"); 453e02b5cc9SBenoit Parrot if (omap_state->r_overlay) 454e02b5cc9SBenoit Parrot drm_printf(p, "\tr_overlay=%s (caps=0x%x)\n", 455e02b5cc9SBenoit Parrot omap_state->r_overlay->name, 456e02b5cc9SBenoit Parrot omap_state->r_overlay->caps); 457e02b5cc9SBenoit Parrot else 458e02b5cc9SBenoit Parrot drm_printf(p, "\tr_overlay=None\n"); 45919e2d266SBenoit Parrot } 46019e2d266SBenoit Parrot 461afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane, 462afc34932SLaurent Pinchart struct drm_plane_state *state, 463afc34932SLaurent Pinchart struct drm_property *property, 464dfe9cfccSLaurent Pinchart u64 val) 465afc34932SLaurent Pinchart { 466afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 467afc34932SLaurent Pinchart 468afc34932SLaurent Pinchart if (property == priv->zorder_prop) 469ba527c13SLaurent Pinchart state->zpos = val; 470afc34932SLaurent Pinchart else 471afc34932SLaurent Pinchart return -EINVAL; 472afc34932SLaurent Pinchart 473a42133a7SLaurent Pinchart return 0; 474afc34932SLaurent Pinchart } 475a42133a7SLaurent Pinchart 476afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane, 477afc34932SLaurent Pinchart const struct drm_plane_state *state, 478afc34932SLaurent Pinchart struct drm_property *property, 479dfe9cfccSLaurent Pinchart u64 *val) 480afc34932SLaurent Pinchart { 481afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 482a42133a7SLaurent Pinchart 483afc34932SLaurent Pinchart if (property == priv->zorder_prop) 484ba527c13SLaurent Pinchart *val = state->zpos; 485afc34932SLaurent Pinchart else 486afc34932SLaurent Pinchart return -EINVAL; 487afc34932SLaurent Pinchart 488afc34932SLaurent Pinchart return 0; 4898bb0daffSRob Clark } 4908bb0daffSRob Clark 4918bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = { 492cef77d40SLaurent Pinchart .update_plane = drm_atomic_helper_update_plane, 493cef77d40SLaurent Pinchart .disable_plane = drm_atomic_helper_disable_plane, 494afc34932SLaurent Pinchart .reset = omap_plane_reset, 4958bb0daffSRob Clark .destroy = omap_plane_destroy, 4963c265d92SBenoit Parrot .atomic_duplicate_state = omap_plane_atomic_duplicate_state, 497d980278bSLaurent Pinchart .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 498afc34932SLaurent Pinchart .atomic_set_property = omap_plane_atomic_set_property, 499afc34932SLaurent Pinchart .atomic_get_property = omap_plane_atomic_get_property, 50019e2d266SBenoit Parrot .atomic_print_state = omap_plane_atomic_print_state, 5018bb0daffSRob Clark }; 5028bb0daffSRob Clark 50364ff1891SJyri Sarha static bool omap_plane_supports_yuv(struct drm_plane *plane) 50464ff1891SJyri Sarha { 50564ff1891SJyri Sarha struct omap_drm_private *priv = plane->dev->dev_private; 50664ff1891SJyri Sarha struct omap_plane *omap_plane = to_omap_plane(plane); 507dac62bcaSTomi Valkeinen const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id); 50864ff1891SJyri Sarha u32 i; 50964ff1891SJyri Sarha 51064ff1891SJyri Sarha for (i = 0; formats[i]; i++) 51164ff1891SJyri Sarha if (formats[i] == DRM_FORMAT_YUYV || 51264ff1891SJyri Sarha formats[i] == DRM_FORMAT_UYVY || 51364ff1891SJyri Sarha formats[i] == DRM_FORMAT_NV12) 51464ff1891SJyri Sarha return true; 51564ff1891SJyri Sarha 51664ff1891SJyri Sarha return false; 51764ff1891SJyri Sarha } 51864ff1891SJyri Sarha 5198bb0daffSRob Clark /* initialize plane */ 5208bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev, 521e8e13b15SJyri Sarha int idx, enum drm_plane_type type, 522e43f2c33STomi Valkeinen u32 possible_crtcs) 5238bb0daffSRob Clark { 5249f759225STomi Valkeinen struct omap_drm_private *priv = dev->dev_private; 525dac62bcaSTomi Valkeinen unsigned int num_planes = dispc_get_num_ovls(priv->dispc); 526ef6b0e02SLaurent Pinchart struct drm_plane *plane; 5278bb0daffSRob Clark struct omap_plane *omap_plane; 528f6e63222SMaxime Ripard unsigned int zpos; 529ef6b0e02SLaurent Pinchart int ret; 530eecad437STomi Valkeinen u32 nformats; 531eecad437STomi Valkeinen const u32 *formats; 5328bb0daffSRob Clark 533c8fa1e73SBenoit Parrot if (WARN_ON(idx >= num_planes)) 534e8e13b15SJyri Sarha return ERR_PTR(-EINVAL); 535e8e13b15SJyri Sarha 5368bb0daffSRob Clark omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 537fffddfd6SLinus Torvalds if (!omap_plane) 538fb9a35f8SLaurent Pinchart return ERR_PTR(-ENOMEM); 5398bb0daffSRob Clark 540c8fa1e73SBenoit Parrot omap_plane->id = idx; 541c8fa1e73SBenoit Parrot 542c8fa1e73SBenoit Parrot DBG("%d: type=%d", omap_plane->id, type); 543c8fa1e73SBenoit Parrot DBG(" crtc_mask: 0x%04x", possible_crtcs); 544c8fa1e73SBenoit Parrot 5452e54ff0eSBenoit Parrot formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id); 546eecad437STomi Valkeinen for (nformats = 0; formats[nformats]; ++nformats) 547eecad437STomi Valkeinen ; 5488bb0daffSRob Clark 5498bb0daffSRob Clark plane = &omap_plane->base; 5508bb0daffSRob Clark 551e43f2c33STomi Valkeinen ret = drm_universal_plane_init(dev, plane, possible_crtcs, 552eecad437STomi Valkeinen &omap_plane_funcs, formats, 553e6fc3b68SBen Widawsky nformats, NULL, type, NULL); 554ef6b0e02SLaurent Pinchart if (ret < 0) 555ef6b0e02SLaurent Pinchart goto error; 5568bb0daffSRob Clark 557de8e4100SLaurent Pinchart drm_plane_helper_add(plane, &omap_plane_helper_funcs); 558de8e4100SLaurent Pinchart 5598bb0daffSRob Clark omap_plane_install_properties(plane, &plane->base); 560f6e63222SMaxime Ripard 561f6e63222SMaxime Ripard /* 562f6e63222SMaxime Ripard * Set the zpos default depending on whether we are a primary or overlay 563f6e63222SMaxime Ripard * plane. 564f6e63222SMaxime Ripard */ 565f6e63222SMaxime Ripard if (plane->type == DRM_PLANE_TYPE_PRIMARY) 566f6e63222SMaxime Ripard zpos = 0; 567f6e63222SMaxime Ripard else 568f6e63222SMaxime Ripard zpos = omap_plane->id; 569f6e63222SMaxime Ripard drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1); 5703037e0c5SJean-Jacques Hiblot drm_plane_create_alpha_property(plane); 5713037e0c5SJean-Jacques Hiblot drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) | 5723037e0c5SJean-Jacques Hiblot BIT(DRM_MODE_BLEND_COVERAGE)); 5738bb0daffSRob Clark 57464ff1891SJyri Sarha if (omap_plane_supports_yuv(plane)) 57564ff1891SJyri Sarha drm_plane_create_color_properties(plane, 57664ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_BT601) | 57764ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_BT709), 57864ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_FULL_RANGE) | 57964ff1891SJyri Sarha BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), 58064ff1891SJyri Sarha DRM_COLOR_YCBCR_BT601, 58164ff1891SJyri Sarha DRM_COLOR_YCBCR_FULL_RANGE); 58264ff1891SJyri Sarha 5838bb0daffSRob Clark return plane; 584ef6b0e02SLaurent Pinchart 585ef6b0e02SLaurent Pinchart error: 586c8fa1e73SBenoit Parrot dev_err(dev->dev, "%s(): could not create plane: %d\n", 587c8fa1e73SBenoit Parrot __func__, omap_plane->id); 588e8e13b15SJyri Sarha 589ef6b0e02SLaurent Pinchart kfree(omap_plane); 590ef6b0e02SLaurent Pinchart return NULL; 5918bb0daffSRob Clark } 592