1 /* 2 * drivers/gpu/drm/omapdrm/omap_plane.c 3 * 4 * Copyright (C) 2011 Texas Instruments 5 * Author: Rob Clark <rob.clark@linaro.org> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <drm/drm_atomic_helper.h> 21 #include <drm/drm_plane_helper.h> 22 23 #include "omap_dmm_tiler.h" 24 #include "omap_drv.h" 25 26 /* some hackery because omapdss has an 'enum omap_plane' (which would be 27 * better named omap_plane_id).. and compiler seems unhappy about having 28 * both a 'struct omap_plane' and 'enum omap_plane' 29 */ 30 #define omap_plane _omap_plane 31 32 /* 33 * plane funcs 34 */ 35 36 #define to_omap_plane(x) container_of(x, struct omap_plane, base) 37 38 struct omap_plane { 39 struct drm_plane base; 40 int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ 41 const char *name; 42 43 uint32_t nformats; 44 uint32_t formats[32]; 45 46 struct omap_drm_irq error_irq; 47 }; 48 49 struct omap_plane_state { 50 struct drm_plane_state base; 51 52 unsigned int zorder; 53 }; 54 55 static inline struct omap_plane_state * 56 to_omap_plane_state(struct drm_plane_state *state) 57 { 58 return container_of(state, struct omap_plane_state, base); 59 } 60 61 static int omap_plane_prepare_fb(struct drm_plane *plane, 62 struct drm_framebuffer *fb, 63 const struct drm_plane_state *new_state) 64 { 65 return omap_framebuffer_pin(fb); 66 } 67 68 static void omap_plane_cleanup_fb(struct drm_plane *plane, 69 struct drm_framebuffer *fb, 70 const struct drm_plane_state *old_state) 71 { 72 omap_framebuffer_unpin(fb); 73 } 74 75 static void omap_plane_atomic_update(struct drm_plane *plane, 76 struct drm_plane_state *old_state) 77 { 78 struct omap_plane *omap_plane = to_omap_plane(plane); 79 struct drm_plane_state *state = plane->state; 80 struct omap_plane_state *omap_state = to_omap_plane_state(state); 81 struct omap_overlay_info info; 82 struct omap_drm_window win; 83 int ret; 84 85 DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); 86 87 memset(&info, 0, sizeof(info)); 88 info.rotation_type = OMAP_DSS_ROT_DMA; 89 info.rotation = OMAP_DSS_ROT_0; 90 info.global_alpha = 0xff; 91 info.mirror = 0; 92 info.zorder = omap_state->zorder; 93 94 memset(&win, 0, sizeof(win)); 95 win.rotation = state->rotation; 96 win.crtc_x = state->crtc_x; 97 win.crtc_y = state->crtc_y; 98 win.crtc_w = state->crtc_w; 99 win.crtc_h = state->crtc_h; 100 101 /* 102 * src values are in Q16 fixed point, convert to integer. 103 * omap_framebuffer_update_scanout() takes adjusted src. 104 */ 105 win.src_x = state->src_x >> 16; 106 win.src_y = state->src_y >> 16; 107 108 switch (state->rotation & 0xf) { 109 case BIT(DRM_ROTATE_90): 110 case BIT(DRM_ROTATE_270): 111 win.src_w = state->src_h >> 16; 112 win.src_h = state->src_w >> 16; 113 break; 114 default: 115 win.src_w = state->src_w >> 16; 116 win.src_h = state->src_h >> 16; 117 break; 118 } 119 120 /* update scanout: */ 121 omap_framebuffer_update_scanout(state->fb, &win, &info); 122 123 DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 124 info.out_width, info.out_height, 125 info.screen_width); 126 DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 127 &info.paddr, &info.p_uv_addr); 128 129 dispc_ovl_set_channel_out(omap_plane->id, 130 omap_crtc_channel(state->crtc)); 131 132 /* and finally, update omapdss: */ 133 ret = dispc_ovl_setup(omap_plane->id, &info, false, 134 omap_crtc_timings(state->crtc), false); 135 if (WARN_ON(ret)) { 136 dispc_ovl_enable(omap_plane->id, false); 137 return; 138 } 139 140 dispc_ovl_enable(omap_plane->id, true); 141 } 142 143 static void omap_plane_atomic_disable(struct drm_plane *plane, 144 struct drm_plane_state *old_state) 145 { 146 struct omap_plane_state *omap_state = to_omap_plane_state(plane->state); 147 struct omap_plane *omap_plane = to_omap_plane(plane); 148 149 plane->state->rotation = BIT(DRM_ROTATE_0); 150 omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 151 ? 0 : omap_plane->id; 152 153 dispc_ovl_enable(omap_plane->id, false); 154 } 155 156 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 157 .prepare_fb = omap_plane_prepare_fb, 158 .cleanup_fb = omap_plane_cleanup_fb, 159 .atomic_update = omap_plane_atomic_update, 160 .atomic_disable = omap_plane_atomic_disable, 161 }; 162 163 static void omap_plane_reset(struct drm_plane *plane) 164 { 165 struct omap_plane *omap_plane = to_omap_plane(plane); 166 struct omap_plane_state *omap_state; 167 168 if (plane->state && plane->state->fb) 169 drm_framebuffer_unreference(plane->state->fb); 170 171 kfree(plane->state); 172 plane->state = NULL; 173 174 omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL); 175 if (omap_state == NULL) 176 return; 177 178 /* 179 * Set defaults depending on whether we are a primary or overlay 180 * plane. 181 */ 182 omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 183 ? 0 : omap_plane->id; 184 omap_state->base.rotation = BIT(DRM_ROTATE_0); 185 186 plane->state = &omap_state->base; 187 plane->state->plane = plane; 188 } 189 190 static void omap_plane_destroy(struct drm_plane *plane) 191 { 192 struct omap_plane *omap_plane = to_omap_plane(plane); 193 194 DBG("%s", omap_plane->name); 195 196 omap_irq_unregister(plane->dev, &omap_plane->error_irq); 197 198 drm_plane_cleanup(plane); 199 200 kfree(omap_plane); 201 } 202 203 /* helper to install properties which are common to planes and crtcs */ 204 void omap_plane_install_properties(struct drm_plane *plane, 205 struct drm_mode_object *obj) 206 { 207 struct drm_device *dev = plane->dev; 208 struct omap_drm_private *priv = dev->dev_private; 209 210 if (priv->has_dmm) { 211 struct drm_property *prop = dev->mode_config.rotation_property; 212 213 drm_object_attach_property(obj, prop, 0); 214 } 215 216 drm_object_attach_property(obj, priv->zorder_prop, 0); 217 } 218 219 static struct drm_plane_state * 220 omap_plane_atomic_duplicate_state(struct drm_plane *plane) 221 { 222 struct omap_plane_state *state; 223 struct omap_plane_state *copy; 224 225 if (WARN_ON(!plane->state)) 226 return NULL; 227 228 state = to_omap_plane_state(plane->state); 229 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 230 if (copy == NULL) 231 return NULL; 232 233 __drm_atomic_helper_plane_duplicate_state(plane, ©->base); 234 235 return ©->base; 236 } 237 238 static void omap_plane_atomic_destroy_state(struct drm_plane *plane, 239 struct drm_plane_state *state) 240 { 241 __drm_atomic_helper_plane_destroy_state(plane, state); 242 kfree(to_omap_plane_state(state)); 243 } 244 245 static int omap_plane_atomic_set_property(struct drm_plane *plane, 246 struct drm_plane_state *state, 247 struct drm_property *property, 248 uint64_t val) 249 { 250 struct omap_drm_private *priv = plane->dev->dev_private; 251 struct omap_plane_state *omap_state = to_omap_plane_state(state); 252 253 if (property == priv->zorder_prop) 254 omap_state->zorder = val; 255 else 256 return -EINVAL; 257 258 return 0; 259 } 260 261 static int omap_plane_atomic_get_property(struct drm_plane *plane, 262 const struct drm_plane_state *state, 263 struct drm_property *property, 264 uint64_t *val) 265 { 266 struct omap_drm_private *priv = plane->dev->dev_private; 267 const struct omap_plane_state *omap_state = 268 container_of(state, const struct omap_plane_state, base); 269 270 if (property == priv->zorder_prop) 271 *val = omap_state->zorder; 272 else 273 return -EINVAL; 274 275 return 0; 276 } 277 278 static const struct drm_plane_funcs omap_plane_funcs = { 279 .update_plane = drm_atomic_helper_update_plane, 280 .disable_plane = drm_atomic_helper_disable_plane, 281 .reset = omap_plane_reset, 282 .destroy = omap_plane_destroy, 283 .set_property = drm_atomic_helper_plane_set_property, 284 .atomic_duplicate_state = omap_plane_atomic_duplicate_state, 285 .atomic_destroy_state = omap_plane_atomic_destroy_state, 286 .atomic_set_property = omap_plane_atomic_set_property, 287 .atomic_get_property = omap_plane_atomic_get_property, 288 }; 289 290 static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 291 { 292 struct omap_plane *omap_plane = 293 container_of(irq, struct omap_plane, error_irq); 294 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name, 295 irqstatus); 296 } 297 298 static const char *plane_names[] = { 299 [OMAP_DSS_GFX] = "gfx", 300 [OMAP_DSS_VIDEO1] = "vid1", 301 [OMAP_DSS_VIDEO2] = "vid2", 302 [OMAP_DSS_VIDEO3] = "vid3", 303 }; 304 305 static const uint32_t error_irqs[] = { 306 [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, 307 [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, 308 [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, 309 [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, 310 }; 311 312 /* initialize plane */ 313 struct drm_plane *omap_plane_init(struct drm_device *dev, 314 int id, enum drm_plane_type type) 315 { 316 struct omap_drm_private *priv = dev->dev_private; 317 struct drm_plane *plane; 318 struct omap_plane *omap_plane; 319 int ret; 320 321 DBG("%s: type=%d", plane_names[id], type); 322 323 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 324 if (!omap_plane) 325 return ERR_PTR(-ENOMEM); 326 327 omap_plane->nformats = omap_framebuffer_get_formats( 328 omap_plane->formats, ARRAY_SIZE(omap_plane->formats), 329 dss_feat_get_supported_color_modes(id)); 330 omap_plane->id = id; 331 omap_plane->name = plane_names[id]; 332 333 plane = &omap_plane->base; 334 335 omap_plane->error_irq.irqmask = error_irqs[id]; 336 omap_plane->error_irq.irq = omap_plane_error_irq; 337 omap_irq_register(dev, &omap_plane->error_irq); 338 339 ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, 340 &omap_plane_funcs, omap_plane->formats, 341 omap_plane->nformats, type); 342 if (ret < 0) 343 goto error; 344 345 drm_plane_helper_add(plane, &omap_plane_helper_funcs); 346 347 omap_plane_install_properties(plane, &plane->base); 348 349 return plane; 350 351 error: 352 omap_irq_unregister(plane->dev, &omap_plane->error_irq); 353 kfree(omap_plane); 354 return NULL; 355 } 356