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.5 414 lines 10 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_fb_cma_helper.h> 18#include <drm/drm_gem_cma_helper.h> 19 20#include "video/imx-ipu-v3.h" 21#include "ipuv3-plane.h" 22 23#define to_ipu_plane(x) container_of(x, struct ipu_plane, base) 24 25static const uint32_t ipu_plane_formats[] = { 26 DRM_FORMAT_ARGB1555, 27 DRM_FORMAT_XRGB1555, 28 DRM_FORMAT_ABGR1555, 29 DRM_FORMAT_XBGR1555, 30 DRM_FORMAT_RGBA5551, 31 DRM_FORMAT_BGRA5551, 32 DRM_FORMAT_ARGB4444, 33 DRM_FORMAT_ARGB8888, 34 DRM_FORMAT_XRGB8888, 35 DRM_FORMAT_ABGR8888, 36 DRM_FORMAT_XBGR8888, 37 DRM_FORMAT_RGBA8888, 38 DRM_FORMAT_RGBX8888, 39 DRM_FORMAT_BGRA8888, 40 DRM_FORMAT_BGRA8888, 41 DRM_FORMAT_YUYV, 42 DRM_FORMAT_YVYU, 43 DRM_FORMAT_YUV420, 44 DRM_FORMAT_YVU420, 45 DRM_FORMAT_RGB565, 46}; 47 48int ipu_plane_irq(struct ipu_plane *ipu_plane) 49{ 50 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch, 51 IPU_IRQ_EOF); 52} 53 54static int calc_vref(struct drm_display_mode *mode) 55{ 56 unsigned long htotal, vtotal; 57 58 htotal = mode->htotal; 59 vtotal = mode->vtotal; 60 61 if (!htotal || !vtotal) 62 return 60; 63 64 return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal); 65} 66 67static inline int calc_bandwidth(int width, int height, unsigned int vref) 68{ 69 return width * height * vref; 70} 71 72int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, 73 int x, int y) 74{ 75 struct drm_gem_cma_object *cma_obj; 76 unsigned long eba; 77 int active; 78 79 cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 80 if (!cma_obj) { 81 DRM_DEBUG_KMS("entry is null.\n"); 82 return -EFAULT; 83 } 84 85 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", 86 &cma_obj->paddr, x, y); 87 88 eba = cma_obj->paddr + fb->offsets[0] + 89 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; 90 91 if (ipu_plane->enabled) { 92 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); 93 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); 94 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); 95 } else { 96 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); 97 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); 98 } 99 100 /* cache offsets for subsequent pageflips */ 101 ipu_plane->x = x; 102 ipu_plane->y = y; 103 104 return 0; 105} 106 107int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, 108 struct drm_display_mode *mode, 109 struct drm_framebuffer *fb, int crtc_x, int crtc_y, 110 unsigned int crtc_w, unsigned int crtc_h, 111 uint32_t src_x, uint32_t src_y, 112 uint32_t src_w, uint32_t src_h, bool interlaced) 113{ 114 struct device *dev = ipu_plane->base.dev->dev; 115 int ret; 116 117 /* no scaling */ 118 if (src_w != crtc_w || src_h != crtc_h) 119 return -EINVAL; 120 121 /* clip to crtc bounds */ 122 if (crtc_x < 0) { 123 if (-crtc_x > crtc_w) 124 return -EINVAL; 125 src_x += -crtc_x; 126 src_w -= -crtc_x; 127 crtc_w -= -crtc_x; 128 crtc_x = 0; 129 } 130 if (crtc_y < 0) { 131 if (-crtc_y > crtc_h) 132 return -EINVAL; 133 src_y += -crtc_y; 134 src_h -= -crtc_y; 135 crtc_h -= -crtc_y; 136 crtc_y = 0; 137 } 138 if (crtc_x + crtc_w > mode->hdisplay) { 139 if (crtc_x > mode->hdisplay) 140 return -EINVAL; 141 crtc_w = mode->hdisplay - crtc_x; 142 src_w = crtc_w; 143 } 144 if (crtc_y + crtc_h > mode->vdisplay) { 145 if (crtc_y > mode->vdisplay) 146 return -EINVAL; 147 crtc_h = mode->vdisplay - crtc_y; 148 src_h = crtc_h; 149 } 150 /* full plane minimum width is 13 pixels */ 151 if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG)) 152 return -EINVAL; 153 if (crtc_h < 2) 154 return -EINVAL; 155 156 /* 157 * since we cannot touch active IDMAC channels, we do not support 158 * resizing the enabled plane or changing its format 159 */ 160 if (ipu_plane->enabled) { 161 if (src_w != ipu_plane->w || src_h != ipu_plane->h || 162 fb->pixel_format != ipu_plane->base.fb->pixel_format) 163 return -EINVAL; 164 165 return ipu_plane_set_base(ipu_plane, fb, src_x, src_y); 166 } 167 168 switch (ipu_plane->dp_flow) { 169 case IPU_DP_FLOW_SYNC_BG: 170 ret = ipu_dp_setup_channel(ipu_plane->dp, 171 IPUV3_COLORSPACE_RGB, 172 IPUV3_COLORSPACE_RGB); 173 if (ret) { 174 dev_err(dev, 175 "initializing display processor failed with %d\n", 176 ret); 177 return ret; 178 } 179 ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true); 180 break; 181 case IPU_DP_FLOW_SYNC_FG: 182 ipu_dp_setup_channel(ipu_plane->dp, 183 ipu_drm_fourcc_to_colorspace(fb->pixel_format), 184 IPUV3_COLORSPACE_UNKNOWN); 185 ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y); 186 /* Enable local alpha on partial plane */ 187 switch (fb->pixel_format) { 188 case DRM_FORMAT_ARGB1555: 189 case DRM_FORMAT_ABGR1555: 190 case DRM_FORMAT_RGBA5551: 191 case DRM_FORMAT_BGRA5551: 192 case DRM_FORMAT_ARGB4444: 193 case DRM_FORMAT_ARGB8888: 194 case DRM_FORMAT_ABGR8888: 195 case DRM_FORMAT_RGBA8888: 196 case DRM_FORMAT_BGRA8888: 197 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); 198 break; 199 default: 200 break; 201 } 202 } 203 204 ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w); 205 if (ret) { 206 dev_err(dev, "initializing dmfc channel failed with %d\n", ret); 207 return ret; 208 } 209 210 ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc, 211 calc_bandwidth(crtc_w, crtc_h, 212 calc_vref(mode)), 64); 213 if (ret) { 214 dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret); 215 return ret; 216 } 217 218 ipu_cpmem_zero(ipu_plane->ipu_ch); 219 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h); 220 ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format); 221 if (ret < 0) { 222 dev_err(dev, "unsupported pixel format 0x%08x\n", 223 fb->pixel_format); 224 return ret; 225 } 226 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); 227 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); 228 ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); 229 230 ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); 231 if (ret < 0) 232 return ret; 233 if (interlaced) 234 ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]); 235 236 ipu_plane->w = src_w; 237 ipu_plane->h = src_h; 238 239 return 0; 240} 241 242void ipu_plane_put_resources(struct ipu_plane *ipu_plane) 243{ 244 if (!IS_ERR_OR_NULL(ipu_plane->dp)) 245 ipu_dp_put(ipu_plane->dp); 246 if (!IS_ERR_OR_NULL(ipu_plane->dmfc)) 247 ipu_dmfc_put(ipu_plane->dmfc); 248 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch)) 249 ipu_idmac_put(ipu_plane->ipu_ch); 250} 251 252int ipu_plane_get_resources(struct ipu_plane *ipu_plane) 253{ 254 int ret; 255 256 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma); 257 if (IS_ERR(ipu_plane->ipu_ch)) { 258 ret = PTR_ERR(ipu_plane->ipu_ch); 259 DRM_ERROR("failed to get idmac channel: %d\n", ret); 260 return ret; 261 } 262 263 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma); 264 if (IS_ERR(ipu_plane->dmfc)) { 265 ret = PTR_ERR(ipu_plane->dmfc); 266 DRM_ERROR("failed to get dmfc: ret %d\n", ret); 267 goto err_out; 268 } 269 270 if (ipu_plane->dp_flow >= 0) { 271 ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow); 272 if (IS_ERR(ipu_plane->dp)) { 273 ret = PTR_ERR(ipu_plane->dp); 274 DRM_ERROR("failed to get dp flow: %d\n", ret); 275 goto err_out; 276 } 277 } 278 279 return 0; 280err_out: 281 ipu_plane_put_resources(ipu_plane); 282 283 return ret; 284} 285 286void ipu_plane_enable(struct ipu_plane *ipu_plane) 287{ 288 if (ipu_plane->dp) 289 ipu_dp_enable(ipu_plane->ipu); 290 ipu_dmfc_enable_channel(ipu_plane->dmfc); 291 ipu_idmac_enable_channel(ipu_plane->ipu_ch); 292 if (ipu_plane->dp) 293 ipu_dp_enable_channel(ipu_plane->dp); 294 295 ipu_plane->enabled = true; 296} 297 298void ipu_plane_disable(struct ipu_plane *ipu_plane) 299{ 300 ipu_plane->enabled = false; 301 302 ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); 303 304 if (ipu_plane->dp) 305 ipu_dp_disable_channel(ipu_plane->dp); 306 ipu_idmac_disable_channel(ipu_plane->ipu_ch); 307 ipu_dmfc_disable_channel(ipu_plane->dmfc); 308 if (ipu_plane->dp) 309 ipu_dp_disable(ipu_plane->ipu); 310} 311 312/* 313 * drm_plane API 314 */ 315 316static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 317 struct drm_framebuffer *fb, int crtc_x, int crtc_y, 318 unsigned int crtc_w, unsigned int crtc_h, 319 uint32_t src_x, uint32_t src_y, 320 uint32_t src_w, uint32_t src_h) 321{ 322 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 323 int ret = 0; 324 325 DRM_DEBUG_KMS("plane - %p\n", plane); 326 327 if (!ipu_plane->enabled) 328 ret = ipu_plane_get_resources(ipu_plane); 329 if (ret < 0) 330 return ret; 331 332 ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, 333 crtc_x, crtc_y, crtc_w, crtc_h, 334 src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, 335 false); 336 if (ret < 0) { 337 ipu_plane_put_resources(ipu_plane); 338 return ret; 339 } 340 341 if (crtc != plane->crtc) 342 dev_info(plane->dev->dev, "crtc change: %p -> %p\n", 343 plane->crtc, crtc); 344 plane->crtc = crtc; 345 346 if (!ipu_plane->enabled) 347 ipu_plane_enable(ipu_plane); 348 349 return 0; 350} 351 352static int ipu_disable_plane(struct drm_plane *plane) 353{ 354 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 355 356 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 357 358 if (ipu_plane->enabled) 359 ipu_plane_disable(ipu_plane); 360 361 ipu_plane_put_resources(ipu_plane); 362 363 return 0; 364} 365 366static void ipu_plane_destroy(struct drm_plane *plane) 367{ 368 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 369 370 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 371 372 ipu_disable_plane(plane); 373 drm_plane_cleanup(plane); 374 kfree(ipu_plane); 375} 376 377static struct drm_plane_funcs ipu_plane_funcs = { 378 .update_plane = ipu_update_plane, 379 .disable_plane = ipu_disable_plane, 380 .destroy = ipu_plane_destroy, 381}; 382 383struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, 384 int dma, int dp, unsigned int possible_crtcs, 385 enum drm_plane_type type) 386{ 387 struct ipu_plane *ipu_plane; 388 int ret; 389 390 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", 391 dma, dp, possible_crtcs); 392 393 ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL); 394 if (!ipu_plane) { 395 DRM_ERROR("failed to allocate plane\n"); 396 return ERR_PTR(-ENOMEM); 397 } 398 399 ipu_plane->ipu = ipu; 400 ipu_plane->dma = dma; 401 ipu_plane->dp_flow = dp; 402 403 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs, 404 &ipu_plane_funcs, ipu_plane_formats, 405 ARRAY_SIZE(ipu_plane_formats), type, 406 NULL); 407 if (ret) { 408 DRM_ERROR("failed to initialize plane\n"); 409 kfree(ipu_plane); 410 return ERR_PTR(ret); 411 } 412 413 return ipu_plane; 414}