1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * R-Car Display Unit VSP-Based Compositor 4 * 5 * Copyright (C) 2015 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <drm/drm_atomic.h> 11 #include <drm/drm_atomic_helper.h> 12 #include <drm/drm_blend.h> 13 #include <drm/drm_crtc.h> 14 #include <drm/drm_fb_dma_helper.h> 15 #include <drm/drm_fourcc.h> 16 #include <drm/drm_framebuffer.h> 17 #include <drm/drm_gem_atomic_helper.h> 18 #include <drm/drm_gem_dma_helper.h> 19 #include <drm/drm_managed.h> 20 #include <drm/drm_vblank.h> 21 22 #include <linux/bitops.h> 23 #include <linux/dma-mapping.h> 24 #include <linux/of_platform.h> 25 #include <linux/platform_device.h> 26 #include <linux/scatterlist.h> 27 #include <linux/slab.h> 28 #include <linux/videodev2.h> 29 30 #include <media/vsp1.h> 31 32 #include "rcar_du_drv.h" 33 #include "rcar_du_kms.h" 34 #include "rcar_du_vsp.h" 35 #include "rcar_du_writeback.h" 36 37 static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc) 38 { 39 struct rcar_du_crtc *crtc = private; 40 41 if (crtc->vblank_enable) 42 drm_crtc_handle_vblank(&crtc->crtc); 43 44 if (status & VSP1_DU_STATUS_COMPLETE) 45 rcar_du_crtc_finish_page_flip(crtc); 46 if (status & VSP1_DU_STATUS_WRITEBACK) 47 rcar_du_writeback_complete(crtc); 48 49 drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc); 50 } 51 52 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) 53 { 54 const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode; 55 struct rcar_du_device *rcdu = crtc->dev; 56 struct vsp1_du_lif_config cfg = { 57 .width = mode->hdisplay, 58 .height = mode->vdisplay, 59 .interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE, 60 .callback = rcar_du_vsp_complete, 61 .callback_data = crtc, 62 }; 63 struct rcar_du_plane_state state = { 64 .state = { 65 .alpha = DRM_BLEND_ALPHA_OPAQUE, 66 .crtc = &crtc->crtc, 67 .dst.x1 = 0, 68 .dst.y1 = 0, 69 .dst.x2 = mode->hdisplay, 70 .dst.y2 = mode->vdisplay, 71 .src.x1 = 0, 72 .src.y1 = 0, 73 .src.x2 = mode->hdisplay << 16, 74 .src.y2 = mode->vdisplay << 16, 75 .zpos = 0, 76 }, 77 .format = rcar_du_format_info(DRM_FORMAT_XRGB8888), 78 .source = RCAR_DU_PLANE_VSPD1, 79 .colorkey = 0, 80 }; 81 82 if (rcdu->info->gen >= 3) 83 state.hwindex = (crtc->index % 2) ? 2 : 0; 84 else 85 state.hwindex = crtc->index % 2; 86 87 __rcar_du_plane_setup(crtc->group, &state); 88 89 vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); 90 } 91 92 void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) 93 { 94 vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL); 95 } 96 97 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) 98 { 99 vsp1_du_atomic_begin(crtc->vsp->vsp, crtc->vsp_pipe); 100 } 101 102 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) 103 { 104 struct vsp1_du_atomic_pipe_config cfg = { { 0, } }; 105 struct rcar_du_crtc_state *state; 106 107 state = to_rcar_crtc_state(crtc->crtc.state); 108 cfg.crc = state->crc; 109 110 rcar_du_writeback_setup(crtc, &cfg.writeback); 111 112 vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); 113 } 114 115 static const u32 rcar_du_vsp_formats[] = { 116 DRM_FORMAT_RGB332, 117 DRM_FORMAT_ARGB4444, 118 DRM_FORMAT_XRGB4444, 119 DRM_FORMAT_ARGB1555, 120 DRM_FORMAT_XRGB1555, 121 DRM_FORMAT_RGB565, 122 DRM_FORMAT_BGR888, 123 DRM_FORMAT_RGB888, 124 DRM_FORMAT_BGRA8888, 125 DRM_FORMAT_BGRX8888, 126 DRM_FORMAT_ABGR8888, 127 DRM_FORMAT_XBGR8888, 128 DRM_FORMAT_ARGB8888, 129 DRM_FORMAT_XRGB8888, 130 DRM_FORMAT_UYVY, 131 DRM_FORMAT_YUYV, 132 DRM_FORMAT_YVYU, 133 DRM_FORMAT_NV12, 134 DRM_FORMAT_NV21, 135 DRM_FORMAT_NV16, 136 DRM_FORMAT_NV61, 137 DRM_FORMAT_YUV420, 138 DRM_FORMAT_YVU420, 139 DRM_FORMAT_YUV422, 140 DRM_FORMAT_YVU422, 141 DRM_FORMAT_YUV444, 142 DRM_FORMAT_YVU444, 143 }; 144 145 /* 146 * Gen4 supports the same formats as above, and additionally 2-10-10-10 RGB 147 * formats and Y210 & Y212 formats. 148 */ 149 static const u32 rcar_du_vsp_formats_gen4[] = { 150 DRM_FORMAT_RGB332, 151 DRM_FORMAT_ARGB4444, 152 DRM_FORMAT_XRGB4444, 153 DRM_FORMAT_ARGB1555, 154 DRM_FORMAT_XRGB1555, 155 DRM_FORMAT_RGB565, 156 DRM_FORMAT_BGR888, 157 DRM_FORMAT_RGB888, 158 DRM_FORMAT_BGRA8888, 159 DRM_FORMAT_BGRX8888, 160 DRM_FORMAT_ABGR8888, 161 DRM_FORMAT_XBGR8888, 162 DRM_FORMAT_ARGB8888, 163 DRM_FORMAT_XRGB8888, 164 DRM_FORMAT_RGBX1010102, 165 DRM_FORMAT_RGBA1010102, 166 DRM_FORMAT_ARGB2101010, 167 DRM_FORMAT_UYVY, 168 DRM_FORMAT_YUYV, 169 DRM_FORMAT_YVYU, 170 DRM_FORMAT_NV12, 171 DRM_FORMAT_NV21, 172 DRM_FORMAT_NV16, 173 DRM_FORMAT_NV61, 174 DRM_FORMAT_YUV420, 175 DRM_FORMAT_YVU420, 176 DRM_FORMAT_YUV422, 177 DRM_FORMAT_YVU422, 178 DRM_FORMAT_YUV444, 179 DRM_FORMAT_YVU444, 180 DRM_FORMAT_Y210, 181 DRM_FORMAT_Y212, 182 }; 183 184 static u32 rcar_du_vsp_state_get_format(struct rcar_du_vsp_plane_state *state) 185 { 186 u32 fourcc = state->format->fourcc; 187 188 if (state->state.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE) { 189 switch (fourcc) { 190 case DRM_FORMAT_ARGB1555: 191 fourcc = DRM_FORMAT_XRGB1555; 192 break; 193 194 case DRM_FORMAT_ARGB4444: 195 fourcc = DRM_FORMAT_XRGB4444; 196 break; 197 198 case DRM_FORMAT_ARGB8888: 199 fourcc = DRM_FORMAT_XRGB8888; 200 break; 201 202 case DRM_FORMAT_ABGR8888: 203 fourcc = DRM_FORMAT_XBGR8888; 204 break; 205 206 case DRM_FORMAT_BGRA8888: 207 fourcc = DRM_FORMAT_BGRX8888; 208 break; 209 210 case DRM_FORMAT_RGBA1010102: 211 fourcc = DRM_FORMAT_RGBX1010102; 212 break; 213 } 214 } 215 216 return fourcc; 217 } 218 219 static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) 220 { 221 struct rcar_du_vsp_plane_state *state = 222 to_rcar_vsp_plane_state(plane->plane.state); 223 struct rcar_du_crtc *crtc = to_rcar_crtc(state->state.crtc); 224 struct drm_framebuffer *fb = plane->plane.state->fb; 225 const struct rcar_du_format_info *format; 226 struct vsp1_du_atomic_config cfg = { 227 .pixelformat = 0, 228 .pitch = fb->pitches[0], 229 .alpha = state->state.alpha >> 8, 230 .zpos = state->state.zpos, 231 }; 232 u32 fourcc = rcar_du_vsp_state_get_format(state); 233 unsigned int i; 234 235 cfg.src.left = state->state.src.x1 >> 16; 236 cfg.src.top = state->state.src.y1 >> 16; 237 cfg.src.width = drm_rect_width(&state->state.src) >> 16; 238 cfg.src.height = drm_rect_height(&state->state.src) >> 16; 239 240 cfg.dst.left = state->state.dst.x1; 241 cfg.dst.top = state->state.dst.y1; 242 cfg.dst.width = drm_rect_width(&state->state.dst); 243 cfg.dst.height = drm_rect_height(&state->state.dst); 244 245 for (i = 0; i < state->format->planes; ++i) 246 cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl) 247 + fb->offsets[i]; 248 249 format = rcar_du_format_info(fourcc); 250 cfg.pixelformat = format->v4l2; 251 252 cfg.premult = state->state.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI; 253 254 vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe, 255 plane->index, &cfg); 256 } 257 258 int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, 259 struct sg_table sg_tables[3]) 260 { 261 struct rcar_du_device *rcdu = vsp->dev; 262 unsigned int i, j; 263 int ret; 264 265 for (i = 0; i < fb->format->num_planes; ++i) { 266 struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i); 267 struct sg_table *sgt = &sg_tables[i]; 268 269 if (gem->sgt) { 270 struct scatterlist *src; 271 struct scatterlist *dst; 272 273 /* 274 * If the GEM buffer has a scatter gather table, it has 275 * been imported from a dma-buf and has no physical 276 * address as it might not be physically contiguous. 277 * Copy the original scatter gather table to map it to 278 * the VSP. 279 */ 280 ret = sg_alloc_table(sgt, gem->sgt->orig_nents, 281 GFP_KERNEL); 282 if (ret) 283 goto fail; 284 285 src = gem->sgt->sgl; 286 dst = sgt->sgl; 287 for (j = 0; j < gem->sgt->orig_nents; ++j) { 288 sg_set_page(dst, sg_page(src), src->length, 289 src->offset); 290 src = sg_next(src); 291 dst = sg_next(dst); 292 } 293 } else { 294 ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, 295 gem->dma_addr, gem->base.size); 296 if (ret) 297 goto fail; 298 } 299 300 ret = vsp1_du_map_sg(vsp->vsp, sgt); 301 if (ret) { 302 sg_free_table(sgt); 303 goto fail; 304 } 305 } 306 307 return 0; 308 309 fail: 310 while (i--) { 311 struct sg_table *sgt = &sg_tables[i]; 312 313 vsp1_du_unmap_sg(vsp->vsp, sgt); 314 sg_free_table(sgt); 315 } 316 317 return ret; 318 } 319 320 static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane, 321 struct drm_plane_state *state) 322 { 323 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); 324 struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; 325 int ret; 326 327 /* 328 * There's no need to prepare (and unprepare) the framebuffer when the 329 * plane is not visible, as it will not be displayed. 330 */ 331 if (!state->visible) 332 return 0; 333 334 ret = rcar_du_vsp_map_fb(vsp, state->fb, rstate->sg_tables); 335 if (ret < 0) 336 return ret; 337 338 return drm_gem_plane_helper_prepare_fb(plane, state); 339 } 340 341 void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, 342 struct sg_table sg_tables[3]) 343 { 344 unsigned int i; 345 346 for (i = 0; i < fb->format->num_planes; ++i) { 347 struct sg_table *sgt = &sg_tables[i]; 348 349 vsp1_du_unmap_sg(vsp->vsp, sgt); 350 sg_free_table(sgt); 351 } 352 } 353 354 static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane, 355 struct drm_plane_state *state) 356 { 357 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); 358 struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; 359 360 if (!state->visible) 361 return; 362 363 rcar_du_vsp_unmap_fb(vsp, state->fb, rstate->sg_tables); 364 } 365 366 static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, 367 struct drm_atomic_state *state) 368 { 369 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 370 plane); 371 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(new_plane_state); 372 373 return __rcar_du_plane_atomic_check(plane, new_plane_state, 374 &rstate->format); 375 } 376 377 static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, 378 struct drm_atomic_state *state) 379 { 380 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); 381 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); 382 struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane); 383 struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc); 384 385 if (new_state->visible) 386 rcar_du_vsp_plane_setup(rplane); 387 else if (old_state->crtc) 388 vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe, 389 rplane->index, NULL); 390 } 391 392 static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { 393 .prepare_fb = rcar_du_vsp_plane_prepare_fb, 394 .cleanup_fb = rcar_du_vsp_plane_cleanup_fb, 395 .atomic_check = rcar_du_vsp_plane_atomic_check, 396 .atomic_update = rcar_du_vsp_plane_atomic_update, 397 }; 398 399 static struct drm_plane_state * 400 rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) 401 { 402 struct rcar_du_vsp_plane_state *copy; 403 404 if (WARN_ON(!plane->state)) 405 return NULL; 406 407 copy = kzalloc(sizeof(*copy), GFP_KERNEL); 408 if (copy == NULL) 409 return NULL; 410 411 __drm_atomic_helper_plane_duplicate_state(plane, ©->state); 412 413 return ©->state; 414 } 415 416 static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane, 417 struct drm_plane_state *state) 418 { 419 __drm_atomic_helper_plane_destroy_state(state); 420 kfree(to_rcar_vsp_plane_state(state)); 421 } 422 423 static void rcar_du_vsp_plane_reset(struct drm_plane *plane) 424 { 425 struct rcar_du_vsp_plane_state *state; 426 427 if (plane->state) { 428 rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state); 429 plane->state = NULL; 430 } 431 432 state = kzalloc(sizeof(*state), GFP_KERNEL); 433 if (state == NULL) 434 return; 435 436 __drm_atomic_helper_plane_reset(plane, &state->state); 437 } 438 439 static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = { 440 .update_plane = drm_atomic_helper_update_plane, 441 .disable_plane = drm_atomic_helper_disable_plane, 442 .reset = rcar_du_vsp_plane_reset, 443 .destroy = drm_plane_cleanup, 444 .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state, 445 .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state, 446 }; 447 448 static void rcar_du_vsp_cleanup(struct drm_device *dev, void *res) 449 { 450 struct rcar_du_vsp *vsp = res; 451 unsigned int i; 452 453 for (i = 0; i < vsp->num_planes; ++i) { 454 struct rcar_du_vsp_plane *plane = &vsp->planes[i]; 455 456 drm_plane_cleanup(&plane->plane); 457 } 458 459 kfree(vsp->planes); 460 461 put_device(vsp->vsp); 462 } 463 464 int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, 465 unsigned int crtcs) 466 { 467 struct rcar_du_device *rcdu = vsp->dev; 468 struct platform_device *pdev; 469 unsigned int num_crtcs = hweight32(crtcs); 470 unsigned int num_planes; 471 unsigned int i; 472 int ret; 473 474 /* Find the VSP device and initialize it. */ 475 pdev = of_find_device_by_node(np); 476 if (!pdev) 477 return -ENXIO; 478 479 vsp->vsp = &pdev->dev; 480 481 ret = drmm_add_action_or_reset(&rcdu->ddev, rcar_du_vsp_cleanup, vsp); 482 if (ret < 0) 483 return ret; 484 485 ret = vsp1_du_init(vsp->vsp); 486 if (ret < 0) 487 return ret; 488 489 num_planes = rcdu->info->num_rpf; 490 491 vsp->planes = kcalloc(num_planes, sizeof(*vsp->planes), GFP_KERNEL); 492 if (!vsp->planes) 493 return -ENOMEM; 494 495 for (i = 0; i < num_planes; ++i) { 496 enum drm_plane_type type = i < num_crtcs 497 ? DRM_PLANE_TYPE_PRIMARY 498 : DRM_PLANE_TYPE_OVERLAY; 499 struct rcar_du_vsp_plane *plane = &vsp->planes[i]; 500 unsigned int num_formats; 501 const u32 *formats; 502 503 if (rcdu->info->gen < 4) { 504 num_formats = ARRAY_SIZE(rcar_du_vsp_formats); 505 formats = rcar_du_vsp_formats; 506 } else { 507 num_formats = ARRAY_SIZE(rcar_du_vsp_formats_gen4); 508 formats = rcar_du_vsp_formats_gen4; 509 } 510 511 plane->vsp = vsp; 512 plane->index = i; 513 514 ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane, 515 crtcs, &rcar_du_vsp_plane_funcs, 516 formats, num_formats, 517 NULL, type, NULL); 518 if (ret < 0) 519 return ret; 520 521 drm_plane_helper_add(&plane->plane, 522 &rcar_du_vsp_plane_helper_funcs); 523 524 drm_plane_create_alpha_property(&plane->plane); 525 drm_plane_create_zpos_property(&plane->plane, i, 0, 526 num_planes - 1); 527 528 drm_plane_create_blend_mode_property(&plane->plane, 529 BIT(DRM_MODE_BLEND_PIXEL_NONE) | 530 BIT(DRM_MODE_BLEND_PREMULTI) | 531 BIT(DRM_MODE_BLEND_COVERAGE)); 532 533 vsp->num_planes++; 534 } 535 536 return 0; 537 } 538