1 /* 2 * Copyright (C) 2012-2013 Avionic Design GmbH 3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 4 * 5 * Based on the KMS/FB CMA helpers 6 * Copyright (C) 2012 Analog Device Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/console.h> 14 15 #include "drm.h" 16 #include "gem.h" 17 18 static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb) 19 { 20 return container_of(fb, struct tegra_fb, base); 21 } 22 23 #ifdef CONFIG_DRM_FBDEV_EMULATION 24 static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) 25 { 26 return container_of(helper, struct tegra_fbdev, base); 27 } 28 #endif 29 30 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, 31 unsigned int index) 32 { 33 struct tegra_fb *fb = to_tegra_fb(framebuffer); 34 35 if (index >= framebuffer->format->num_planes) 36 return NULL; 37 38 return fb->planes[index]; 39 } 40 41 bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer) 42 { 43 struct tegra_fb *fb = to_tegra_fb(framebuffer); 44 45 if (fb->planes[0]->flags & TEGRA_BO_BOTTOM_UP) 46 return true; 47 48 return false; 49 } 50 51 int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, 52 struct tegra_bo_tiling *tiling) 53 { 54 struct tegra_fb *fb = to_tegra_fb(framebuffer); 55 uint64_t modifier = fb->base.modifier; 56 57 switch (modifier) { 58 case DRM_FORMAT_MOD_LINEAR: 59 tiling->mode = TEGRA_BO_TILING_MODE_PITCH; 60 tiling->value = 0; 61 break; 62 63 case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED: 64 tiling->mode = TEGRA_BO_TILING_MODE_TILED; 65 tiling->value = 0; 66 break; 67 68 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0): 69 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 70 tiling->value = 0; 71 break; 72 73 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1): 74 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 75 tiling->value = 1; 76 break; 77 78 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2): 79 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 80 tiling->value = 2; 81 break; 82 83 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3): 84 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 85 tiling->value = 3; 86 break; 87 88 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4): 89 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 90 tiling->value = 4; 91 break; 92 93 case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5): 94 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK; 95 tiling->value = 5; 96 break; 97 98 default: 99 return -EINVAL; 100 } 101 102 return 0; 103 } 104 105 static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) 106 { 107 struct tegra_fb *fb = to_tegra_fb(framebuffer); 108 unsigned int i; 109 110 for (i = 0; i < fb->num_planes; i++) { 111 struct tegra_bo *bo = fb->planes[i]; 112 113 if (bo) { 114 if (bo->pages) 115 vunmap(bo->vaddr); 116 117 drm_gem_object_put_unlocked(&bo->gem); 118 } 119 } 120 121 drm_framebuffer_cleanup(framebuffer); 122 kfree(fb->planes); 123 kfree(fb); 124 } 125 126 static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer, 127 struct drm_file *file, unsigned int *handle) 128 { 129 struct tegra_fb *fb = to_tegra_fb(framebuffer); 130 131 return drm_gem_handle_create(file, &fb->planes[0]->gem, handle); 132 } 133 134 static const struct drm_framebuffer_funcs tegra_fb_funcs = { 135 .destroy = tegra_fb_destroy, 136 .create_handle = tegra_fb_create_handle, 137 }; 138 139 static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, 140 const struct drm_mode_fb_cmd2 *mode_cmd, 141 struct tegra_bo **planes, 142 unsigned int num_planes) 143 { 144 struct tegra_fb *fb; 145 unsigned int i; 146 int err; 147 148 fb = kzalloc(sizeof(*fb), GFP_KERNEL); 149 if (!fb) 150 return ERR_PTR(-ENOMEM); 151 152 fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL); 153 if (!fb->planes) { 154 kfree(fb); 155 return ERR_PTR(-ENOMEM); 156 } 157 158 fb->num_planes = num_planes; 159 160 drm_helper_mode_fill_fb_struct(drm, &fb->base, mode_cmd); 161 162 for (i = 0; i < fb->num_planes; i++) 163 fb->planes[i] = planes[i]; 164 165 err = drm_framebuffer_init(drm, &fb->base, &tegra_fb_funcs); 166 if (err < 0) { 167 dev_err(drm->dev, "failed to initialize framebuffer: %d\n", 168 err); 169 kfree(fb->planes); 170 kfree(fb); 171 return ERR_PTR(err); 172 } 173 174 return fb; 175 } 176 177 struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, 178 struct drm_file *file, 179 const struct drm_mode_fb_cmd2 *cmd) 180 { 181 unsigned int hsub, vsub, i; 182 struct tegra_bo *planes[4]; 183 struct drm_gem_object *gem; 184 struct tegra_fb *fb; 185 int err; 186 187 hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); 188 vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); 189 190 for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { 191 unsigned int width = cmd->width / (i ? hsub : 1); 192 unsigned int height = cmd->height / (i ? vsub : 1); 193 unsigned int size, bpp; 194 195 gem = drm_gem_object_lookup(file, cmd->handles[i]); 196 if (!gem) { 197 err = -ENXIO; 198 goto unreference; 199 } 200 201 bpp = drm_format_plane_cpp(cmd->pixel_format, i); 202 203 size = (height - 1) * cmd->pitches[i] + 204 width * bpp + cmd->offsets[i]; 205 206 if (gem->size < size) { 207 err = -EINVAL; 208 goto unreference; 209 } 210 211 planes[i] = to_tegra_bo(gem); 212 } 213 214 fb = tegra_fb_alloc(drm, cmd, planes, i); 215 if (IS_ERR(fb)) { 216 err = PTR_ERR(fb); 217 goto unreference; 218 } 219 220 return &fb->base; 221 222 unreference: 223 while (i--) 224 drm_gem_object_put_unlocked(&planes[i]->gem); 225 226 return ERR_PTR(err); 227 } 228 229 #ifdef CONFIG_DRM_FBDEV_EMULATION 230 static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) 231 { 232 struct drm_fb_helper *helper = info->par; 233 struct tegra_bo *bo; 234 int err; 235 236 bo = tegra_fb_get_plane(helper->fb, 0); 237 238 err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma); 239 if (err < 0) 240 return err; 241 242 return __tegra_gem_mmap(&bo->gem, vma); 243 } 244 245 static struct fb_ops tegra_fb_ops = { 246 .owner = THIS_MODULE, 247 DRM_FB_HELPER_DEFAULT_OPS, 248 .fb_fillrect = drm_fb_helper_sys_fillrect, 249 .fb_copyarea = drm_fb_helper_sys_copyarea, 250 .fb_imageblit = drm_fb_helper_sys_imageblit, 251 .fb_mmap = tegra_fb_mmap, 252 }; 253 254 static int tegra_fbdev_probe(struct drm_fb_helper *helper, 255 struct drm_fb_helper_surface_size *sizes) 256 { 257 struct tegra_fbdev *fbdev = to_tegra_fbdev(helper); 258 struct tegra_drm *tegra = helper->dev->dev_private; 259 struct drm_device *drm = helper->dev; 260 struct drm_mode_fb_cmd2 cmd = { 0 }; 261 unsigned int bytes_per_pixel; 262 struct drm_framebuffer *fb; 263 unsigned long offset; 264 struct fb_info *info; 265 struct tegra_bo *bo; 266 size_t size; 267 int err; 268 269 bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); 270 271 cmd.width = sizes->surface_width; 272 cmd.height = sizes->surface_height; 273 cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel, 274 tegra->pitch_align); 275 276 cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 277 sizes->surface_depth); 278 279 size = cmd.pitches[0] * cmd.height; 280 281 bo = tegra_bo_create(drm, size, 0); 282 if (IS_ERR(bo)) 283 return PTR_ERR(bo); 284 285 info = drm_fb_helper_alloc_fbi(helper); 286 if (IS_ERR(info)) { 287 dev_err(drm->dev, "failed to allocate framebuffer info\n"); 288 drm_gem_object_put_unlocked(&bo->gem); 289 return PTR_ERR(info); 290 } 291 292 fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); 293 if (IS_ERR(fbdev->fb)) { 294 err = PTR_ERR(fbdev->fb); 295 dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n", 296 err); 297 drm_gem_object_put_unlocked(&bo->gem); 298 return PTR_ERR(fbdev->fb); 299 } 300 301 fb = &fbdev->fb->base; 302 helper->fb = fb; 303 helper->fbdev = info; 304 305 info->par = helper; 306 info->flags = FBINFO_FLAG_DEFAULT; 307 info->fbops = &tegra_fb_ops; 308 309 drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); 310 drm_fb_helper_fill_var(info, helper, fb->width, fb->height); 311 312 offset = info->var.xoffset * bytes_per_pixel + 313 info->var.yoffset * fb->pitches[0]; 314 315 if (bo->pages) { 316 bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP, 317 pgprot_writecombine(PAGE_KERNEL)); 318 if (!bo->vaddr) { 319 dev_err(drm->dev, "failed to vmap() framebuffer\n"); 320 err = -ENOMEM; 321 goto destroy; 322 } 323 } 324 325 drm->mode_config.fb_base = (resource_size_t)bo->paddr; 326 info->screen_base = (void __iomem *)bo->vaddr + offset; 327 info->screen_size = size; 328 info->fix.smem_start = (unsigned long)(bo->paddr + offset); 329 info->fix.smem_len = size; 330 331 return 0; 332 333 destroy: 334 drm_framebuffer_remove(fb); 335 return err; 336 } 337 338 static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = { 339 .fb_probe = tegra_fbdev_probe, 340 }; 341 342 static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm) 343 { 344 struct tegra_fbdev *fbdev; 345 346 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 347 if (!fbdev) { 348 dev_err(drm->dev, "failed to allocate DRM fbdev\n"); 349 return ERR_PTR(-ENOMEM); 350 } 351 352 drm_fb_helper_prepare(drm, &fbdev->base, &tegra_fb_helper_funcs); 353 354 return fbdev; 355 } 356 357 static void tegra_fbdev_free(struct tegra_fbdev *fbdev) 358 { 359 kfree(fbdev); 360 } 361 362 static int tegra_fbdev_init(struct tegra_fbdev *fbdev, 363 unsigned int preferred_bpp, 364 unsigned int num_crtc, 365 unsigned int max_connectors) 366 { 367 struct drm_device *drm = fbdev->base.dev; 368 int err; 369 370 err = drm_fb_helper_init(drm, &fbdev->base, max_connectors); 371 if (err < 0) { 372 dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n", 373 err); 374 return err; 375 } 376 377 err = drm_fb_helper_single_add_all_connectors(&fbdev->base); 378 if (err < 0) { 379 dev_err(drm->dev, "failed to add connectors: %d\n", err); 380 goto fini; 381 } 382 383 err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); 384 if (err < 0) { 385 dev_err(drm->dev, "failed to set initial configuration: %d\n", 386 err); 387 goto fini; 388 } 389 390 return 0; 391 392 fini: 393 drm_fb_helper_fini(&fbdev->base); 394 return err; 395 } 396 397 static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) 398 { 399 drm_fb_helper_unregister_fbi(&fbdev->base); 400 401 if (fbdev->fb) 402 drm_framebuffer_remove(&fbdev->fb->base); 403 404 drm_fb_helper_fini(&fbdev->base); 405 tegra_fbdev_free(fbdev); 406 } 407 #endif 408 409 int tegra_drm_fb_prepare(struct drm_device *drm) 410 { 411 #ifdef CONFIG_DRM_FBDEV_EMULATION 412 struct tegra_drm *tegra = drm->dev_private; 413 414 tegra->fbdev = tegra_fbdev_create(drm); 415 if (IS_ERR(tegra->fbdev)) 416 return PTR_ERR(tegra->fbdev); 417 #endif 418 419 return 0; 420 } 421 422 void tegra_drm_fb_free(struct drm_device *drm) 423 { 424 #ifdef CONFIG_DRM_FBDEV_EMULATION 425 struct tegra_drm *tegra = drm->dev_private; 426 427 tegra_fbdev_free(tegra->fbdev); 428 #endif 429 } 430 431 int tegra_drm_fb_init(struct drm_device *drm) 432 { 433 #ifdef CONFIG_DRM_FBDEV_EMULATION 434 struct tegra_drm *tegra = drm->dev_private; 435 int err; 436 437 err = tegra_fbdev_init(tegra->fbdev, 32, drm->mode_config.num_crtc, 438 drm->mode_config.num_connector); 439 if (err < 0) 440 return err; 441 #endif 442 443 return 0; 444 } 445 446 void tegra_drm_fb_exit(struct drm_device *drm) 447 { 448 #ifdef CONFIG_DRM_FBDEV_EMULATION 449 struct tegra_drm *tegra = drm->dev_private; 450 451 tegra_fbdev_exit(tegra->fbdev); 452 #endif 453 } 454 455 void tegra_drm_fb_suspend(struct drm_device *drm) 456 { 457 #ifdef CONFIG_DRM_FBDEV_EMULATION 458 struct tegra_drm *tegra = drm->dev_private; 459 460 console_lock(); 461 drm_fb_helper_set_suspend(&tegra->fbdev->base, 1); 462 console_unlock(); 463 #endif 464 } 465 466 void tegra_drm_fb_resume(struct drm_device *drm) 467 { 468 #ifdef CONFIG_DRM_FBDEV_EMULATION 469 struct tegra_drm *tegra = drm->dev_private; 470 471 console_lock(); 472 drm_fb_helper_set_suspend(&tegra->fbdev->base, 0); 473 console_unlock(); 474 #endif 475 } 476