1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 4 * Author: Rob Clark <rob.clark@linaro.org> 5 */ 6 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_plane_helper.h> 10 11 #include "omap_dmm_tiler.h" 12 #include "omap_drv.h" 13 14 /* 15 * plane funcs 16 */ 17 18 #define to_omap_plane(x) container_of(x, struct omap_plane, base) 19 20 struct omap_plane { 21 struct drm_plane base; 22 enum omap_plane_id id; 23 const char *name; 24 }; 25 26 static int omap_plane_prepare_fb(struct drm_plane *plane, 27 struct drm_plane_state *new_state) 28 { 29 if (!new_state->fb) 30 return 0; 31 32 return omap_framebuffer_pin(new_state->fb); 33 } 34 35 static void omap_plane_cleanup_fb(struct drm_plane *plane, 36 struct drm_plane_state *old_state) 37 { 38 if (old_state->fb) 39 omap_framebuffer_unpin(old_state->fb); 40 } 41 42 static void omap_plane_atomic_update(struct drm_plane *plane, 43 struct drm_plane_state *old_state) 44 { 45 struct omap_drm_private *priv = plane->dev->dev_private; 46 struct omap_plane *omap_plane = to_omap_plane(plane); 47 struct drm_plane_state *state = plane->state; 48 struct omap_overlay_info info; 49 int ret; 50 51 DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb); 52 53 memset(&info, 0, sizeof(info)); 54 info.rotation_type = OMAP_DSS_ROT_NONE; 55 info.rotation = DRM_MODE_ROTATE_0; 56 info.global_alpha = state->alpha >> 8; 57 info.zorder = state->normalized_zpos; 58 if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 59 info.pre_mult_alpha = 1; 60 else 61 info.pre_mult_alpha = 0; 62 63 /* update scanout: */ 64 omap_framebuffer_update_scanout(state->fb, state, &info); 65 66 DBG("%dx%d -> %dx%d (%d)", info.width, info.height, 67 info.out_width, info.out_height, 68 info.screen_width); 69 DBG("%d,%d %pad %pad", info.pos_x, info.pos_y, 70 &info.paddr, &info.p_uv_addr); 71 72 /* and finally, update omapdss: */ 73 ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info, 74 omap_crtc_timings(state->crtc), false, 75 omap_crtc_channel(state->crtc)); 76 if (ret) { 77 dev_err(plane->dev->dev, "Failed to setup plane %s\n", 78 omap_plane->name); 79 priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); 80 return; 81 } 82 83 priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true); 84 } 85 86 static void omap_plane_atomic_disable(struct drm_plane *plane, 87 struct drm_plane_state *old_state) 88 { 89 struct omap_drm_private *priv = plane->dev->dev_private; 90 struct omap_plane *omap_plane = to_omap_plane(plane); 91 92 plane->state->rotation = DRM_MODE_ROTATE_0; 93 plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY 94 ? 0 : omap_plane->id; 95 96 priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false); 97 } 98 99 static int omap_plane_atomic_check(struct drm_plane *plane, 100 struct drm_plane_state *state) 101 { 102 struct drm_crtc_state *crtc_state; 103 104 if (!state->fb) 105 return 0; 106 107 /* crtc should only be NULL when disabling (i.e., !state->fb) */ 108 if (WARN_ON(!state->crtc)) 109 return 0; 110 111 crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); 112 /* we should have a crtc state if the plane is attached to a crtc */ 113 if (WARN_ON(!crtc_state)) 114 return 0; 115 116 if (!crtc_state->enable) 117 return 0; 118 119 if (state->crtc_x < 0 || state->crtc_y < 0) 120 return -EINVAL; 121 122 if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay) 123 return -EINVAL; 124 125 if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) 126 return -EINVAL; 127 128 if (state->rotation != DRM_MODE_ROTATE_0 && 129 !omap_framebuffer_supports_rotation(state->fb)) 130 return -EINVAL; 131 132 return 0; 133 } 134 135 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { 136 .prepare_fb = omap_plane_prepare_fb, 137 .cleanup_fb = omap_plane_cleanup_fb, 138 .atomic_check = omap_plane_atomic_check, 139 .atomic_update = omap_plane_atomic_update, 140 .atomic_disable = omap_plane_atomic_disable, 141 }; 142 143 static void omap_plane_destroy(struct drm_plane *plane) 144 { 145 struct omap_plane *omap_plane = to_omap_plane(plane); 146 147 DBG("%s", omap_plane->name); 148 149 drm_plane_cleanup(plane); 150 151 kfree(omap_plane); 152 } 153 154 /* helper to install properties which are common to planes and crtcs */ 155 void omap_plane_install_properties(struct drm_plane *plane, 156 struct drm_mode_object *obj) 157 { 158 struct drm_device *dev = plane->dev; 159 struct omap_drm_private *priv = dev->dev_private; 160 161 if (priv->has_dmm) { 162 if (!plane->rotation_property) 163 drm_plane_create_rotation_property(plane, 164 DRM_MODE_ROTATE_0, 165 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | 166 DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 | 167 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); 168 169 /* Attach the rotation property also to the crtc object */ 170 if (plane->rotation_property && obj != &plane->base) 171 drm_object_attach_property(obj, plane->rotation_property, 172 DRM_MODE_ROTATE_0); 173 } 174 175 drm_object_attach_property(obj, priv->zorder_prop, 0); 176 } 177 178 static void omap_plane_reset(struct drm_plane *plane) 179 { 180 struct omap_plane *omap_plane = to_omap_plane(plane); 181 182 drm_atomic_helper_plane_reset(plane); 183 if (!plane->state) 184 return; 185 186 /* 187 * Set the zpos default depending on whether we are a primary or overlay 188 * plane. 189 */ 190 plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY 191 ? 0 : omap_plane->id; 192 } 193 194 static int omap_plane_atomic_set_property(struct drm_plane *plane, 195 struct drm_plane_state *state, 196 struct drm_property *property, 197 u64 val) 198 { 199 struct omap_drm_private *priv = plane->dev->dev_private; 200 201 if (property == priv->zorder_prop) 202 state->zpos = val; 203 else 204 return -EINVAL; 205 206 return 0; 207 } 208 209 static int omap_plane_atomic_get_property(struct drm_plane *plane, 210 const struct drm_plane_state *state, 211 struct drm_property *property, 212 u64 *val) 213 { 214 struct omap_drm_private *priv = plane->dev->dev_private; 215 216 if (property == priv->zorder_prop) 217 *val = state->zpos; 218 else 219 return -EINVAL; 220 221 return 0; 222 } 223 224 static const struct drm_plane_funcs omap_plane_funcs = { 225 .update_plane = drm_atomic_helper_update_plane, 226 .disable_plane = drm_atomic_helper_disable_plane, 227 .reset = omap_plane_reset, 228 .destroy = omap_plane_destroy, 229 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 230 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 231 .atomic_set_property = omap_plane_atomic_set_property, 232 .atomic_get_property = omap_plane_atomic_get_property, 233 }; 234 235 static const char *plane_id_to_name[] = { 236 [OMAP_DSS_GFX] = "gfx", 237 [OMAP_DSS_VIDEO1] = "vid1", 238 [OMAP_DSS_VIDEO2] = "vid2", 239 [OMAP_DSS_VIDEO3] = "vid3", 240 }; 241 242 static const enum omap_plane_id plane_idx_to_id[] = { 243 OMAP_DSS_GFX, 244 OMAP_DSS_VIDEO1, 245 OMAP_DSS_VIDEO2, 246 OMAP_DSS_VIDEO3, 247 }; 248 249 /* initialize plane */ 250 struct drm_plane *omap_plane_init(struct drm_device *dev, 251 int idx, enum drm_plane_type type, 252 u32 possible_crtcs) 253 { 254 struct omap_drm_private *priv = dev->dev_private; 255 unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc); 256 struct drm_plane *plane; 257 struct omap_plane *omap_plane; 258 enum omap_plane_id id; 259 int ret; 260 u32 nformats; 261 const u32 *formats; 262 263 if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id))) 264 return ERR_PTR(-EINVAL); 265 266 id = plane_idx_to_id[idx]; 267 268 DBG("%s: type=%d", plane_id_to_name[id], type); 269 270 omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); 271 if (!omap_plane) 272 return ERR_PTR(-ENOMEM); 273 274 formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id); 275 for (nformats = 0; formats[nformats]; ++nformats) 276 ; 277 omap_plane->id = id; 278 omap_plane->name = plane_id_to_name[id]; 279 280 plane = &omap_plane->base; 281 282 ret = drm_universal_plane_init(dev, plane, possible_crtcs, 283 &omap_plane_funcs, formats, 284 nformats, NULL, type, NULL); 285 if (ret < 0) 286 goto error; 287 288 drm_plane_helper_add(plane, &omap_plane_helper_funcs); 289 290 omap_plane_install_properties(plane, &plane->base); 291 drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1); 292 drm_plane_create_alpha_property(plane); 293 drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) | 294 BIT(DRM_MODE_BLEND_COVERAGE)); 295 296 return plane; 297 298 error: 299 dev_err(dev->dev, "%s(): could not create plane: %s\n", 300 __func__, plane_id_to_name[id]); 301 302 kfree(omap_plane); 303 return NULL; 304 } 305