1 /* 2 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 3 * Author: Rob Clark <rob@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <linux/seq_file.h> 19 20 #include <drm/drm_crtc.h> 21 #include <drm/drm_crtc_helper.h> 22 23 #include "omap_dmm_tiler.h" 24 #include "omap_drv.h" 25 26 /* 27 * framebuffer funcs 28 */ 29 30 static const u32 formats[] = { 31 /* 16bpp [A]RGB: */ 32 DRM_FORMAT_RGB565, /* RGB16-565 */ 33 DRM_FORMAT_RGBX4444, /* RGB12x-4444 */ 34 DRM_FORMAT_XRGB4444, /* xRGB12-4444 */ 35 DRM_FORMAT_RGBA4444, /* RGBA12-4444 */ 36 DRM_FORMAT_ARGB4444, /* ARGB16-4444 */ 37 DRM_FORMAT_XRGB1555, /* xRGB15-1555 */ 38 DRM_FORMAT_ARGB1555, /* ARGB16-1555 */ 39 /* 24bpp RGB: */ 40 DRM_FORMAT_RGB888, /* RGB24-888 */ 41 /* 32bpp [A]RGB: */ 42 DRM_FORMAT_RGBX8888, /* RGBx24-8888 */ 43 DRM_FORMAT_XRGB8888, /* xRGB24-8888 */ 44 DRM_FORMAT_RGBA8888, /* RGBA32-8888 */ 45 DRM_FORMAT_ARGB8888, /* ARGB32-8888 */ 46 /* YUV: */ 47 DRM_FORMAT_NV12, 48 DRM_FORMAT_YUYV, 49 DRM_FORMAT_UYVY, 50 }; 51 52 /* per-plane info for the fb: */ 53 struct plane { 54 struct drm_gem_object *bo; 55 uint32_t pitch; 56 uint32_t offset; 57 dma_addr_t dma_addr; 58 }; 59 60 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base) 61 62 struct omap_framebuffer { 63 struct drm_framebuffer base; 64 int pin_count; 65 const struct drm_format_info *format; 66 struct plane planes[2]; 67 /* lock for pinning (pin_count and planes.dma_addr) */ 68 struct mutex lock; 69 }; 70 71 static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, 72 struct drm_file *file_priv, 73 unsigned int *handle) 74 { 75 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 76 return drm_gem_handle_create(file_priv, 77 omap_fb->planes[0].bo, handle); 78 } 79 80 static void omap_framebuffer_destroy(struct drm_framebuffer *fb) 81 { 82 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 83 int i, n = fb->format->num_planes; 84 85 DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); 86 87 drm_framebuffer_cleanup(fb); 88 89 for (i = 0; i < n; i++) { 90 struct plane *plane = &omap_fb->planes[i]; 91 92 drm_gem_object_unreference_unlocked(plane->bo); 93 } 94 95 kfree(omap_fb); 96 } 97 98 static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { 99 .create_handle = omap_framebuffer_create_handle, 100 .destroy = omap_framebuffer_destroy, 101 }; 102 103 static uint32_t get_linear_addr(struct plane *plane, 104 const struct drm_format_info *format, int n, int x, int y) 105 { 106 uint32_t offset; 107 108 offset = plane->offset 109 + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub)) 110 + (y * plane->pitch / (n == 0 ? 1 : format->vsub)); 111 112 return plane->dma_addr + offset; 113 } 114 115 bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) 116 { 117 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 118 struct plane *plane = &omap_fb->planes[0]; 119 120 return omap_gem_flags(plane->bo) & OMAP_BO_TILED; 121 } 122 123 /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */ 124 static uint32_t drm_rotation_to_tiler(unsigned int drm_rot) 125 { 126 uint32_t orient; 127 128 switch (drm_rot & DRM_MODE_ROTATE_MASK) { 129 default: 130 case DRM_MODE_ROTATE_0: 131 orient = 0; 132 break; 133 case DRM_MODE_ROTATE_90: 134 orient = MASK_XY_FLIP | MASK_X_INVERT; 135 break; 136 case DRM_MODE_ROTATE_180: 137 orient = MASK_X_INVERT | MASK_Y_INVERT; 138 break; 139 case DRM_MODE_ROTATE_270: 140 orient = MASK_XY_FLIP | MASK_Y_INVERT; 141 break; 142 } 143 144 if (drm_rot & DRM_MODE_REFLECT_X) 145 orient ^= MASK_X_INVERT; 146 147 if (drm_rot & DRM_MODE_REFLECT_Y) 148 orient ^= MASK_Y_INVERT; 149 150 return orient; 151 } 152 153 /* update ovl info for scanout, handles cases of multi-planar fb's, etc. 154 */ 155 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, 156 struct drm_plane_state *state, struct omap_overlay_info *info) 157 { 158 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 159 const struct drm_format_info *format = omap_fb->format; 160 struct plane *plane = &omap_fb->planes[0]; 161 uint32_t x, y, orient = 0; 162 163 info->fourcc = fb->format->format; 164 165 info->pos_x = state->crtc_x; 166 info->pos_y = state->crtc_y; 167 info->out_width = state->crtc_w; 168 info->out_height = state->crtc_h; 169 info->width = state->src_w >> 16; 170 info->height = state->src_h >> 16; 171 172 /* DSS driver wants the w & h in rotated orientation */ 173 if (drm_rotation_90_or_270(state->rotation)) 174 swap(info->width, info->height); 175 176 x = state->src_x >> 16; 177 y = state->src_y >> 16; 178 179 if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { 180 uint32_t w = state->src_w >> 16; 181 uint32_t h = state->src_h >> 16; 182 183 orient = drm_rotation_to_tiler(state->rotation); 184 185 /* 186 * omap_gem_rotated_paddr() wants the x & y in tiler units. 187 * Usually tiler unit size is the same as the pixel size, except 188 * for YUV422 formats, for which the tiler unit size is 32 bits 189 * and pixel size is 16 bits. 190 */ 191 if (fb->format->format == DRM_FORMAT_UYVY || 192 fb->format->format == DRM_FORMAT_YUYV) { 193 x /= 2; 194 w /= 2; 195 } 196 197 /* adjust x,y offset for invert: */ 198 if (orient & MASK_Y_INVERT) 199 y += h - 1; 200 if (orient & MASK_X_INVERT) 201 x += w - 1; 202 203 /* Note: x and y are in TILER units, not pixels */ 204 omap_gem_rotated_dma_addr(plane->bo, orient, x, y, 205 &info->paddr); 206 info->rotation_type = OMAP_DSS_ROT_TILER; 207 info->rotation = state->rotation ?: DRM_MODE_ROTATE_0; 208 /* Note: stride in TILER units, not pixels */ 209 info->screen_width = omap_gem_tiled_stride(plane->bo, orient); 210 } else { 211 switch (state->rotation & DRM_MODE_ROTATE_MASK) { 212 case 0: 213 case DRM_MODE_ROTATE_0: 214 /* OK */ 215 break; 216 217 default: 218 dev_warn(fb->dev->dev, 219 "rotation '%d' ignored for non-tiled fb\n", 220 state->rotation); 221 break; 222 } 223 224 info->paddr = get_linear_addr(plane, format, 0, x, y); 225 info->rotation_type = OMAP_DSS_ROT_NONE; 226 info->rotation = DRM_MODE_ROTATE_0; 227 info->screen_width = plane->pitch; 228 } 229 230 /* convert to pixels: */ 231 info->screen_width /= format->cpp[0]; 232 233 if (fb->format->format == DRM_FORMAT_NV12) { 234 plane = &omap_fb->planes[1]; 235 236 if (info->rotation_type == OMAP_DSS_ROT_TILER) { 237 WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED)); 238 omap_gem_rotated_dma_addr(plane->bo, orient, x/2, y/2, 239 &info->p_uv_addr); 240 } else { 241 info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); 242 } 243 } else { 244 info->p_uv_addr = 0; 245 } 246 } 247 248 /* pin, prepare for scanout: */ 249 int omap_framebuffer_pin(struct drm_framebuffer *fb) 250 { 251 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 252 int ret, i, n = fb->format->num_planes; 253 254 mutex_lock(&omap_fb->lock); 255 256 if (omap_fb->pin_count > 0) { 257 omap_fb->pin_count++; 258 mutex_unlock(&omap_fb->lock); 259 return 0; 260 } 261 262 for (i = 0; i < n; i++) { 263 struct plane *plane = &omap_fb->planes[i]; 264 ret = omap_gem_pin(plane->bo, &plane->dma_addr); 265 if (ret) 266 goto fail; 267 omap_gem_dma_sync_buffer(plane->bo, DMA_TO_DEVICE); 268 } 269 270 omap_fb->pin_count++; 271 272 mutex_unlock(&omap_fb->lock); 273 274 return 0; 275 276 fail: 277 for (i--; i >= 0; i--) { 278 struct plane *plane = &omap_fb->planes[i]; 279 omap_gem_unpin(plane->bo); 280 plane->dma_addr = 0; 281 } 282 283 mutex_unlock(&omap_fb->lock); 284 285 return ret; 286 } 287 288 /* unpin, no longer being scanned out: */ 289 void omap_framebuffer_unpin(struct drm_framebuffer *fb) 290 { 291 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 292 int i, n = fb->format->num_planes; 293 294 mutex_lock(&omap_fb->lock); 295 296 omap_fb->pin_count--; 297 298 if (omap_fb->pin_count > 0) { 299 mutex_unlock(&omap_fb->lock); 300 return; 301 } 302 303 for (i = 0; i < n; i++) { 304 struct plane *plane = &omap_fb->planes[i]; 305 omap_gem_unpin(plane->bo); 306 plane->dma_addr = 0; 307 } 308 309 mutex_unlock(&omap_fb->lock); 310 } 311 312 /* iterate thru all the connectors, returning ones that are attached 313 * to the same fb.. 314 */ 315 struct drm_connector *omap_framebuffer_get_next_connector( 316 struct drm_framebuffer *fb, struct drm_connector *from) 317 { 318 struct drm_device *dev = fb->dev; 319 struct list_head *connector_list = &dev->mode_config.connector_list; 320 struct drm_connector *connector = from; 321 322 if (!from) 323 return list_first_entry_or_null(connector_list, typeof(*from), 324 head); 325 326 list_for_each_entry_from(connector, connector_list, head) { 327 if (connector != from) { 328 struct drm_encoder *encoder = connector->encoder; 329 struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; 330 if (crtc && crtc->primary->fb == fb) 331 return connector; 332 333 } 334 } 335 336 return NULL; 337 } 338 339 #ifdef CONFIG_DEBUG_FS 340 void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) 341 { 342 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 343 int i, n = fb->format->num_planes; 344 345 seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, 346 (char *)&fb->format->format); 347 348 for (i = 0; i < n; i++) { 349 struct plane *plane = &omap_fb->planes[i]; 350 seq_printf(m, " %d: offset=%d pitch=%d, obj: ", 351 i, plane->offset, plane->pitch); 352 omap_gem_describe(plane->bo, m); 353 } 354 } 355 #endif 356 357 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, 358 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) 359 { 360 unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format); 361 struct drm_gem_object *bos[4]; 362 struct drm_framebuffer *fb; 363 int i; 364 365 for (i = 0; i < num_planes; i++) { 366 bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); 367 if (!bos[i]) { 368 fb = ERR_PTR(-ENOENT); 369 goto error; 370 } 371 } 372 373 fb = omap_framebuffer_init(dev, mode_cmd, bos); 374 if (IS_ERR(fb)) 375 goto error; 376 377 return fb; 378 379 error: 380 while (--i >= 0) 381 drm_gem_object_unreference_unlocked(bos[i]); 382 383 return fb; 384 } 385 386 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, 387 const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) 388 { 389 const struct drm_format_info *format = NULL; 390 struct omap_framebuffer *omap_fb = NULL; 391 struct drm_framebuffer *fb = NULL; 392 unsigned int pitch = mode_cmd->pitches[0]; 393 int ret, i; 394 395 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", 396 dev, mode_cmd, mode_cmd->width, mode_cmd->height, 397 (char *)&mode_cmd->pixel_format); 398 399 format = drm_format_info(mode_cmd->pixel_format); 400 401 for (i = 0; i < ARRAY_SIZE(formats); i++) { 402 if (formats[i] == mode_cmd->pixel_format) 403 break; 404 } 405 406 if (!format || i == ARRAY_SIZE(formats)) { 407 dev_dbg(dev->dev, "unsupported pixel format: %4.4s\n", 408 (char *)&mode_cmd->pixel_format); 409 ret = -EINVAL; 410 goto fail; 411 } 412 413 omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL); 414 if (!omap_fb) { 415 ret = -ENOMEM; 416 goto fail; 417 } 418 419 fb = &omap_fb->base; 420 omap_fb->format = format; 421 mutex_init(&omap_fb->lock); 422 423 /* 424 * The code below assumes that no format use more than two planes, and 425 * that the two planes of multiplane formats need the same number of 426 * bytes per pixel. 427 */ 428 if (format->num_planes == 2 && pitch != mode_cmd->pitches[1]) { 429 dev_dbg(dev->dev, "pitches differ between planes 0 and 1\n"); 430 ret = -EINVAL; 431 goto fail; 432 } 433 434 if (pitch % format->cpp[0]) { 435 dev_dbg(dev->dev, 436 "buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n", 437 pitch, format->cpp[0]); 438 ret = -EINVAL; 439 goto fail; 440 } 441 442 for (i = 0; i < format->num_planes; i++) { 443 struct plane *plane = &omap_fb->planes[i]; 444 unsigned int vsub = i == 0 ? 1 : format->vsub; 445 unsigned int size; 446 447 size = pitch * mode_cmd->height / vsub; 448 449 if (size > omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i]) { 450 dev_dbg(dev->dev, 451 "provided buffer object is too small! %zu < %d\n", 452 bos[i]->size - mode_cmd->offsets[i], size); 453 ret = -EINVAL; 454 goto fail; 455 } 456 457 plane->bo = bos[i]; 458 plane->offset = mode_cmd->offsets[i]; 459 plane->pitch = pitch; 460 plane->dma_addr = 0; 461 } 462 463 drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); 464 465 ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); 466 if (ret) { 467 dev_err(dev->dev, "framebuffer init failed: %d\n", ret); 468 goto fail; 469 } 470 471 DBG("create: FB ID: %d (%p)", fb->base.id, fb); 472 473 return fb; 474 475 fail: 476 kfree(omap_fb); 477 478 return ERR_PTR(ret); 479 } 480