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.h> 21 #include <drm/drm_atomic_helper.h> 22 #include <drm/drm_plane_helper.h> 23 24 #include "omap_dmm_tiler.h" 25 #include "omap_drv.h" 26 27 /* some hackery because omapdss has an 'enum omap_plane' (which would be 28 * better named omap_plane_id).. and compiler seems unhappy about having 29 * both a 'struct omap_plane' and 'enum omap_plane' 30 */ 31 #define omap_plane _omap_plane 32 33 /* 34 * plane funcs 35 */ 36 37 #define to_omap_plane(x) container_of(x, struct omap_plane, base) 38 39 struct omap_plane { 40 struct drm_plane base; 41 int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ 42 const char *name; 43 44 uint32_t nformats; 45 uint32_t formats[32]; 46 }; 47 48 struct omap_plane_state { 49 struct drm_plane_state base; 50 51 unsigned int zorder; 52 }; 53 54 static inline struct omap_plane_state * 55 to_omap_plane_state(struct drm_plane_state *state) 56 { 57 return container_of(state, struct omap_plane_state, base); 58 } 59 60 static int omap_plane_prepare_fb(struct drm_plane *plane, 61 struct drm_plane_state *new_state) 62 { 63 if (!new_state->fb) 64 return 0; 65 66 return omap_framebuffer_pin(new_state->fb); 67 } 68 69 static void omap_plane_cleanup_fb(struct drm_plane *plane, 70 struct drm_plane_state *old_state) 71 { 72 if (old_state->fb) 73 omap_framebuffer_unpin(old_state->fb); 74 } 75 76 static void omap_plane_atomic_update(struct drm_plane *plane, 77 struct drm_plane_state *old_state) 78 { 79 struct omap_plane *omap_plane = to_omap_plane(plane); 80 struct drm_plane_state *state = plane->state; 81 struct omap_plane_state *omap_state = to_omap_plane_state(state); 82 struct omap_overlay_info info; 83 struct omap_drm_window win; 84 int ret; 85 86 DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); 87 88 memset(&info, 0, sizeof(info)); 89 info.rotation_type = OMAP_DSS_ROT_DMA; 90 info.rotation = OMAP_DSS_ROT_0; 91 info.global_alpha = 0xff; 92 info.mirror = 0; 93 info.zorder = omap_state->zorder; 94 95 memset(&win, 0, sizeof(win)); 96 win.rotation = state->rotation; 97 win.crtc_x = state->crtc_x; 98 win.crtc_y = state->crtc_y; 99 win.crtc_w = state->crtc_w; 100 win.crtc_h = state->crtc_h; 101 102 /* 103 * src values are in Q16 fixed point, convert to integer. 104 * omap_framebuffer_update_scanout() takes adjusted src. 105 */ 106 win.src_x = state->src_x >> 16; 107 win.src_y = state->src_y >> 16; 108 109 if (drm_rotation_90_or_270(state->rotation)) { 110 win.src_w = state->src_h >> 16; 111 win.src_h = state->src_w >> 16; 112 } else { 113 win.src_w = state->src_w >> 16; 114 win.src_h = state->src_h >> 16; 115 } 116 117 /* update scanout: */ 118 omap_framebuffer_update_scanout(state->fb, &win, &info); 119 120 DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 121 info.out_width, info.out_height, 122 info.screen_width); 123 DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 124 &info.paddr, &info.p_uv_addr); 125 126 dispc_ovl_set_channel_out(omap_plane->id, 127 omap_crtc_channel(state->crtc)); 128 129 /* and finally, update omapdss: */ 130 ret = dispc_ovl_setup(omap_plane->id, &info, false, 131 omap_crtc_timings(state->crtc), false); 132 if (ret) { 133 dev_err(plane->dev->dev, "Failed to setup plane %s\n", 134 omap_plane->name); 135 dispc_ovl_enable(omap_plane->id, false); 136 return; 137 } 138 139 dispc_ovl_enable(omap_plane->id, true); 140 } 141 142 static void omap_plane_atomic_disable(struct drm_plane *plane, 143 struct drm_plane_state *old_state) 144 { 145 struct omap_plane_state *omap_state = to_omap_plane_state(plane->state); 146 struct omap_plane *omap_plane = to_omap_plane(plane); 147 148 plane->state->rotation = DRM_ROTATE_0; 149 omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 150 ? 0 : omap_plane->id; 151 152 dispc_ovl_enable(omap_plane->id, false); 153 } 154 155 static int omap_plane_atomic_check(struct drm_plane *plane, 156 struct drm_plane_state *state) 157 { 158 struct drm_crtc_state *crtc_state; 159 160 if (!state->fb) 161 return 0; 162 163 /* crtc should only be NULL when disabling (i.e., !state->fb) */ 164 if (WARN_ON(!state->crtc)) 165 return 0; 166 167 crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); 168 /* we should have a crtc state if the plane is attached to a crtc */ 169 if (WARN_ON(!crtc_state)) 170 return 0; 171 172 if (!crtc_state->enable) 173 return 0; 174 175 if (state->crtc_x < 0 || state->crtc_y < 0) 176 return -EINVAL; 177 178 if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay) 179 return -EINVAL; 180 181 if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) 182 return -EINVAL; 183 184 if (state->rotation != DRM_ROTATE_0 && 185 !omap_framebuffer_supports_rotation(state->fb)) 186 return -EINVAL; 187 188 return 0; 189 } 190 191 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 192 .prepare_fb = omap_plane_prepare_fb, 193 .cleanup_fb = omap_plane_cleanup_fb, 194 .atomic_check = omap_plane_atomic_check, 195 .atomic_update = omap_plane_atomic_update, 196 .atomic_disable = omap_plane_atomic_disable, 197 }; 198 199 static void omap_plane_destroy(struct drm_plane *plane) 200 { 201 struct omap_plane *omap_plane = to_omap_plane(plane); 202 203 DBG("%s", omap_plane->name); 204 205 drm_plane_cleanup(plane); 206 207 kfree(omap_plane); 208 } 209 210 /* helper to install properties which are common to planes and crtcs */ 211 void omap_plane_install_properties(struct drm_plane *plane, 212 struct drm_mode_object *obj) 213 { 214 struct drm_device *dev = plane->dev; 215 struct omap_drm_private *priv = dev->dev_private; 216 217 if (priv->has_dmm) { 218 if (!plane->rotation_property) 219 drm_plane_create_rotation_property(plane, 220 DRM_ROTATE_0, 221 DRM_ROTATE_0 | DRM_ROTATE_90 | 222 DRM_ROTATE_180 | DRM_ROTATE_270 | 223 DRM_REFLECT_X | DRM_REFLECT_Y); 224 225 /* Attach the rotation property also to the crtc object */ 226 if (plane->rotation_property && obj != &plane->base) 227 drm_object_attach_property(obj, plane->rotation_property, 228 DRM_ROTATE_0); 229 } 230 231 drm_object_attach_property(obj, priv->zorder_prop, 0); 232 } 233 234 static struct drm_plane_state * 235 omap_plane_atomic_duplicate_state(struct drm_plane *plane) 236 { 237 struct omap_plane_state *state; 238 struct omap_plane_state *copy; 239 240 if (WARN_ON(!plane->state)) 241 return NULL; 242 243 state = to_omap_plane_state(plane->state); 244 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 245 if (copy == NULL) 246 return NULL; 247 248 __drm_atomic_helper_plane_duplicate_state(plane, ©->base); 249 250 return ©->base; 251 } 252 253 static void omap_plane_atomic_destroy_state(struct drm_plane *plane, 254 struct drm_plane_state *state) 255 { 256 __drm_atomic_helper_plane_destroy_state(state); 257 kfree(to_omap_plane_state(state)); 258 } 259 260 static void omap_plane_reset(struct drm_plane *plane) 261 { 262 struct omap_plane *omap_plane = to_omap_plane(plane); 263 struct omap_plane_state *omap_state; 264 265 if (plane->state) { 266 omap_plane_atomic_destroy_state(plane, plane->state); 267 plane->state = NULL; 268 } 269 270 omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL); 271 if (omap_state == NULL) 272 return; 273 274 /* 275 * Set defaults depending on whether we are a primary or overlay 276 * plane. 277 */ 278 omap_state->zorder = plane->type == DRM_PLANE_TYPE_PRIMARY 279 ? 0 : omap_plane->id; 280 omap_state->base.rotation = DRM_ROTATE_0; 281 282 plane->state = &omap_state->base; 283 plane->state->plane = plane; 284 } 285 286 static int omap_plane_atomic_set_property(struct drm_plane *plane, 287 struct drm_plane_state *state, 288 struct drm_property *property, 289 uint64_t val) 290 { 291 struct omap_drm_private *priv = plane->dev->dev_private; 292 struct omap_plane_state *omap_state = to_omap_plane_state(state); 293 294 if (property == priv->zorder_prop) 295 omap_state->zorder = val; 296 else 297 return -EINVAL; 298 299 return 0; 300 } 301 302 static int omap_plane_atomic_get_property(struct drm_plane *plane, 303 const struct drm_plane_state *state, 304 struct drm_property *property, 305 uint64_t *val) 306 { 307 struct omap_drm_private *priv = plane->dev->dev_private; 308 const struct omap_plane_state *omap_state = 309 container_of(state, const struct omap_plane_state, base); 310 311 if (property == priv->zorder_prop) 312 *val = omap_state->zorder; 313 else 314 return -EINVAL; 315 316 return 0; 317 } 318 319 static const struct drm_plane_funcs omap_plane_funcs = { 320 .update_plane = drm_atomic_helper_update_plane, 321 .disable_plane = drm_atomic_helper_disable_plane, 322 .reset = omap_plane_reset, 323 .destroy = omap_plane_destroy, 324 .set_property = drm_atomic_helper_plane_set_property, 325 .atomic_duplicate_state = omap_plane_atomic_duplicate_state, 326 .atomic_destroy_state = omap_plane_atomic_destroy_state, 327 .atomic_set_property = omap_plane_atomic_set_property, 328 .atomic_get_property = omap_plane_atomic_get_property, 329 }; 330 331 static const char *plane_names[] = { 332 [OMAP_DSS_GFX] = "gfx", 333 [OMAP_DSS_VIDEO1] = "vid1", 334 [OMAP_DSS_VIDEO2] = "vid2", 335 [OMAP_DSS_VIDEO3] = "vid3", 336 }; 337 338 /* initialize plane */ 339 struct drm_plane *omap_plane_init(struct drm_device *dev, 340 int id, enum drm_plane_type type, 341 u32 possible_crtcs) 342 { 343 struct drm_plane *plane; 344 struct omap_plane *omap_plane; 345 int ret; 346 347 DBG("%s: type=%d", plane_names[id], type); 348 349 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 350 if (!omap_plane) 351 return ERR_PTR(-ENOMEM); 352 353 omap_plane->nformats = omap_framebuffer_get_formats( 354 omap_plane->formats, ARRAY_SIZE(omap_plane->formats), 355 dss_feat_get_supported_color_modes(id)); 356 omap_plane->id = id; 357 omap_plane->name = plane_names[id]; 358 359 plane = &omap_plane->base; 360 361 ret = drm_universal_plane_init(dev, plane, possible_crtcs, 362 &omap_plane_funcs, omap_plane->formats, 363 omap_plane->nformats, type, NULL); 364 if (ret < 0) 365 goto error; 366 367 drm_plane_helper_add(plane, &omap_plane_helper_funcs); 368 369 omap_plane_install_properties(plane, &plane->base); 370 371 return plane; 372 373 error: 374 kfree(omap_plane); 375 return NULL; 376 } 377