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 2069a12263SLaurent Pinchart #include <drm/drm_atomic_helper.h> 21de8e4100SLaurent Pinchart #include <drm/drm_plane_helper.h> 2269a12263SLaurent Pinchart 238bb0daffSRob Clark #include "omap_dmm_tiler.h" 242d278f54SLaurent Pinchart #include "omap_drv.h" 258bb0daffSRob Clark 268bb0daffSRob Clark /* some hackery because omapdss has an 'enum omap_plane' (which would be 278bb0daffSRob Clark * better named omap_plane_id).. and compiler seems unhappy about having 288bb0daffSRob Clark * both a 'struct omap_plane' and 'enum omap_plane' 298bb0daffSRob Clark */ 308bb0daffSRob Clark #define omap_plane _omap_plane 318bb0daffSRob Clark 328bb0daffSRob Clark /* 338bb0daffSRob Clark * plane funcs 348bb0daffSRob Clark */ 358bb0daffSRob Clark 368bb0daffSRob Clark #define to_omap_plane(x) container_of(x, struct omap_plane, base) 378bb0daffSRob Clark 388bb0daffSRob Clark struct omap_plane { 398bb0daffSRob Clark struct drm_plane base; 408bb0daffSRob Clark int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ 418bb0daffSRob Clark const char *name; 428bb0daffSRob Clark 438bb0daffSRob Clark uint32_t nformats; 448bb0daffSRob Clark uint32_t formats[32]; 458bb0daffSRob Clark 468bb0daffSRob Clark struct omap_drm_irq error_irq; 478bb0daffSRob Clark }; 488bb0daffSRob Clark 49afc34932SLaurent Pinchart struct omap_plane_state { 50afc34932SLaurent Pinchart struct drm_plane_state base; 51afc34932SLaurent Pinchart 52afc34932SLaurent Pinchart unsigned int zorder; 53afc34932SLaurent Pinchart }; 54afc34932SLaurent Pinchart 55afc34932SLaurent Pinchart static inline struct omap_plane_state * 56afc34932SLaurent Pinchart to_omap_plane_state(struct drm_plane_state *state) 578bb0daffSRob Clark { 58afc34932SLaurent Pinchart return container_of(state, struct omap_plane_state, base); 59afc34932SLaurent Pinchart } 60afc34932SLaurent Pinchart 61d9157dfdSTomi Valkeinen static void omap_plane_setup(struct drm_plane *plane) 62afc34932SLaurent Pinchart { 63edc72557SLaurent Pinchart struct omap_plane *omap_plane = to_omap_plane(plane); 64edc72557SLaurent Pinchart struct drm_plane_state *state = plane->state; 65afc34932SLaurent Pinchart struct omap_plane_state *omap_state = to_omap_plane_state(state); 66fb730c9bSLaurent Pinchart struct omap_overlay_info info; 67fb730c9bSLaurent Pinchart struct omap_drm_window win; 688bb0daffSRob Clark int ret; 698bb0daffSRob Clark 70edc72557SLaurent Pinchart DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); 718bb0daffSRob Clark 72edc72557SLaurent Pinchart if (!state->crtc) { 738bb0daffSRob Clark dispc_ovl_enable(omap_plane->id, false); 74d9157dfdSTomi Valkeinen return; 758bb0daffSRob Clark } 768bb0daffSRob Clark 77fb730c9bSLaurent Pinchart memset(&info, 0, sizeof(info)); 78fb730c9bSLaurent Pinchart info.rotation_type = OMAP_DSS_ROT_DMA; 79fb730c9bSLaurent Pinchart info.rotation = OMAP_DSS_ROT_0; 80fb730c9bSLaurent Pinchart info.global_alpha = 0xff; 81fb730c9bSLaurent Pinchart info.mirror = 0; 82fb730c9bSLaurent Pinchart info.zorder = omap_state->zorder; 83fb730c9bSLaurent Pinchart 84fb730c9bSLaurent Pinchart memset(&win, 0, sizeof(win)); 85fb730c9bSLaurent Pinchart win.rotation = state->rotation; 86fb730c9bSLaurent Pinchart win.crtc_x = state->crtc_x; 87fb730c9bSLaurent Pinchart win.crtc_y = state->crtc_y; 88fb730c9bSLaurent Pinchart win.crtc_w = state->crtc_w; 89fb730c9bSLaurent Pinchart win.crtc_h = state->crtc_h; 90fb730c9bSLaurent Pinchart 91fb730c9bSLaurent Pinchart /* 92fb730c9bSLaurent Pinchart * src values are in Q16 fixed point, convert to integer. 93fb730c9bSLaurent Pinchart * omap_framebuffer_update_scanout() takes adjusted src. 94fb730c9bSLaurent Pinchart */ 95fb730c9bSLaurent Pinchart win.src_x = state->src_x >> 16; 96fb730c9bSLaurent Pinchart win.src_y = state->src_y >> 16; 97fb730c9bSLaurent Pinchart 98fb730c9bSLaurent Pinchart switch (state->rotation & 0xf) { 99fb730c9bSLaurent Pinchart case BIT(DRM_ROTATE_90): 100fb730c9bSLaurent Pinchart case BIT(DRM_ROTATE_270): 101fb730c9bSLaurent Pinchart win.src_w = state->src_h >> 16; 102fb730c9bSLaurent Pinchart win.src_h = state->src_w >> 16; 103fb730c9bSLaurent Pinchart break; 104fb730c9bSLaurent Pinchart default: 105fb730c9bSLaurent Pinchart win.src_w = state->src_w >> 16; 106fb730c9bSLaurent Pinchart win.src_h = state->src_h >> 16; 107fb730c9bSLaurent Pinchart break; 108fb730c9bSLaurent Pinchart } 109afc34932SLaurent Pinchart 1108bb0daffSRob Clark /* update scanout: */ 111fb730c9bSLaurent Pinchart omap_framebuffer_update_scanout(state->fb, &win, &info); 1128bb0daffSRob Clark 113fb730c9bSLaurent Pinchart DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 114fb730c9bSLaurent Pinchart info.out_width, info.out_height, 115fb730c9bSLaurent Pinchart info.screen_width); 116fb730c9bSLaurent Pinchart DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 117fb730c9bSLaurent Pinchart &info.paddr, &info.p_uv_addr); 1188bb0daffSRob Clark 119a42133a7SLaurent Pinchart dispc_ovl_set_channel_out(omap_plane->id, 120afc34932SLaurent Pinchart omap_crtc_channel(state->crtc)); 1212dd3887bSTomi Valkeinen 1228bb0daffSRob Clark /* and finally, update omapdss: */ 123fb730c9bSLaurent Pinchart ret = dispc_ovl_setup(omap_plane->id, &info, false, 124afc34932SLaurent Pinchart omap_crtc_timings(state->crtc), false); 125d9157dfdSTomi Valkeinen if (WARN_ON(ret)) 126d9157dfdSTomi Valkeinen return; 1278bb0daffSRob Clark 1288bb0daffSRob Clark dispc_ovl_enable(omap_plane->id, true); 129de8e4100SLaurent Pinchart } 130de8e4100SLaurent Pinchart 131de8e4100SLaurent Pinchart static int omap_plane_prepare_fb(struct drm_plane *plane, 132de8e4100SLaurent Pinchart struct drm_framebuffer *fb, 133de8e4100SLaurent Pinchart const struct drm_plane_state *new_state) 134de8e4100SLaurent Pinchart { 135de8e4100SLaurent Pinchart return omap_framebuffer_pin(fb); 136de8e4100SLaurent Pinchart } 137de8e4100SLaurent Pinchart 138de8e4100SLaurent Pinchart static void omap_plane_cleanup_fb(struct drm_plane *plane, 139de8e4100SLaurent Pinchart struct drm_framebuffer *fb, 140de8e4100SLaurent Pinchart const struct drm_plane_state *old_state) 141de8e4100SLaurent Pinchart { 142de8e4100SLaurent Pinchart omap_framebuffer_unpin(fb); 143de8e4100SLaurent Pinchart } 144de8e4100SLaurent Pinchart 145de8e4100SLaurent Pinchart static void omap_plane_atomic_update(struct drm_plane *plane, 146de8e4100SLaurent Pinchart struct drm_plane_state *old_state) 1478bb0daffSRob Clark { 148edc72557SLaurent Pinchart omap_plane_setup(plane); 1498bb0daffSRob Clark } 1508bb0daffSRob Clark 151de8e4100SLaurent Pinchart static void omap_plane_atomic_disable(struct drm_plane *plane, 152de8e4100SLaurent Pinchart struct drm_plane_state *old_state) 1538bb0daffSRob Clark { 154afc34932SLaurent Pinchart struct omap_plane_state *omap_state = to_omap_plane_state(plane->state); 1558bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 1562debab97SLaurent Pinchart 157afc34932SLaurent Pinchart plane->state->rotation = BIT(DRM_ROTATE_0); 158afc34932SLaurent Pinchart omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 15982e58855SLaurent Pinchart ? 0 : omap_plane->id; 16082e58855SLaurent Pinchart 161edc72557SLaurent Pinchart omap_plane_setup(plane); 1628bb0daffSRob Clark } 1638bb0daffSRob Clark 164de8e4100SLaurent Pinchart static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 165de8e4100SLaurent Pinchart .prepare_fb = omap_plane_prepare_fb, 166de8e4100SLaurent Pinchart .cleanup_fb = omap_plane_cleanup_fb, 167de8e4100SLaurent Pinchart .atomic_update = omap_plane_atomic_update, 168de8e4100SLaurent Pinchart .atomic_disable = omap_plane_atomic_disable, 169de8e4100SLaurent Pinchart }; 170de8e4100SLaurent Pinchart 171afc34932SLaurent Pinchart static void omap_plane_reset(struct drm_plane *plane) 172afc34932SLaurent Pinchart { 173afc34932SLaurent Pinchart struct omap_plane *omap_plane = to_omap_plane(plane); 174afc34932SLaurent Pinchart struct omap_plane_state *omap_state; 175afc34932SLaurent Pinchart 176afc34932SLaurent Pinchart if (plane->state && plane->state->fb) 177afc34932SLaurent Pinchart drm_framebuffer_unreference(plane->state->fb); 178afc34932SLaurent Pinchart 179afc34932SLaurent Pinchart kfree(plane->state); 180afc34932SLaurent Pinchart plane->state = NULL; 181afc34932SLaurent Pinchart 182afc34932SLaurent Pinchart omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL); 183afc34932SLaurent Pinchart if (omap_state == NULL) 184afc34932SLaurent Pinchart return; 185afc34932SLaurent Pinchart 186afc34932SLaurent Pinchart /* 187afc34932SLaurent Pinchart * Set defaults depending on whether we are a primary or overlay 188afc34932SLaurent Pinchart * plane. 189afc34932SLaurent Pinchart */ 190afc34932SLaurent Pinchart omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 191afc34932SLaurent Pinchart ? 0 : omap_plane->id; 192afc34932SLaurent Pinchart omap_state->base.rotation = BIT(DRM_ROTATE_0); 193afc34932SLaurent Pinchart 194afc34932SLaurent Pinchart plane->state = &omap_state->base; 195afc34932SLaurent Pinchart plane->state->plane = plane; 196afc34932SLaurent Pinchart } 197afc34932SLaurent Pinchart 1988bb0daffSRob Clark static void omap_plane_destroy(struct drm_plane *plane) 1998bb0daffSRob Clark { 2008bb0daffSRob Clark struct omap_plane *omap_plane = to_omap_plane(plane); 2018bb0daffSRob Clark 2028bb0daffSRob Clark DBG("%s", omap_plane->name); 2038bb0daffSRob Clark 2048bb0daffSRob Clark omap_irq_unregister(plane->dev, &omap_plane->error_irq); 2058bb0daffSRob Clark 2068bb0daffSRob Clark drm_plane_cleanup(plane); 2078bb0daffSRob Clark 2088bb0daffSRob Clark kfree(omap_plane); 2098bb0daffSRob Clark } 2108bb0daffSRob Clark 2118bb0daffSRob Clark /* helper to install properties which are common to planes and crtcs */ 2128bb0daffSRob Clark void omap_plane_install_properties(struct drm_plane *plane, 2138bb0daffSRob Clark struct drm_mode_object *obj) 2148bb0daffSRob Clark { 2158bb0daffSRob Clark struct drm_device *dev = plane->dev; 2168bb0daffSRob Clark struct omap_drm_private *priv = dev->dev_private; 2178bb0daffSRob Clark 2188bb0daffSRob Clark if (priv->has_dmm) { 219e2cd09b2SLaurent Pinchart struct drm_property *prop = dev->mode_config.rotation_property; 220e2cd09b2SLaurent Pinchart 2218bb0daffSRob Clark drm_object_attach_property(obj, prop, 0); 2228bb0daffSRob Clark } 2238bb0daffSRob Clark 224e2cd09b2SLaurent Pinchart drm_object_attach_property(obj, priv->zorder_prop, 0); 2258bb0daffSRob Clark } 2268bb0daffSRob Clark 227afc34932SLaurent Pinchart static struct drm_plane_state * 228afc34932SLaurent Pinchart omap_plane_atomic_duplicate_state(struct drm_plane *plane) 2298bb0daffSRob Clark { 230afc34932SLaurent Pinchart struct omap_plane_state *state; 231afc34932SLaurent Pinchart struct omap_plane_state *copy; 2328bb0daffSRob Clark 233afc34932SLaurent Pinchart if (WARN_ON(!plane->state)) 234afc34932SLaurent Pinchart return NULL; 235afc34932SLaurent Pinchart 236afc34932SLaurent Pinchart state = to_omap_plane_state(plane->state); 237afc34932SLaurent Pinchart copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 238afc34932SLaurent Pinchart if (copy == NULL) 239afc34932SLaurent Pinchart return NULL; 240afc34932SLaurent Pinchart 241afc34932SLaurent Pinchart __drm_atomic_helper_plane_duplicate_state(plane, ©->base); 242afc34932SLaurent Pinchart 243afc34932SLaurent Pinchart return ©->base; 2448bb0daffSRob Clark } 2458bb0daffSRob Clark 246afc34932SLaurent Pinchart static void omap_plane_atomic_destroy_state(struct drm_plane *plane, 247afc34932SLaurent Pinchart struct drm_plane_state *state) 248afc34932SLaurent Pinchart { 249afc34932SLaurent Pinchart __drm_atomic_helper_plane_destroy_state(plane, state); 250afc34932SLaurent Pinchart kfree(to_omap_plane_state(state)); 251afc34932SLaurent Pinchart } 252afc34932SLaurent Pinchart 253afc34932SLaurent Pinchart static int omap_plane_atomic_set_property(struct drm_plane *plane, 254afc34932SLaurent Pinchart struct drm_plane_state *state, 255afc34932SLaurent Pinchart struct drm_property *property, 256afc34932SLaurent Pinchart uint64_t val) 257afc34932SLaurent Pinchart { 258afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 259afc34932SLaurent Pinchart struct omap_plane_state *omap_state = to_omap_plane_state(state); 260afc34932SLaurent Pinchart 261afc34932SLaurent Pinchart if (property == priv->zorder_prop) 262afc34932SLaurent Pinchart omap_state->zorder = val; 263afc34932SLaurent Pinchart else 264afc34932SLaurent Pinchart return -EINVAL; 265afc34932SLaurent Pinchart 266a42133a7SLaurent Pinchart return 0; 267afc34932SLaurent Pinchart } 268a42133a7SLaurent Pinchart 269afc34932SLaurent Pinchart static int omap_plane_atomic_get_property(struct drm_plane *plane, 270afc34932SLaurent Pinchart const struct drm_plane_state *state, 271afc34932SLaurent Pinchart struct drm_property *property, 272afc34932SLaurent Pinchart uint64_t *val) 273afc34932SLaurent Pinchart { 274afc34932SLaurent Pinchart struct omap_drm_private *priv = plane->dev->dev_private; 275afc34932SLaurent Pinchart const struct omap_plane_state *omap_state = 276afc34932SLaurent Pinchart container_of(state, const struct omap_plane_state, base); 277a42133a7SLaurent Pinchart 278afc34932SLaurent Pinchart if (property == priv->zorder_prop) 279afc34932SLaurent Pinchart *val = omap_state->zorder; 280afc34932SLaurent Pinchart else 281afc34932SLaurent Pinchart return -EINVAL; 282afc34932SLaurent Pinchart 283afc34932SLaurent Pinchart return 0; 2848bb0daffSRob Clark } 2858bb0daffSRob Clark 2868bb0daffSRob Clark static const struct drm_plane_funcs omap_plane_funcs = { 287cef77d40SLaurent Pinchart .update_plane = drm_atomic_helper_update_plane, 288cef77d40SLaurent Pinchart .disable_plane = drm_atomic_helper_disable_plane, 289afc34932SLaurent Pinchart .reset = omap_plane_reset, 2908bb0daffSRob Clark .destroy = omap_plane_destroy, 291afc34932SLaurent Pinchart .set_property = drm_atomic_helper_plane_set_property, 292afc34932SLaurent Pinchart .atomic_duplicate_state = omap_plane_atomic_duplicate_state, 293afc34932SLaurent Pinchart .atomic_destroy_state = omap_plane_atomic_destroy_state, 294afc34932SLaurent Pinchart .atomic_set_property = omap_plane_atomic_set_property, 295afc34932SLaurent Pinchart .atomic_get_property = omap_plane_atomic_get_property, 2968bb0daffSRob Clark }; 2978bb0daffSRob Clark 2988bb0daffSRob Clark static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 2998bb0daffSRob Clark { 3008bb0daffSRob Clark struct omap_plane *omap_plane = 3018bb0daffSRob Clark container_of(irq, struct omap_plane, error_irq); 3023b143fc8STomi Valkeinen DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name, 3033b143fc8STomi Valkeinen irqstatus); 3048bb0daffSRob Clark } 3058bb0daffSRob Clark 3068bb0daffSRob Clark static const char *plane_names[] = { 3078bb0daffSRob Clark [OMAP_DSS_GFX] = "gfx", 3088bb0daffSRob Clark [OMAP_DSS_VIDEO1] = "vid1", 3098bb0daffSRob Clark [OMAP_DSS_VIDEO2] = "vid2", 3108bb0daffSRob Clark [OMAP_DSS_VIDEO3] = "vid3", 3118bb0daffSRob Clark }; 3128bb0daffSRob Clark 3138bb0daffSRob Clark static const uint32_t error_irqs[] = { 3148bb0daffSRob Clark [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, 3158bb0daffSRob Clark [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, 3168bb0daffSRob Clark [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, 3178bb0daffSRob Clark [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, 3188bb0daffSRob Clark }; 3198bb0daffSRob Clark 3208bb0daffSRob Clark /* initialize plane */ 3218bb0daffSRob Clark struct drm_plane *omap_plane_init(struct drm_device *dev, 322ef6b0e02SLaurent Pinchart int id, enum drm_plane_type type) 3238bb0daffSRob Clark { 3248bb0daffSRob Clark struct omap_drm_private *priv = dev->dev_private; 325ef6b0e02SLaurent Pinchart struct drm_plane *plane; 3268bb0daffSRob Clark struct omap_plane *omap_plane; 327ef6b0e02SLaurent Pinchart int ret; 3288bb0daffSRob Clark 329ef6b0e02SLaurent Pinchart DBG("%s: type=%d", plane_names[id], type); 3308bb0daffSRob Clark 3318bb0daffSRob Clark omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 332fffddfd6SLinus Torvalds if (!omap_plane) 333fb9a35f8SLaurent Pinchart return ERR_PTR(-ENOMEM); 3348bb0daffSRob Clark 3358bb0daffSRob Clark omap_plane->nformats = omap_framebuffer_get_formats( 3368bb0daffSRob Clark omap_plane->formats, ARRAY_SIZE(omap_plane->formats), 3378bb0daffSRob Clark dss_feat_get_supported_color_modes(id)); 3388bb0daffSRob Clark omap_plane->id = id; 3398bb0daffSRob Clark omap_plane->name = plane_names[id]; 3408bb0daffSRob Clark 3418bb0daffSRob Clark plane = &omap_plane->base; 3428bb0daffSRob Clark 3438bb0daffSRob Clark omap_plane->error_irq.irqmask = error_irqs[id]; 3448bb0daffSRob Clark omap_plane->error_irq.irq = omap_plane_error_irq; 3458bb0daffSRob Clark omap_irq_register(dev, &omap_plane->error_irq); 3468bb0daffSRob Clark 347ef6b0e02SLaurent Pinchart ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, 348ef6b0e02SLaurent Pinchart &omap_plane_funcs, omap_plane->formats, 349ef6b0e02SLaurent Pinchart omap_plane->nformats, type); 350ef6b0e02SLaurent Pinchart if (ret < 0) 351ef6b0e02SLaurent Pinchart goto error; 3528bb0daffSRob Clark 353de8e4100SLaurent Pinchart drm_plane_helper_add(plane, &omap_plane_helper_funcs); 354de8e4100SLaurent Pinchart 3558bb0daffSRob Clark omap_plane_install_properties(plane, &plane->base); 3568bb0daffSRob Clark 3578bb0daffSRob Clark return plane; 358ef6b0e02SLaurent Pinchart 359ef6b0e02SLaurent Pinchart error: 360ef6b0e02SLaurent Pinchart omap_irq_unregister(plane->dev, &omap_plane->error_irq); 361ef6b0e02SLaurent Pinchart kfree(omap_plane); 362ef6b0e02SLaurent Pinchart return NULL; 3638bb0daffSRob Clark } 364