Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.9-rc3 483 lines 13 kB view raw
1/* 2 * i.MX IPUv3 DP Overlay Planes 3 * 4 * Copyright (C) 2013 Philipp Zabel, Pengutronix 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16#include <drm/drmP.h> 17#include <drm/drm_atomic.h> 18#include <drm/drm_atomic_helper.h> 19#include <drm/drm_fb_cma_helper.h> 20#include <drm/drm_gem_cma_helper.h> 21#include <drm/drm_plane_helper.h> 22 23#include "video/imx-ipu-v3.h" 24#include "ipuv3-plane.h" 25 26static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) 27{ 28 return container_of(p, struct ipu_plane, base); 29} 30 31static const uint32_t ipu_plane_formats[] = { 32 DRM_FORMAT_ARGB1555, 33 DRM_FORMAT_XRGB1555, 34 DRM_FORMAT_ABGR1555, 35 DRM_FORMAT_XBGR1555, 36 DRM_FORMAT_RGBA5551, 37 DRM_FORMAT_BGRA5551, 38 DRM_FORMAT_ARGB4444, 39 DRM_FORMAT_ARGB8888, 40 DRM_FORMAT_XRGB8888, 41 DRM_FORMAT_ABGR8888, 42 DRM_FORMAT_XBGR8888, 43 DRM_FORMAT_RGBA8888, 44 DRM_FORMAT_RGBX8888, 45 DRM_FORMAT_BGRA8888, 46 DRM_FORMAT_BGRA8888, 47 DRM_FORMAT_UYVY, 48 DRM_FORMAT_VYUY, 49 DRM_FORMAT_YUYV, 50 DRM_FORMAT_YVYU, 51 DRM_FORMAT_YUV420, 52 DRM_FORMAT_YVU420, 53 DRM_FORMAT_RGB565, 54}; 55 56int ipu_plane_irq(struct ipu_plane *ipu_plane) 57{ 58 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch, 59 IPU_IRQ_EOF); 60} 61 62static inline unsigned long 63drm_plane_state_to_eba(struct drm_plane_state *state) 64{ 65 struct drm_framebuffer *fb = state->fb; 66 struct drm_gem_cma_object *cma_obj; 67 68 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 69 BUG_ON(!cma_obj); 70 71 return cma_obj->paddr + fb->offsets[0] + 72 fb->pitches[0] * (state->src_y >> 16) + 73 (fb->bits_per_pixel >> 3) * (state->src_x >> 16); 74} 75 76static inline unsigned long 77drm_plane_state_to_ubo(struct drm_plane_state *state) 78{ 79 struct drm_framebuffer *fb = state->fb; 80 struct drm_gem_cma_object *cma_obj; 81 unsigned long eba = drm_plane_state_to_eba(state); 82 83 cma_obj = drm_fb_cma_get_gem_obj(fb, 1); 84 BUG_ON(!cma_obj); 85 86 return cma_obj->paddr + fb->offsets[1] + 87 fb->pitches[1] * (state->src_y >> 16) / 2 + 88 (state->src_x >> 16) / 2 - eba; 89} 90 91static inline unsigned long 92drm_plane_state_to_vbo(struct drm_plane_state *state) 93{ 94 struct drm_framebuffer *fb = state->fb; 95 struct drm_gem_cma_object *cma_obj; 96 unsigned long eba = drm_plane_state_to_eba(state); 97 98 cma_obj = drm_fb_cma_get_gem_obj(fb, 2); 99 BUG_ON(!cma_obj); 100 101 return cma_obj->paddr + fb->offsets[2] + 102 fb->pitches[2] * (state->src_y >> 16) / 2 + 103 (state->src_x >> 16) / 2 - eba; 104} 105 106static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane, 107 struct drm_plane_state *old_state) 108{ 109 struct drm_plane *plane = &ipu_plane->base; 110 struct drm_plane_state *state = plane->state; 111 struct drm_framebuffer *fb = state->fb; 112 unsigned long eba, ubo, vbo; 113 int active; 114 115 eba = drm_plane_state_to_eba(state); 116 117 switch (fb->pixel_format) { 118 case DRM_FORMAT_YUV420: 119 case DRM_FORMAT_YVU420: 120 if (old_state->fb) 121 break; 122 123 /* 124 * Multiplanar formats have to meet the following restrictions: 125 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO 126 * - EBA, UBO and VBO are a multiple of 8 127 * - UBO and VBO are unsigned and not larger than 0xfffff8 128 * - Only EBA may be changed while scanout is active 129 * - The strides of U and V planes must be identical. 130 */ 131 ubo = drm_plane_state_to_ubo(state); 132 vbo = drm_plane_state_to_vbo(state); 133 134 if (fb->pixel_format == DRM_FORMAT_YUV420) 135 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, 136 fb->pitches[1], ubo, vbo); 137 else 138 ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch, 139 fb->pitches[1], vbo, ubo); 140 141 dev_dbg(ipu_plane->base.dev->dev, 142 "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, 143 state->src_x >> 16, state->src_y >> 16); 144 break; 145 default: 146 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", 147 eba, state->src_x >> 16, state->src_y >> 16); 148 149 break; 150 } 151 152 if (old_state->fb) { 153 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); 154 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); 155 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); 156 } else { 157 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); 158 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); 159 } 160} 161 162void ipu_plane_put_resources(struct ipu_plane *ipu_plane) 163{ 164 if (!IS_ERR_OR_NULL(ipu_plane->dp)) 165 ipu_dp_put(ipu_plane->dp); 166 if (!IS_ERR_OR_NULL(ipu_plane->dmfc)) 167 ipu_dmfc_put(ipu_plane->dmfc); 168 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch)) 169 ipu_idmac_put(ipu_plane->ipu_ch); 170} 171 172int ipu_plane_get_resources(struct ipu_plane *ipu_plane) 173{ 174 int ret; 175 176 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma); 177 if (IS_ERR(ipu_plane->ipu_ch)) { 178 ret = PTR_ERR(ipu_plane->ipu_ch); 179 DRM_ERROR("failed to get idmac channel: %d\n", ret); 180 return ret; 181 } 182 183 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma); 184 if (IS_ERR(ipu_plane->dmfc)) { 185 ret = PTR_ERR(ipu_plane->dmfc); 186 DRM_ERROR("failed to get dmfc: ret %d\n", ret); 187 goto err_out; 188 } 189 190 if (ipu_plane->dp_flow >= 0) { 191 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow); 192 if (IS_ERR(ipu_plane->dp)) { 193 ret = PTR_ERR(ipu_plane->dp); 194 DRM_ERROR("failed to get dp flow: %d\n", ret); 195 goto err_out; 196 } 197 } 198 199 return 0; 200err_out: 201 ipu_plane_put_resources(ipu_plane); 202 203 return ret; 204} 205 206static void ipu_plane_enable(struct ipu_plane *ipu_plane) 207{ 208 if (ipu_plane->dp) 209 ipu_dp_enable(ipu_plane->ipu); 210 ipu_dmfc_enable_channel(ipu_plane->dmfc); 211 ipu_idmac_enable_channel(ipu_plane->ipu_ch); 212 if (ipu_plane->dp) 213 ipu_dp_enable_channel(ipu_plane->dp); 214} 215 216static int ipu_disable_plane(struct drm_plane *plane) 217{ 218 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 219 220 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 221 222 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); 223 224 if (ipu_plane->dp) 225 ipu_dp_disable_channel(ipu_plane->dp); 226 ipu_idmac_disable_channel(ipu_plane->ipu_ch); 227 ipu_dmfc_disable_channel(ipu_plane->dmfc); 228 if (ipu_plane->dp) 229 ipu_dp_disable(ipu_plane->ipu); 230 231 return 0; 232} 233 234static void ipu_plane_destroy(struct drm_plane *plane) 235{ 236 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 237 238 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 239 240 drm_plane_cleanup(plane); 241 kfree(ipu_plane); 242} 243 244static const struct drm_plane_funcs ipu_plane_funcs = { 245 .update_plane = drm_atomic_helper_update_plane, 246 .disable_plane = drm_atomic_helper_disable_plane, 247 .destroy = ipu_plane_destroy, 248 .reset = drm_atomic_helper_plane_reset, 249 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 250 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 251}; 252 253static int ipu_plane_atomic_check(struct drm_plane *plane, 254 struct drm_plane_state *state) 255{ 256 struct drm_plane_state *old_state = plane->state; 257 struct drm_crtc_state *crtc_state; 258 struct device *dev = plane->dev->dev; 259 struct drm_framebuffer *fb = state->fb; 260 struct drm_framebuffer *old_fb = old_state->fb; 261 unsigned long eba, ubo, vbo, old_ubo, old_vbo; 262 263 /* Ok to disable */ 264 if (!fb) 265 return 0; 266 267 if (!state->crtc) 268 return -EINVAL; 269 270 crtc_state = 271 drm_atomic_get_existing_crtc_state(state->state, state->crtc); 272 if (WARN_ON(!crtc_state)) 273 return -EINVAL; 274 275 /* CRTC should be enabled */ 276 if (!crtc_state->enable) 277 return -EINVAL; 278 279 /* no scaling */ 280 if (state->src_w >> 16 != state->crtc_w || 281 state->src_h >> 16 != state->crtc_h) 282 return -EINVAL; 283 284 switch (plane->type) { 285 case DRM_PLANE_TYPE_PRIMARY: 286 /* full plane doesn't support partial off screen */ 287 if (state->crtc_x || state->crtc_y || 288 state->crtc_w != crtc_state->adjusted_mode.hdisplay || 289 state->crtc_h != crtc_state->adjusted_mode.vdisplay) 290 return -EINVAL; 291 292 /* full plane minimum width is 13 pixels */ 293 if (state->crtc_w < 13) 294 return -EINVAL; 295 break; 296 case DRM_PLANE_TYPE_OVERLAY: 297 if (state->crtc_x < 0 || state->crtc_y < 0) 298 return -EINVAL; 299 300 if (state->crtc_x + state->crtc_w > 301 crtc_state->adjusted_mode.hdisplay) 302 return -EINVAL; 303 if (state->crtc_y + state->crtc_h > 304 crtc_state->adjusted_mode.vdisplay) 305 return -EINVAL; 306 break; 307 default: 308 dev_warn(dev, "Unsupported plane type\n"); 309 return -EINVAL; 310 } 311 312 if (state->crtc_h < 2) 313 return -EINVAL; 314 315 /* 316 * We support resizing active plane or changing its format by 317 * forcing CRTC mode change in plane's ->atomic_check callback 318 * and disabling all affected active planes in CRTC's ->atomic_disable 319 * callback. The planes will be reenabled in plane's ->atomic_update 320 * callback. 321 */ 322 if (old_fb && (state->src_w != old_state->src_w || 323 state->src_h != old_state->src_h || 324 fb->pixel_format != old_fb->pixel_format)) 325 crtc_state->mode_changed = true; 326 327 eba = drm_plane_state_to_eba(state); 328 329 if (eba & 0x7) 330 return -EINVAL; 331 332 if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) 333 return -EINVAL; 334 335 if (old_fb && fb->pitches[0] != old_fb->pitches[0]) 336 crtc_state->mode_changed = true; 337 338 switch (fb->pixel_format) { 339 case DRM_FORMAT_YUV420: 340 case DRM_FORMAT_YVU420: 341 /* 342 * Multiplanar formats have to meet the following restrictions: 343 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO 344 * - EBA, UBO and VBO are a multiple of 8 345 * - UBO and VBO are unsigned and not larger than 0xfffff8 346 * - Only EBA may be changed while scanout is active 347 * - The strides of U and V planes must be identical. 348 */ 349 ubo = drm_plane_state_to_ubo(state); 350 vbo = drm_plane_state_to_vbo(state); 351 352 if ((ubo & 0x7) || (vbo & 0x7)) 353 return -EINVAL; 354 355 if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) 356 return -EINVAL; 357 358 if (old_fb) { 359 old_ubo = drm_plane_state_to_ubo(old_state); 360 old_vbo = drm_plane_state_to_vbo(old_state); 361 if (ubo != old_ubo || vbo != old_vbo) 362 return -EINVAL; 363 } 364 365 if (fb->pitches[1] != fb->pitches[2]) 366 return -EINVAL; 367 368 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) 369 return -EINVAL; 370 371 if (old_fb && old_fb->pitches[1] != fb->pitches[1]) 372 crtc_state->mode_changed = true; 373 } 374 375 return 0; 376} 377 378static void ipu_plane_atomic_disable(struct drm_plane *plane, 379 struct drm_plane_state *old_state) 380{ 381 ipu_disable_plane(plane); 382} 383 384static void ipu_plane_atomic_update(struct drm_plane *plane, 385 struct drm_plane_state *old_state) 386{ 387 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 388 struct drm_plane_state *state = plane->state; 389 enum ipu_color_space ics; 390 391 if (old_state->fb) { 392 struct drm_crtc_state *crtc_state = state->crtc->state; 393 394 if (!drm_atomic_crtc_needs_modeset(crtc_state)) { 395 ipu_plane_atomic_set_base(ipu_plane, old_state); 396 return; 397 } 398 } 399 400 switch (ipu_plane->dp_flow) { 401 case IPU_DP_FLOW_SYNC_BG: 402 ipu_dp_setup_channel(ipu_plane->dp, 403 IPUV3_COLORSPACE_RGB, 404 IPUV3_COLORSPACE_RGB); 405 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); 406 break; 407 case IPU_DP_FLOW_SYNC_FG: 408 ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format); 409 ipu_dp_setup_channel(ipu_plane->dp, ics, 410 IPUV3_COLORSPACE_UNKNOWN); 411 ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x, 412 state->crtc_y); 413 /* Enable local alpha on partial plane */ 414 switch (state->fb->pixel_format) { 415 case DRM_FORMAT_ARGB1555: 416 case DRM_FORMAT_ABGR1555: 417 case DRM_FORMAT_RGBA5551: 418 case DRM_FORMAT_BGRA5551: 419 case DRM_FORMAT_ARGB4444: 420 case DRM_FORMAT_ARGB8888: 421 case DRM_FORMAT_ABGR8888: 422 case DRM_FORMAT_RGBA8888: 423 case DRM_FORMAT_BGRA8888: 424 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); 425 break; 426 default: 427 break; 428 } 429 } 430 431 ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w); 432 433 ipu_cpmem_zero(ipu_plane->ipu_ch); 434 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16, 435 state->src_h >> 16); 436 ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format); 437 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); 438 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); 439 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); 440 ipu_plane_atomic_set_base(ipu_plane, old_state); 441 ipu_plane_enable(ipu_plane); 442} 443 444static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { 445 .atomic_check = ipu_plane_atomic_check, 446 .atomic_disable = ipu_plane_atomic_disable, 447 .atomic_update = ipu_plane_atomic_update, 448}; 449 450struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, 451 int dma, int dp, unsigned int possible_crtcs, 452 enum drm_plane_type type) 453{ 454 struct ipu_plane *ipu_plane; 455 int ret; 456 457 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", 458 dma, dp, possible_crtcs); 459 460 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL); 461 if (!ipu_plane) { 462 DRM_ERROR("failed to allocate plane\n"); 463 return ERR_PTR(-ENOMEM); 464 } 465 466 ipu_plane->ipu = ipu; 467 ipu_plane->dma = dma; 468 ipu_plane->dp_flow = dp; 469 470 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs, 471 &ipu_plane_funcs, ipu_plane_formats, 472 ARRAY_SIZE(ipu_plane_formats), type, 473 NULL); 474 if (ret) { 475 DRM_ERROR("failed to initialize plane\n"); 476 kfree(ipu_plane); 477 return ERR_PTR(ret); 478 } 479 480 drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); 481 482 return ipu_plane; 483}