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