0001
0002
0003
0004
0005
0006
0007 #include <drm/drm_atomic.h>
0008 #include <drm/drm_atomic_helper.h>
0009 #include <drm/drm_blend.h>
0010 #include <drm/drm_gem_atomic_helper.h>
0011 #include <drm/drm_plane_helper.h>
0012 #include <drm/drm_fourcc.h>
0013 #include <drm/drm_framebuffer.h>
0014
0015 #include "omap_dmm_tiler.h"
0016 #include "omap_drv.h"
0017
0018
0019
0020
0021
0022 #define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base)
0023
0024 struct omap_plane_state {
0025
0026 struct drm_plane_state base;
0027
0028 struct omap_hw_overlay *overlay;
0029 struct omap_hw_overlay *r_overlay;
0030 };
0031
0032 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
0033
0034 struct omap_plane {
0035 struct drm_plane base;
0036 enum omap_plane_id id;
0037 };
0038
0039 bool is_omap_plane_dual_overlay(struct drm_plane_state *state)
0040 {
0041 struct omap_plane_state *omap_state = to_omap_plane_state(state);
0042
0043 return !!omap_state->r_overlay;
0044 }
0045
0046 static int omap_plane_prepare_fb(struct drm_plane *plane,
0047 struct drm_plane_state *new_state)
0048 {
0049 if (!new_state->fb)
0050 return 0;
0051
0052 drm_gem_plane_helper_prepare_fb(plane, new_state);
0053
0054 return omap_framebuffer_pin(new_state->fb);
0055 }
0056
0057 static void omap_plane_cleanup_fb(struct drm_plane *plane,
0058 struct drm_plane_state *old_state)
0059 {
0060 if (old_state->fb)
0061 omap_framebuffer_unpin(old_state->fb);
0062 }
0063
0064 static void omap_plane_atomic_update(struct drm_plane *plane,
0065 struct drm_atomic_state *state)
0066 {
0067 struct omap_drm_private *priv = plane->dev->dev_private;
0068 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0069 plane);
0070 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0071 plane);
0072 struct omap_plane_state *new_omap_state;
0073 struct omap_plane_state *old_omap_state;
0074 struct omap_overlay_info info, r_info;
0075 enum omap_plane_id ovl_id, r_ovl_id;
0076 int ret;
0077 bool dual_ovl;
0078
0079 new_omap_state = to_omap_plane_state(new_state);
0080 old_omap_state = to_omap_plane_state(old_state);
0081
0082 dual_ovl = is_omap_plane_dual_overlay(new_state);
0083
0084
0085 if (old_omap_state->overlay)
0086 omap_overlay_update_state(priv, old_omap_state->overlay);
0087 if (old_omap_state->r_overlay)
0088 omap_overlay_update_state(priv, old_omap_state->r_overlay);
0089
0090 if (!new_omap_state->overlay) {
0091 DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name);
0092 return;
0093 }
0094
0095 ovl_id = new_omap_state->overlay->id;
0096 DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc,
0097 new_state->fb);
0098
0099 memset(&info, 0, sizeof(info));
0100 info.rotation_type = OMAP_DSS_ROT_NONE;
0101 info.rotation = DRM_MODE_ROTATE_0;
0102 info.global_alpha = new_state->alpha >> 8;
0103 info.zorder = new_state->normalized_zpos;
0104 if (new_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
0105 info.pre_mult_alpha = 1;
0106 else
0107 info.pre_mult_alpha = 0;
0108 info.color_encoding = new_state->color_encoding;
0109 info.color_range = new_state->color_range;
0110
0111 r_info = info;
0112
0113
0114 omap_framebuffer_update_scanout(new_state->fb, new_state, &info,
0115 dual_ovl ? &r_info : NULL);
0116
0117 DBG("%s: %dx%d -> %dx%d (%d)",
0118 new_omap_state->overlay->name, info.width, info.height,
0119 info.out_width, info.out_height, info.screen_width);
0120 DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
0121 &info.paddr, &info.p_uv_addr);
0122
0123 if (dual_ovl) {
0124 r_ovl_id = new_omap_state->r_overlay->id;
0125
0126
0127
0128
0129
0130 r_info.zorder = info.zorder + 1;
0131
0132 DBG("%s: %dx%d -> %dx%d (%d)",
0133 new_omap_state->r_overlay->name,
0134 r_info.width, r_info.height,
0135 r_info.out_width, r_info.out_height, r_info.screen_width);
0136 DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y,
0137 &r_info.paddr, &r_info.p_uv_addr);
0138 }
0139
0140
0141 ret = dispc_ovl_setup(priv->dispc, ovl_id, &info,
0142 omap_crtc_timings(new_state->crtc), false,
0143 omap_crtc_channel(new_state->crtc));
0144 if (ret) {
0145 dev_err(plane->dev->dev, "Failed to setup plane %s\n",
0146 plane->name);
0147 dispc_ovl_enable(priv->dispc, ovl_id, false);
0148 return;
0149 }
0150
0151 dispc_ovl_enable(priv->dispc, ovl_id, true);
0152
0153 if (dual_ovl) {
0154 ret = dispc_ovl_setup(priv->dispc, r_ovl_id, &r_info,
0155 omap_crtc_timings(new_state->crtc), false,
0156 omap_crtc_channel(new_state->crtc));
0157 if (ret) {
0158 dev_err(plane->dev->dev, "Failed to setup plane right-overlay %s\n",
0159 plane->name);
0160 dispc_ovl_enable(priv->dispc, r_ovl_id, false);
0161 dispc_ovl_enable(priv->dispc, ovl_id, false);
0162 return;
0163 }
0164
0165 dispc_ovl_enable(priv->dispc, r_ovl_id, true);
0166 }
0167 }
0168
0169 static void omap_plane_atomic_disable(struct drm_plane *plane,
0170 struct drm_atomic_state *state)
0171 {
0172 struct omap_drm_private *priv = plane->dev->dev_private;
0173 struct omap_plane *omap_plane = to_omap_plane(plane);
0174 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0175 plane);
0176 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0177 plane);
0178 struct omap_plane_state *new_omap_state;
0179 struct omap_plane_state *old_omap_state;
0180
0181 new_omap_state = to_omap_plane_state(new_state);
0182 old_omap_state = to_omap_plane_state(old_state);
0183
0184 if (!old_omap_state->overlay)
0185 return;
0186
0187 new_state->rotation = DRM_MODE_ROTATE_0;
0188 new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id;
0189
0190 omap_overlay_update_state(priv, old_omap_state->overlay);
0191 new_omap_state->overlay = NULL;
0192
0193 if (is_omap_plane_dual_overlay(old_state)) {
0194 omap_overlay_update_state(priv, old_omap_state->r_overlay);
0195 new_omap_state->r_overlay = NULL;
0196 }
0197 }
0198
0199 #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
0200
0201 static int omap_plane_atomic_check(struct drm_plane *plane,
0202 struct drm_atomic_state *state)
0203 {
0204 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0205 plane);
0206 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
0207 plane);
0208 struct omap_drm_private *priv = plane->dev->dev_private;
0209 struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state);
0210 struct omap_global_state *omap_overlay_global_state;
0211 struct drm_crtc_state *crtc_state;
0212 bool new_r_hw_overlay = false;
0213 bool new_hw_overlay = false;
0214 u32 max_width, max_height;
0215 struct drm_crtc *crtc;
0216 u16 width, height;
0217 u32 caps = 0;
0218 u32 fourcc;
0219 int ret;
0220
0221 omap_overlay_global_state = omap_get_global_state(state);
0222 if (IS_ERR(omap_overlay_global_state))
0223 return PTR_ERR(omap_overlay_global_state);
0224
0225 dispc_ovl_get_max_size(priv->dispc, &width, &height);
0226 max_width = width << 16;
0227 max_height = height << 16;
0228
0229 crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc;
0230 if (!crtc)
0231 return 0;
0232
0233 crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
0234
0235 if (WARN_ON(!crtc_state))
0236 return 0;
0237
0238
0239
0240
0241
0242
0243
0244 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
0245 FRAC_16_16(1, 8), FRAC_16_16(8, 1),
0246 true, true);
0247 if (ret)
0248 return ret;
0249
0250 DBG("%s: visible %d -> %d", plane->name,
0251 old_plane_state->visible, new_plane_state->visible);
0252
0253 if (!new_plane_state->visible) {
0254 omap_overlay_release(state, omap_state->overlay);
0255 omap_overlay_release(state, omap_state->r_overlay);
0256 omap_state->overlay = NULL;
0257 omap_state->r_overlay = NULL;
0258 return 0;
0259 }
0260
0261 if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0)
0262 return -EINVAL;
0263
0264 if (new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->adjusted_mode.hdisplay)
0265 return -EINVAL;
0266
0267 if (new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->adjusted_mode.vdisplay)
0268 return -EINVAL;
0269
0270
0271 if (new_plane_state->src_h > max_height || new_plane_state->crtc_h > height)
0272 return -EINVAL;
0273
0274
0275 if (new_plane_state->src_w > max_width || new_plane_state->crtc_w > width) {
0276 bool is_fourcc_yuv = new_plane_state->fb->format->is_yuv;
0277
0278 if (is_fourcc_yuv && (((new_plane_state->src_w >> 16) / 2 & 1) ||
0279 new_plane_state->crtc_w / 2 & 1)) {
0280
0281
0282
0283
0284
0285 if (new_plane_state->src_w <= ((2 * width - 1) << 16) &&
0286 new_plane_state->crtc_w <= (2 * width - 1))
0287 new_r_hw_overlay = true;
0288 else
0289 return -EINVAL;
0290 } else {
0291 if (new_plane_state->src_w <= (2 * max_width) &&
0292 new_plane_state->crtc_w <= (2 * width))
0293 new_r_hw_overlay = true;
0294 else
0295 return -EINVAL;
0296 }
0297 }
0298
0299 if (new_plane_state->rotation != DRM_MODE_ROTATE_0 &&
0300 !omap_framebuffer_supports_rotation(new_plane_state->fb))
0301 return -EINVAL;
0302
0303 if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w ||
0304 (new_plane_state->src_h >> 16) != new_plane_state->crtc_h)
0305 caps |= OMAP_DSS_OVL_CAP_SCALE;
0306
0307 fourcc = new_plane_state->fb->format->format;
0308
0309
0310
0311
0312
0313 if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) {
0314 new_hw_overlay = true;
0315 } else {
0316
0317 if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id,
0318 fourcc))
0319 new_hw_overlay = true;
0320 }
0321
0322
0323
0324
0325
0326 if ((new_r_hw_overlay && !omap_state->r_overlay) ||
0327 (!new_r_hw_overlay && omap_state->r_overlay))
0328 new_hw_overlay = true;
0329
0330 if (new_hw_overlay) {
0331 struct omap_hw_overlay *old_ovl = omap_state->overlay;
0332 struct omap_hw_overlay *old_r_ovl = omap_state->r_overlay;
0333 struct omap_hw_overlay *new_ovl = NULL;
0334 struct omap_hw_overlay *new_r_ovl = NULL;
0335
0336 omap_overlay_release(state, old_ovl);
0337 omap_overlay_release(state, old_r_ovl);
0338
0339 ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl,
0340 new_r_hw_overlay ? &new_r_ovl : NULL);
0341 if (ret) {
0342 DBG("%s: failed to assign hw_overlay", plane->name);
0343 omap_state->overlay = NULL;
0344 omap_state->r_overlay = NULL;
0345 return ret;
0346 }
0347
0348 omap_state->overlay = new_ovl;
0349 if (new_r_hw_overlay)
0350 omap_state->r_overlay = new_r_ovl;
0351 else
0352 omap_state->r_overlay = NULL;
0353 }
0354
0355 DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id);
0356
0357 if (omap_state->r_overlay)
0358 DBG("plane: %s r_overlay_id: %d", plane->name, omap_state->r_overlay->id);
0359
0360 return 0;
0361 }
0362
0363 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
0364 .prepare_fb = omap_plane_prepare_fb,
0365 .cleanup_fb = omap_plane_cleanup_fb,
0366 .atomic_check = omap_plane_atomic_check,
0367 .atomic_update = omap_plane_atomic_update,
0368 .atomic_disable = omap_plane_atomic_disable,
0369 };
0370
0371 static void omap_plane_destroy(struct drm_plane *plane)
0372 {
0373 struct omap_plane *omap_plane = to_omap_plane(plane);
0374
0375 DBG("%s", plane->name);
0376
0377 drm_plane_cleanup(plane);
0378
0379 kfree(omap_plane);
0380 }
0381
0382
0383 void omap_plane_install_properties(struct drm_plane *plane,
0384 struct drm_mode_object *obj)
0385 {
0386 struct drm_device *dev = plane->dev;
0387 struct omap_drm_private *priv = dev->dev_private;
0388
0389 if (priv->has_dmm) {
0390 if (!plane->rotation_property)
0391 drm_plane_create_rotation_property(plane,
0392 DRM_MODE_ROTATE_0,
0393 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
0394 DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
0395 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
0396
0397
0398 if (plane->rotation_property && obj != &plane->base)
0399 drm_object_attach_property(obj, plane->rotation_property,
0400 DRM_MODE_ROTATE_0);
0401 }
0402
0403 drm_object_attach_property(obj, priv->zorder_prop, 0);
0404 }
0405
0406 static void omap_plane_reset(struct drm_plane *plane)
0407 {
0408 struct omap_plane_state *omap_state;
0409
0410 if (plane->state)
0411 drm_atomic_helper_plane_destroy_state(plane, plane->state);
0412
0413 omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
0414 if (!omap_state)
0415 return;
0416
0417 __drm_atomic_helper_plane_reset(plane, &omap_state->base);
0418 }
0419
0420 static struct drm_plane_state *
0421 omap_plane_atomic_duplicate_state(struct drm_plane *plane)
0422 {
0423 struct omap_plane_state *state, *current_state;
0424
0425 if (WARN_ON(!plane->state))
0426 return NULL;
0427
0428 current_state = to_omap_plane_state(plane->state);
0429
0430 state = kmalloc(sizeof(*state), GFP_KERNEL);
0431 if (!state)
0432 return NULL;
0433
0434 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
0435
0436 state->overlay = current_state->overlay;
0437 state->r_overlay = current_state->r_overlay;
0438
0439 return &state->base;
0440 }
0441
0442 static void omap_plane_atomic_print_state(struct drm_printer *p,
0443 const struct drm_plane_state *state)
0444 {
0445 struct omap_plane_state *omap_state = to_omap_plane_state(state);
0446
0447 if (omap_state->overlay)
0448 drm_printf(p, "\toverlay=%s (caps=0x%x)\n",
0449 omap_state->overlay->name,
0450 omap_state->overlay->caps);
0451 else
0452 drm_printf(p, "\toverlay=None\n");
0453 if (omap_state->r_overlay)
0454 drm_printf(p, "\tr_overlay=%s (caps=0x%x)\n",
0455 omap_state->r_overlay->name,
0456 omap_state->r_overlay->caps);
0457 else
0458 drm_printf(p, "\tr_overlay=None\n");
0459 }
0460
0461 static int omap_plane_atomic_set_property(struct drm_plane *plane,
0462 struct drm_plane_state *state,
0463 struct drm_property *property,
0464 u64 val)
0465 {
0466 struct omap_drm_private *priv = plane->dev->dev_private;
0467
0468 if (property == priv->zorder_prop)
0469 state->zpos = val;
0470 else
0471 return -EINVAL;
0472
0473 return 0;
0474 }
0475
0476 static int omap_plane_atomic_get_property(struct drm_plane *plane,
0477 const struct drm_plane_state *state,
0478 struct drm_property *property,
0479 u64 *val)
0480 {
0481 struct omap_drm_private *priv = plane->dev->dev_private;
0482
0483 if (property == priv->zorder_prop)
0484 *val = state->zpos;
0485 else
0486 return -EINVAL;
0487
0488 return 0;
0489 }
0490
0491 static const struct drm_plane_funcs omap_plane_funcs = {
0492 .update_plane = drm_atomic_helper_update_plane,
0493 .disable_plane = drm_atomic_helper_disable_plane,
0494 .reset = omap_plane_reset,
0495 .destroy = omap_plane_destroy,
0496 .atomic_duplicate_state = omap_plane_atomic_duplicate_state,
0497 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0498 .atomic_set_property = omap_plane_atomic_set_property,
0499 .atomic_get_property = omap_plane_atomic_get_property,
0500 .atomic_print_state = omap_plane_atomic_print_state,
0501 };
0502
0503 static bool omap_plane_supports_yuv(struct drm_plane *plane)
0504 {
0505 struct omap_drm_private *priv = plane->dev->dev_private;
0506 struct omap_plane *omap_plane = to_omap_plane(plane);
0507 const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
0508 u32 i;
0509
0510 for (i = 0; formats[i]; i++)
0511 if (formats[i] == DRM_FORMAT_YUYV ||
0512 formats[i] == DRM_FORMAT_UYVY ||
0513 formats[i] == DRM_FORMAT_NV12)
0514 return true;
0515
0516 return false;
0517 }
0518
0519
0520 struct drm_plane *omap_plane_init(struct drm_device *dev,
0521 int idx, enum drm_plane_type type,
0522 u32 possible_crtcs)
0523 {
0524 struct omap_drm_private *priv = dev->dev_private;
0525 unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
0526 struct drm_plane *plane;
0527 struct omap_plane *omap_plane;
0528 unsigned int zpos;
0529 int ret;
0530 u32 nformats;
0531 const u32 *formats;
0532
0533 if (WARN_ON(idx >= num_planes))
0534 return ERR_PTR(-EINVAL);
0535
0536 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
0537 if (!omap_plane)
0538 return ERR_PTR(-ENOMEM);
0539
0540 omap_plane->id = idx;
0541
0542 DBG("%d: type=%d", omap_plane->id, type);
0543 DBG(" crtc_mask: 0x%04x", possible_crtcs);
0544
0545 formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
0546 for (nformats = 0; formats[nformats]; ++nformats)
0547 ;
0548
0549 plane = &omap_plane->base;
0550
0551 ret = drm_universal_plane_init(dev, plane, possible_crtcs,
0552 &omap_plane_funcs, formats,
0553 nformats, NULL, type, NULL);
0554 if (ret < 0)
0555 goto error;
0556
0557 drm_plane_helper_add(plane, &omap_plane_helper_funcs);
0558
0559 omap_plane_install_properties(plane, &plane->base);
0560
0561
0562
0563
0564
0565 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
0566 zpos = 0;
0567 else
0568 zpos = omap_plane->id;
0569 drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1);
0570 drm_plane_create_alpha_property(plane);
0571 drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
0572 BIT(DRM_MODE_BLEND_COVERAGE));
0573
0574 if (omap_plane_supports_yuv(plane))
0575 drm_plane_create_color_properties(plane,
0576 BIT(DRM_COLOR_YCBCR_BT601) |
0577 BIT(DRM_COLOR_YCBCR_BT709),
0578 BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
0579 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
0580 DRM_COLOR_YCBCR_BT601,
0581 DRM_COLOR_YCBCR_FULL_RANGE);
0582
0583 return plane;
0584
0585 error:
0586 dev_err(dev->dev, "%s(): could not create plane: %d\n",
0587 __func__, omap_plane->id);
0588
0589 kfree(omap_plane);
0590 return NULL;
0591 }