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