18bb0daffSRob Clark /* 28bb0daffSRob Clark * drivers/gpu/drm/omapdrm/omap_plane.c 38bb0daffSRob Clark * 48bb0daffSRob Clark * Copyright (C) 2011 Texas Instruments 58bb0daffSRob Clark * Author: Rob Clark <rob.clark@linaro.org> 68bb0daffSRob Clark * 78bb0daffSRob Clark * This program is free software; you can redistribute it and/or modify it 88bb0daffSRob Clark * under the terms of the GNU General Public License version 2 as published by 98bb0daffSRob Clark * the Free Software Foundation. 108bb0daffSRob Clark * 118bb0daffSRob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 128bb0daffSRob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 138bb0daffSRob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 148bb0daffSRob Clark * more details. 158bb0daffSRob Clark * 168bb0daffSRob Clark * You should have received a copy of the GNU General Public License along with 178bb0daffSRob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 188bb0daffSRob Clark */ 198bb0daffSRob Clark 20c423bc85STomi Valkeinen #include <drm/drm_atomic.h> 2169a12263SLaurent Pinchart #include <drm/drm_atomic_helper.h> 22de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h> 2369a12263SLaurent Pinchart 248bb0daffSRob Clark #include "omap_dmm_tiler.h" 252d278f54SLaurent Pinchart #include "omap_drv.h" 268bb0daffSRob Clark 278bb0daffSRob Clark /* 288bb0daffSRob Clark * plane funcs 298bb0daffSRob Clark */ 308bb0daffSRob Clark 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 const char *name; 378bb0daffSRob Clark 388bb0daffSRob Clark uint32_t nformats; 398bb0daffSRob Clark uint32_t formats[32]; 408bb0daffSRob Clark }; 418bb0daffSRob Clark 4211ffd031STomi Valkeinen static int omap_plane_prepare_fb(struct drm_plane *plane, 431832040dSChris Wilson struct drm_plane_state *new_state) 4411ffd031STomi Valkeinen { 45844f9111SMaarten Lankhorst if (!new_state->fb) 46844f9111SMaarten Lankhorst return 0; 47844f9111SMaarten Lankhorst 48844f9111SMaarten Lankhorst return omap_framebuffer_pin(new_state->fb); 4911ffd031STomi Valkeinen } 5011ffd031STomi Valkeinen 5111ffd031STomi Valkeinen static void omap_plane_cleanup_fb(struct drm_plane *plane, 521832040dSChris Wilson struct drm_plane_state *old_state) 5311ffd031STomi Valkeinen { 54844f9111SMaarten Lankhorst if (old_state->fb) 55844f9111SMaarten Lankhorst omap_framebuffer_unpin(old_state->fb); 5611ffd031STomi Valkeinen } 5711ffd031STomi Valkeinen 5811ffd031STomi Valkeinen static void omap_plane_atomic_update(struct drm_plane *plane, 5911ffd031STomi Valkeinen struct drm_plane_state *old_state) 60afc34932SLaurent Pinchart { 619f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 62edc72557SLaurent Pinchart struct omap_plane *omap_plane = to_omap_plane(plane); 63edc72557SLaurent Pinchart struct drm_plane_state *state = plane->state; 64fb730c9bSLaurent Pinchart struct omap_overlay_info info; 65fb730c9bSLaurent Pinchart struct omap_drm_window win; 668bb0daffSRob Clark int ret; 678bb0daffSRob Clark 68edc72557SLaurent Pinchart DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); 698bb0daffSRob Clark 70fb730c9bSLaurent Pinchart memset(&info, 0, sizeof(info)); 71517a8a95STomi Valkeinen info.rotation_type = OMAP_DSS_ROT_NONE; 72fb730c9bSLaurent Pinchart info.rotation = OMAP_DSS_ROT_0; 73fb730c9bSLaurent Pinchart info.global_alpha = 0xff; 74fb730c9bSLaurent Pinchart info.mirror = 0; 75ba527c13SLaurent Pinchart info.zorder = state->zpos; 76fb730c9bSLaurent Pinchart 77fb730c9bSLaurent Pinchart memset(&win, 0, sizeof(win)); 78fb730c9bSLaurent Pinchart win.rotation = state->rotation; 79fb730c9bSLaurent Pinchart win.crtc_x = state->crtc_x; 80fb730c9bSLaurent Pinchart win.crtc_y = state->crtc_y; 81fb730c9bSLaurent Pinchart win.crtc_w = state->crtc_w; 82fb730c9bSLaurent Pinchart win.crtc_h = state->crtc_h; 83fb730c9bSLaurent Pinchart 84fb730c9bSLaurent Pinchart /* 85fb730c9bSLaurent Pinchart * src values are in Q16 fixed point, convert to integer. 86fb730c9bSLaurent Pinchart * omap_framebuffer_update_scanout() takes adjusted src. 87fb730c9bSLaurent Pinchart */ 88fb730c9bSLaurent Pinchart win.src_x = state->src_x >> 16; 89fb730c9bSLaurent Pinchart win.src_y = state->src_y >> 16; 90fb730c9bSLaurent Pinchart 91bd2ef25dSVille Syrjälä if (drm_rotation_90_or_270(state->rotation)) { 92fb730c9bSLaurent Pinchart win.src_w = state->src_h >> 16; 93fb730c9bSLaurent Pinchart win.src_h = state->src_w >> 16; 94bd2ef25dSVille Syrjälä } else { 95fb730c9bSLaurent Pinchart win.src_w = state->src_w >> 16; 96fb730c9bSLaurent Pinchart win.src_h = state->src_h >> 16; 97fb730c9bSLaurent Pinchart } 98afc34932SLaurent Pinchart 998bb0daffSRob Clark /* update scanout: */ 100fb730c9bSLaurent Pinchart omap_framebuffer_update_scanout(state->fb, &win, &info); 1018bb0daffSRob Clark 102fb730c9bSLaurent Pinchart DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 103fb730c9bSLaurent Pinchart info.out_width, info.out_height, 104fb730c9bSLaurent Pinchart info.screen_width); 105fb730c9bSLaurent Pinchart DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 106fb730c9bSLaurent Pinchart &info.paddr, &info.p_uv_addr); 1078bb0daffSRob Clark 1088bb0daffSRob Clark /* and finally, update omapdss: */ 109be2d68c6STomi Valkeinen ret = priv->dispc_ops->ovl_setup(omap_plane->id, &info, 11049a3057aSTomi Valkeinen omap_crtc_timings(state->crtc), false, 11149a3057aSTomi Valkeinen omap_crtc_channel(state->crtc)); 112cfb73f20STomi Valkeinen if (ret) { 113cfb73f20STomi Valkeinen dev_err(plane->dev->dev, "Failed to setup plane %s\n", 114cfb73f20STomi Valkeinen omap_plane->name); 1159f759225STomi Valkeinen priv->dispc_ops->ovl_enable(omap_plane->id, false); 116d9157dfdSTomi Valkeinen return; 117794a65ffSTomi Valkeinen } 1188bb0daffSRob Clark 1199f759225STomi Valkeinen priv->dispc_ops->ovl_enable(omap_plane->id, true); 120de8e4100SLaurent Pinchart } 121de8e4100SLaurent Pinchart 122de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane, 123de8e4100SLaurent Pinchart struct drm_plane_state *old_state) 1248bb0daffSRob Clark { 1259f759225STomi Valkeinen struct omap_drm_private *priv = plane->dev->dev_private; 1268bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 1272debab97SLaurent Pinchart 128c2c446adSRobert Foss plane->state->rotation = DRM_MODE_ROTATE_0; 129ba527c13SLaurent Pinchart plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY 13082e58855SLaurent Pinchart ? 0 : omap_plane->id; 13182e58855SLaurent Pinchart 1329f759225STomi Valkeinen priv->dispc_ops->ovl_enable(omap_plane->id, false); 1338bb0daffSRob Clark } 1348bb0daffSRob Clark 135c423bc85STomi Valkeinen static int omap_plane_atomic_check(struct drm_plane *plane, 136c423bc85STomi Valkeinen struct drm_plane_state *state) 137c423bc85STomi Valkeinen { 138c423bc85STomi Valkeinen struct drm_crtc_state *crtc_state; 139c423bc85STomi Valkeinen 14070dd2a62STomi Valkeinen if (!state->fb) 141c423bc85STomi Valkeinen return 0; 142c423bc85STomi Valkeinen 14370dd2a62STomi Valkeinen /* crtc should only be NULL when disabling (i.e., !state->fb) */ 14470dd2a62STomi Valkeinen if (WARN_ON(!state->crtc)) 14570dd2a62STomi Valkeinen return 0; 14670dd2a62STomi Valkeinen 14770dd2a62STomi Valkeinen crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); 14870dd2a62STomi Valkeinen /* we should have a crtc state if the plane is attached to a crtc */ 14970dd2a62STomi Valkeinen if (WARN_ON(!crtc_state)) 15070dd2a62STomi Valkeinen return 0; 151c423bc85STomi Valkeinen 152aaf7642eSTomi Valkeinen if (!crtc_state->enable) 153aaf7642eSTomi Valkeinen return 0; 154aaf7642eSTomi Valkeinen 155c423bc85STomi Valkeinen if (state->crtc_x < 0 || state->crtc_y < 0) 156c423bc85STomi Valkeinen return -EINVAL; 157c423bc85STomi Valkeinen 158c423bc85STomi Valkeinen if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay) 159c423bc85STomi Valkeinen return -EINVAL; 160c423bc85STomi Valkeinen 161c423bc85STomi Valkeinen if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) 162c423bc85STomi Valkeinen return -EINVAL; 163c423bc85STomi Valkeinen 164c2c446adSRobert Foss if (state->rotation != DRM_MODE_ROTATE_0 && 165bfeece55STomi Valkeinen !omap_framebuffer_supports_rotation(state->fb)) 166bfeece55STomi Valkeinen return -EINVAL; 167bfeece55STomi Valkeinen 168c423bc85STomi Valkeinen return 0; 169c423bc85STomi Valkeinen } 170c423bc85STomi Valkeinen 171de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 172de8e4100SLaurent Pinchart .prepare_fb = omap_plane_prepare_fb, 173de8e4100SLaurent Pinchart .cleanup_fb = omap_plane_cleanup_fb, 174c423bc85STomi Valkeinen .atomic_check = omap_plane_atomic_check, 175de8e4100SLaurent Pinchart .atomic_update = omap_plane_atomic_update, 176de8e4100SLaurent Pinchart .atomic_disable = omap_plane_atomic_disable, 177de8e4100SLaurent Pinchart }; 178de8e4100SLaurent Pinchart 1798bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane) 1808bb0daffSRob Clark { 1818bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 1828bb0daffSRob Clark 1838bb0daffSRob Clark DBG("%s", omap_plane->name); 1848bb0daffSRob Clark 1858bb0daffSRob Clark drm_plane_cleanup(plane); 1868bb0daffSRob Clark 1878bb0daffSRob Clark kfree(omap_plane); 1888bb0daffSRob Clark } 1898bb0daffSRob Clark 1908bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */ 1918bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane, 1928bb0daffSRob Clark struct drm_mode_object *obj) 1938bb0daffSRob Clark { 1948bb0daffSRob Clark struct drm_device *dev = plane->dev; 1958bb0daffSRob Clark struct omap_drm_private *priv = dev->dev_private; 1968bb0daffSRob Clark 1978bb0daffSRob Clark if (priv->has_dmm) { 1980da88db1SVille Syrjälä if (!plane->rotation_property) 1990da88db1SVille Syrjälä drm_plane_create_rotation_property(plane, 200c2c446adSRobert Foss DRM_MODE_ROTATE_0, 201c2c446adSRobert Foss DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | 202c2c446adSRobert Foss DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | 203c2c446adSRobert Foss DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); 204e2cd09b2SLaurent Pinchart 2050da88db1SVille Syrjälä /* Attach the rotation property also to the crtc object */ 2060da88db1SVille Syrjälä if (plane->rotation_property && obj != &plane->base) 2070da88db1SVille Syrjälä drm_object_attach_property(obj, plane->rotation_property, 208c2c446adSRobert Foss DRM_MODE_ROTATE_0); 2098bb0daffSRob Clark } 2108bb0daffSRob Clark 211e2cd09b2SLaurent Pinchart drm_object_attach_property(obj, priv->zorder_prop, 0); 2128bb0daffSRob Clark } 2138bb0daffSRob Clark 214e07323cfSTomi Valkeinen static void omap_plane_reset(struct drm_plane *plane) 215e07323cfSTomi Valkeinen { 216e07323cfSTomi Valkeinen struct omap_plane *omap_plane = to_omap_plane(plane); 217e07323cfSTomi Valkeinen 218d980278bSLaurent Pinchart drm_atomic_helper_plane_reset(plane); 219d980278bSLaurent Pinchart if (!plane->state) 220e07323cfSTomi Valkeinen return; 221e07323cfSTomi Valkeinen 222e07323cfSTomi Valkeinen /* 223ba527c13SLaurent Pinchart * Set the zpos default depending on whether we are a primary or overlay 224e07323cfSTomi Valkeinen * plane. 225e07323cfSTomi Valkeinen */ 226d980278bSLaurent Pinchart plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY 227e07323cfSTomi Valkeinen ? 0 : omap_plane->id; 228e07323cfSTomi Valkeinen } 229e07323cfSTomi Valkeinen 230afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane, 231afc34932SLaurent Pinchart struct drm_plane_state *state, 232afc34932SLaurent Pinchart struct drm_property *property, 233afc34932SLaurent Pinchart uint64_t val) 234afc34932SLaurent Pinchart { 235afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 236afc34932SLaurent Pinchart 237afc34932SLaurent Pinchart if (property == priv->zorder_prop) 238ba527c13SLaurent Pinchart state->zpos = val; 239afc34932SLaurent Pinchart else 240afc34932SLaurent Pinchart return -EINVAL; 241afc34932SLaurent Pinchart 242a42133a7SLaurent Pinchart return 0; 243afc34932SLaurent Pinchart } 244a42133a7SLaurent Pinchart 245afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane, 246afc34932SLaurent Pinchart const struct drm_plane_state *state, 247afc34932SLaurent Pinchart struct drm_property *property, 248afc34932SLaurent Pinchart uint64_t *val) 249afc34932SLaurent Pinchart { 250afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 251a42133a7SLaurent Pinchart 252afc34932SLaurent Pinchart if (property == priv->zorder_prop) 253ba527c13SLaurent Pinchart *val = state->zpos; 254afc34932SLaurent Pinchart else 255afc34932SLaurent Pinchart return -EINVAL; 256afc34932SLaurent Pinchart 257afc34932SLaurent Pinchart return 0; 2588bb0daffSRob Clark } 2598bb0daffSRob Clark 2608bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = { 261cef77d40SLaurent Pinchart .update_plane = drm_atomic_helper_update_plane, 262cef77d40SLaurent Pinchart .disable_plane = drm_atomic_helper_disable_plane, 263afc34932SLaurent Pinchart .reset = omap_plane_reset, 2648bb0daffSRob Clark .destroy = omap_plane_destroy, 265afc34932SLaurent Pinchart .set_property = drm_atomic_helper_plane_set_property, 266d980278bSLaurent Pinchart .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 267d980278bSLaurent Pinchart .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 268afc34932SLaurent Pinchart .atomic_set_property = omap_plane_atomic_set_property, 269afc34932SLaurent Pinchart .atomic_get_property = omap_plane_atomic_get_property, 2708bb0daffSRob Clark }; 2718bb0daffSRob Clark 272e8e13b15SJyri Sarha static const char *plane_id_to_name[] = { 2738bb0daffSRob Clark [OMAP_DSS_GFX] = "gfx", 2748bb0daffSRob Clark [OMAP_DSS_VIDEO1] = "vid1", 2758bb0daffSRob Clark [OMAP_DSS_VIDEO2] = "vid2", 2768bb0daffSRob Clark [OMAP_DSS_VIDEO3] = "vid3", 2778bb0daffSRob Clark }; 2788bb0daffSRob Clark 279e8e13b15SJyri Sarha static const enum omap_plane_id plane_idx_to_id[] = { 280e8e13b15SJyri Sarha OMAP_DSS_GFX, 281e8e13b15SJyri Sarha OMAP_DSS_VIDEO1, 282e8e13b15SJyri Sarha OMAP_DSS_VIDEO2, 283e8e13b15SJyri Sarha OMAP_DSS_VIDEO3, 284e8e13b15SJyri Sarha }; 285e8e13b15SJyri Sarha 2868bb0daffSRob Clark /* initialize plane */ 2878bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev, 288e8e13b15SJyri Sarha int idx, enum drm_plane_type type, 289e43f2c33STomi Valkeinen u32 possible_crtcs) 2908bb0daffSRob Clark { 2919f759225STomi Valkeinen struct omap_drm_private *priv = dev->dev_private; 292dff6c246SLaurent Pinchart unsigned int num_planes = priv->dispc_ops->get_num_ovls(); 293ef6b0e02SLaurent Pinchart struct drm_plane *plane; 2948bb0daffSRob Clark struct omap_plane *omap_plane; 295e8e13b15SJyri Sarha enum omap_plane_id id; 296ef6b0e02SLaurent Pinchart int ret; 2978bb0daffSRob Clark 298e8e13b15SJyri Sarha if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id))) 299e8e13b15SJyri Sarha return ERR_PTR(-EINVAL); 300e8e13b15SJyri Sarha 301e8e13b15SJyri Sarha id = plane_idx_to_id[idx]; 302e8e13b15SJyri Sarha 303e8e13b15SJyri Sarha DBG("%s: type=%d", plane_id_to_name[id], type); 3048bb0daffSRob Clark 3058bb0daffSRob Clark omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 306fffddfd6SLinus Torvalds if (!omap_plane) 307fb9a35f8SLaurent Pinchart return ERR_PTR(-ENOMEM); 3088bb0daffSRob Clark 3098bb0daffSRob Clark omap_plane->nformats = omap_framebuffer_get_formats( 3108bb0daffSRob Clark omap_plane->formats, ARRAY_SIZE(omap_plane->formats), 3119f759225STomi Valkeinen priv->dispc_ops->ovl_get_color_modes(id)); 3128bb0daffSRob Clark omap_plane->id = id; 313e8e13b15SJyri Sarha omap_plane->name = plane_id_to_name[id]; 3148bb0daffSRob Clark 3158bb0daffSRob Clark plane = &omap_plane->base; 3168bb0daffSRob Clark 317e43f2c33STomi Valkeinen ret = drm_universal_plane_init(dev, plane, possible_crtcs, 318ef6b0e02SLaurent Pinchart &omap_plane_funcs, omap_plane->formats, 319b0b3b795SVille Syrjälä omap_plane->nformats, type, NULL); 320ef6b0e02SLaurent Pinchart if (ret < 0) 321ef6b0e02SLaurent Pinchart goto error; 3228bb0daffSRob Clark 323de8e4100SLaurent Pinchart drm_plane_helper_add(plane, &omap_plane_helper_funcs); 324de8e4100SLaurent Pinchart 3258bb0daffSRob Clark omap_plane_install_properties(plane, &plane->base); 326dff6c246SLaurent Pinchart drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1); 3278bb0daffSRob Clark 3288bb0daffSRob Clark return plane; 329ef6b0e02SLaurent Pinchart 330ef6b0e02SLaurent Pinchart error: 331e8e13b15SJyri Sarha dev_err(dev->dev, "%s(): could not create plane: %s\n", 332e8e13b15SJyri Sarha __func__, plane_id_to_name[id]); 333e8e13b15SJyri Sarha 334ef6b0e02SLaurent Pinchart kfree(omap_plane); 335ef6b0e02SLaurent Pinchart return NULL; 3368bb0daffSRob Clark } 337