Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.9 406 lines 10 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * rcar_du_vsp.h -- 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_helper.h> 11#include <drm/drm_crtc.h> 12#include <drm/drm_fb_cma_helper.h> 13#include <drm/drm_fourcc.h> 14#include <drm/drm_gem_cma_helper.h> 15#include <drm/drm_gem_framebuffer_helper.h> 16#include <drm/drm_plane_helper.h> 17#include <drm/drm_vblank.h> 18 19#include <linux/bitops.h> 20#include <linux/dma-mapping.h> 21#include <linux/of_platform.h> 22#include <linux/scatterlist.h> 23#include <linux/videodev2.h> 24 25#include <media/vsp1.h> 26 27#include "rcar_du_drv.h" 28#include "rcar_du_kms.h" 29#include "rcar_du_vsp.h" 30#include "rcar_du_writeback.h" 31 32static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc) 33{ 34 struct rcar_du_crtc *crtc = private; 35 36 if (crtc->vblank_enable) 37 drm_crtc_handle_vblank(&crtc->crtc); 38 39 if (status & VSP1_DU_STATUS_COMPLETE) 40 rcar_du_crtc_finish_page_flip(crtc); 41 if (status & VSP1_DU_STATUS_WRITEBACK) 42 rcar_du_writeback_complete(crtc); 43 44 drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc); 45} 46 47void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) 48{ 49 const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode; 50 struct rcar_du_device *rcdu = crtc->dev; 51 struct vsp1_du_lif_config cfg = { 52 .width = mode->hdisplay, 53 .height = mode->vdisplay, 54 .interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE, 55 .callback = rcar_du_vsp_complete, 56 .callback_data = crtc, 57 }; 58 struct rcar_du_plane_state state = { 59 .state = { 60 .alpha = DRM_BLEND_ALPHA_OPAQUE, 61 .crtc = &crtc->crtc, 62 .dst.x1 = 0, 63 .dst.y1 = 0, 64 .dst.x2 = mode->hdisplay, 65 .dst.y2 = mode->vdisplay, 66 .src.x1 = 0, 67 .src.y1 = 0, 68 .src.x2 = mode->hdisplay << 16, 69 .src.y2 = mode->vdisplay << 16, 70 .zpos = 0, 71 }, 72 .format = rcar_du_format_info(DRM_FORMAT_ARGB8888), 73 .source = RCAR_DU_PLANE_VSPD1, 74 .colorkey = 0, 75 }; 76 77 if (rcdu->info->gen >= 3) 78 state.hwindex = (crtc->index % 2) ? 2 : 0; 79 else 80 state.hwindex = crtc->index % 2; 81 82 __rcar_du_plane_setup(crtc->group, &state); 83 84 /* 85 * Ensure that the plane source configuration takes effect by requesting 86 * a restart of the group. See rcar_du_plane_atomic_update() for a more 87 * detailed explanation. 88 * 89 * TODO: Check whether this is still needed on Gen3. 90 */ 91 crtc->group->need_restart = true; 92 93 vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); 94} 95 96void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) 97{ 98 vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL); 99} 100 101void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) 102{ 103 vsp1_du_atomic_begin(crtc->vsp->vsp, crtc->vsp_pipe); 104} 105 106void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) 107{ 108 struct vsp1_du_atomic_pipe_config cfg = { { 0, } }; 109 struct rcar_du_crtc_state *state; 110 111 state = to_rcar_crtc_state(crtc->crtc.state); 112 cfg.crc = state->crc; 113 114 rcar_du_writeback_setup(crtc, &cfg.writeback); 115 116 vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); 117} 118 119static const u32 rcar_du_vsp_formats[] = { 120 DRM_FORMAT_RGB332, 121 DRM_FORMAT_ARGB4444, 122 DRM_FORMAT_XRGB4444, 123 DRM_FORMAT_ARGB1555, 124 DRM_FORMAT_XRGB1555, 125 DRM_FORMAT_RGB565, 126 DRM_FORMAT_BGR888, 127 DRM_FORMAT_RGB888, 128 DRM_FORMAT_BGRA8888, 129 DRM_FORMAT_BGRX8888, 130 DRM_FORMAT_ARGB8888, 131 DRM_FORMAT_XRGB8888, 132 DRM_FORMAT_UYVY, 133 DRM_FORMAT_YUYV, 134 DRM_FORMAT_YVYU, 135 DRM_FORMAT_NV12, 136 DRM_FORMAT_NV21, 137 DRM_FORMAT_NV16, 138 DRM_FORMAT_NV61, 139 DRM_FORMAT_YUV420, 140 DRM_FORMAT_YVU420, 141 DRM_FORMAT_YUV422, 142 DRM_FORMAT_YVU422, 143 DRM_FORMAT_YUV444, 144 DRM_FORMAT_YVU444, 145}; 146 147static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) 148{ 149 struct rcar_du_vsp_plane_state *state = 150 to_rcar_vsp_plane_state(plane->plane.state); 151 struct rcar_du_crtc *crtc = to_rcar_crtc(state->state.crtc); 152 struct drm_framebuffer *fb = plane->plane.state->fb; 153 const struct rcar_du_format_info *format; 154 struct vsp1_du_atomic_config cfg = { 155 .pixelformat = 0, 156 .pitch = fb->pitches[0], 157 .alpha = state->state.alpha >> 8, 158 .zpos = state->state.zpos, 159 }; 160 unsigned int i; 161 162 cfg.src.left = state->state.src.x1 >> 16; 163 cfg.src.top = state->state.src.y1 >> 16; 164 cfg.src.width = drm_rect_width(&state->state.src) >> 16; 165 cfg.src.height = drm_rect_height(&state->state.src) >> 16; 166 167 cfg.dst.left = state->state.dst.x1; 168 cfg.dst.top = state->state.dst.y1; 169 cfg.dst.width = drm_rect_width(&state->state.dst); 170 cfg.dst.height = drm_rect_height(&state->state.dst); 171 172 for (i = 0; i < state->format->planes; ++i) 173 cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl) 174 + fb->offsets[i]; 175 176 format = rcar_du_format_info(state->format->fourcc); 177 cfg.pixelformat = format->v4l2; 178 179 vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe, 180 plane->index, &cfg); 181} 182 183int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, 184 struct sg_table sg_tables[3]) 185{ 186 struct rcar_du_device *rcdu = vsp->dev; 187 unsigned int i; 188 int ret; 189 190 for (i = 0; i < fb->format->num_planes; ++i) { 191 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); 192 struct sg_table *sgt = &sg_tables[i]; 193 194 ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, gem->paddr, 195 gem->base.size); 196 if (ret) 197 goto fail; 198 199 ret = vsp1_du_map_sg(vsp->vsp, sgt); 200 if (!ret) { 201 sg_free_table(sgt); 202 ret = -ENOMEM; 203 goto fail; 204 } 205 } 206 207 return 0; 208 209fail: 210 while (i--) { 211 struct sg_table *sgt = &sg_tables[i]; 212 213 vsp1_du_unmap_sg(vsp->vsp, sgt); 214 sg_free_table(sgt); 215 } 216 217 return ret; 218} 219 220static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane, 221 struct drm_plane_state *state) 222{ 223 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); 224 struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; 225 int ret; 226 227 /* 228 * There's no need to prepare (and unprepare) the framebuffer when the 229 * plane is not visible, as it will not be displayed. 230 */ 231 if (!state->visible) 232 return 0; 233 234 ret = rcar_du_vsp_map_fb(vsp, state->fb, rstate->sg_tables); 235 if (ret < 0) 236 return ret; 237 238 return drm_gem_fb_prepare_fb(plane, state); 239} 240 241void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, 242 struct sg_table sg_tables[3]) 243{ 244 unsigned int i; 245 246 for (i = 0; i < fb->format->num_planes; ++i) { 247 struct sg_table *sgt = &sg_tables[i]; 248 249 vsp1_du_unmap_sg(vsp->vsp, sgt); 250 sg_free_table(sgt); 251 } 252} 253 254static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane, 255 struct drm_plane_state *state) 256{ 257 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); 258 struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp; 259 260 if (!state->visible) 261 return; 262 263 rcar_du_vsp_unmap_fb(vsp, state->fb, rstate->sg_tables); 264} 265 266static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, 267 struct drm_plane_state *state) 268{ 269 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); 270 271 return __rcar_du_plane_atomic_check(plane, state, &rstate->format); 272} 273 274static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, 275 struct drm_plane_state *old_state) 276{ 277 struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane); 278 struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc); 279 280 if (plane->state->visible) 281 rcar_du_vsp_plane_setup(rplane); 282 else 283 vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe, 284 rplane->index, NULL); 285} 286 287static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { 288 .prepare_fb = rcar_du_vsp_plane_prepare_fb, 289 .cleanup_fb = rcar_du_vsp_plane_cleanup_fb, 290 .atomic_check = rcar_du_vsp_plane_atomic_check, 291 .atomic_update = rcar_du_vsp_plane_atomic_update, 292}; 293 294static struct drm_plane_state * 295rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) 296{ 297 struct rcar_du_vsp_plane_state *copy; 298 299 if (WARN_ON(!plane->state)) 300 return NULL; 301 302 copy = kzalloc(sizeof(*copy), GFP_KERNEL); 303 if (copy == NULL) 304 return NULL; 305 306 __drm_atomic_helper_plane_duplicate_state(plane, &copy->state); 307 308 return &copy->state; 309} 310 311static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane, 312 struct drm_plane_state *state) 313{ 314 __drm_atomic_helper_plane_destroy_state(state); 315 kfree(to_rcar_vsp_plane_state(state)); 316} 317 318static void rcar_du_vsp_plane_reset(struct drm_plane *plane) 319{ 320 struct rcar_du_vsp_plane_state *state; 321 322 if (plane->state) { 323 rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state); 324 plane->state = NULL; 325 } 326 327 state = kzalloc(sizeof(*state), GFP_KERNEL); 328 if (state == NULL) 329 return; 330 331 __drm_atomic_helper_plane_reset(plane, &state->state); 332 state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; 333} 334 335static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = { 336 .update_plane = drm_atomic_helper_update_plane, 337 .disable_plane = drm_atomic_helper_disable_plane, 338 .reset = rcar_du_vsp_plane_reset, 339 .destroy = drm_plane_cleanup, 340 .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state, 341 .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state, 342}; 343 344int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, 345 unsigned int crtcs) 346{ 347 struct rcar_du_device *rcdu = vsp->dev; 348 struct platform_device *pdev; 349 unsigned int num_crtcs = hweight32(crtcs); 350 unsigned int i; 351 int ret; 352 353 /* Find the VSP device and initialize it. */ 354 pdev = of_find_device_by_node(np); 355 if (!pdev) 356 return -ENXIO; 357 358 vsp->vsp = &pdev->dev; 359 360 ret = vsp1_du_init(vsp->vsp); 361 if (ret < 0) 362 return ret; 363 364 /* 365 * The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to 366 * 4 RPFs. 367 */ 368 vsp->num_planes = rcdu->info->gen >= 3 ? 5 : 4; 369 370 vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes, 371 sizeof(*vsp->planes), GFP_KERNEL); 372 if (!vsp->planes) 373 return -ENOMEM; 374 375 for (i = 0; i < vsp->num_planes; ++i) { 376 enum drm_plane_type type = i < num_crtcs 377 ? DRM_PLANE_TYPE_PRIMARY 378 : DRM_PLANE_TYPE_OVERLAY; 379 struct rcar_du_vsp_plane *plane = &vsp->planes[i]; 380 381 plane->vsp = vsp; 382 plane->index = i; 383 384 ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs, 385 &rcar_du_vsp_plane_funcs, 386 rcar_du_vsp_formats, 387 ARRAY_SIZE(rcar_du_vsp_formats), 388 NULL, type, NULL); 389 if (ret < 0) 390 return ret; 391 392 drm_plane_helper_add(&plane->plane, 393 &rcar_du_vsp_plane_helper_funcs); 394 395 if (type == DRM_PLANE_TYPE_PRIMARY) { 396 drm_plane_create_zpos_immutable_property(&plane->plane, 397 0); 398 } else { 399 drm_plane_create_alpha_property(&plane->plane); 400 drm_plane_create_zpos_property(&plane->plane, 1, 1, 401 vsp->num_planes - 1); 402 } 403 } 404 405 return 0; 406}