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

drm: rcar-du: Add VSP1 compositor support

Configure the plane source at plane setup time to source frames from
memory or from the VSP1.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

+82 -49
+2
drivers/gpu/drm/rcar-du/rcar_du_drv.h
··· 90 90 } props; 91 91 92 92 unsigned int dpad0_source; 93 + unsigned int vspd1_sink; 94 + 93 95 struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS]; 94 96 95 97 struct {
+14 -10
drivers/gpu/drm/rcar-du/rcar_du_group.c
··· 49 49 u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; 50 50 51 51 /* The DEFR8 register for the first group also controls RGB output 52 - * routing to DPAD0 for DU instances that support it. 52 + * routing to DPAD0 and VSPD1 routing to DU0/1/2 for DU instances that 53 + * support it. 53 54 */ 54 - if (rgrp->dev->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs > 1 && 55 - rgrp->index == 0) 56 - defr8 |= DEFR8_DRGBS_DU(rgrp->dev->dpad0_source); 55 + if (rgrp->index == 0) { 56 + if (rgrp->dev->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs > 1) 57 + defr8 |= DEFR8_DRGBS_DU(rgrp->dev->dpad0_source); 58 + if (rgrp->dev->vspd1_sink == 2) 59 + defr8 |= DEFR8_VSCS; 60 + } 57 61 58 62 rcar_du_group_write(rgrp, DEFR8, defr8); 59 63 } ··· 166 162 __rcar_du_group_start_stop(rgrp, true); 167 163 } 168 164 169 - static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu) 165 + int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu) 170 166 { 171 167 int ret; 172 168 173 169 if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) 174 170 return 0; 175 171 176 - /* RGB output routing to DPAD0 is configured in the DEFR8 register of 177 - * the first group. As this function can be called with the DU0 and DU1 178 - * CRTCs disabled, we need to enable the first group clock before 179 - * accessing the register. 172 + /* RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are 173 + * configured in the DEFR8 register of the first group. As this function 174 + * can be called with the DU0 and DU1 CRTCs disabled, we need to enable 175 + * the first group clock before accessing the register. 180 176 */ 181 177 ret = clk_prepare_enable(rcdu->crtcs[0].clock); 182 178 if (ret < 0) ··· 207 203 208 204 rcar_du_group_write(rgrp, DORCR, dorcr); 209 205 210 - return rcar_du_set_dpad0_routing(rgrp->dev); 206 + return rcar_du_set_dpad0_vsp1_routing(rgrp->dev); 211 207 }
+2
drivers/gpu/drm/rcar-du/rcar_du_group.h
··· 58 58 void rcar_du_group_restart(struct rcar_du_group *rgrp); 59 59 int rcar_du_group_set_routing(struct rcar_du_group *rgrp); 60 60 61 + int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu); 62 + 61 63 #endif /* __RCAR_DU_GROUP_H__ */
+12 -4
drivers/gpu/drm/rcar-du/rcar_du_kms.c
··· 217 217 */ 218 218 219 219 static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane, 220 - struct rcar_du_plane_state *state) 220 + struct rcar_du_plane_state *new_state) 221 221 { 222 - const struct rcar_du_format_info *cur_format; 222 + struct rcar_du_plane_state *cur_state; 223 223 224 - cur_format = to_rcar_plane_state(plane->plane.state)->format; 224 + cur_state = to_rcar_plane_state(plane->plane.state); 225 225 226 226 /* Lowering the number of planes doesn't strictly require reallocation 227 227 * as the extra hardware plane will be freed when committing, but doing 228 228 * so could lead to more fragmentation. 229 229 */ 230 - return !cur_format || cur_format->planes != state->format->planes; 230 + if (!cur_state->format || 231 + cur_state->format->planes != new_state->format->planes) 232 + return true; 233 + 234 + /* Reallocate hardware planes if the source has changed. */ 235 + if (cur_state->source != new_state->source) 236 + return true; 237 + 238 + return false; 231 239 } 232 240 233 241 static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state)
+51 -35
drivers/gpu/drm/rcar-du/rcar_du_plane.c
··· 20 20 #include <drm/drm_plane_helper.h> 21 21 22 22 #include "rcar_du_drv.h" 23 + #include "rcar_du_group.h" 23 24 #include "rcar_du_kms.h" 24 25 #include "rcar_du_plane.h" 25 26 #include "rcar_du_regs.h" ··· 36 35 data); 37 36 } 38 37 39 - static void rcar_du_plane_setup_scanout(struct rcar_du_plane *plane) 38 + static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp, 39 + const struct rcar_du_plane_state *state) 40 40 { 41 - struct rcar_du_plane_state *state = 42 - to_rcar_plane_state(plane->plane.state); 43 - struct drm_framebuffer *fb = plane->plane.state->fb; 44 - struct rcar_du_group *rgrp = plane->group; 45 41 unsigned int src_x = state->state.src_x >> 16; 46 42 unsigned int src_y = state->state.src_y >> 16; 47 43 unsigned int index = state->hwindex; 48 - struct drm_gem_cma_object *gem; 49 44 unsigned int pitch; 50 45 bool interlaced; 51 - unsigned int i; 52 46 u32 dma[2]; 53 47 54 48 interlaced = state->state.crtc->state->adjusted_mode.flags 55 49 & DRM_MODE_FLAG_INTERLACE; 56 50 51 + if (state->source == RCAR_DU_PLANE_MEMORY) { 52 + struct drm_framebuffer *fb = state->state.fb; 53 + struct drm_gem_cma_object *gem; 54 + unsigned int i; 55 + 56 + if (state->format->planes == 2) 57 + pitch = fb->pitches[0]; 58 + else 59 + pitch = fb->pitches[0] * 8 / state->format->bpp; 60 + 61 + for (i = 0; i < state->format->planes; ++i) { 62 + gem = drm_fb_cma_get_gem_obj(fb, i); 63 + dma[i] = gem->paddr + fb->offsets[i]; 64 + } 65 + } else { 66 + pitch = state->state.src_w >> 16; 67 + dma[0] = 0; 68 + dma[1] = 0; 69 + } 70 + 57 71 /* Memory pitch (expressed in pixels). Must be doubled for interlaced 58 72 * operation with 32bpp formats. 59 73 */ 60 - if (state->format->planes == 2) 61 - pitch = fb->pitches[0]; 62 - else 63 - pitch = fb->pitches[0] * 8 / state->format->bpp; 64 - 65 - for (i = 0; i < state->format->planes; ++i) { 66 - gem = drm_fb_cma_get_gem_obj(fb, i); 67 - dma[i] = gem->paddr + fb->offsets[i]; 68 - } 69 - 70 74 rcar_du_plane_write(rgrp, index, PnMWR, 71 75 (interlaced && state->format->bpp == 32) ? 72 76 pitch * 2 : pitch); ··· 107 101 } 108 102 } 109 103 110 - static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, 111 - unsigned int index) 104 + static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp, 105 + unsigned int index, 106 + const struct rcar_du_plane_state *state) 112 107 { 113 - struct rcar_du_plane_state *state = 114 - to_rcar_plane_state(plane->plane.state); 115 - struct rcar_du_group *rgrp = plane->group; 116 108 u32 colorkey; 117 109 u32 pnmr; 118 110 ··· 168 164 } 169 165 } 170 166 171 - static void rcar_du_plane_setup_format(struct rcar_du_plane *plane, 172 - unsigned int index) 167 + static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp, 168 + unsigned int index, 169 + const struct rcar_du_plane_state *state) 173 170 { 174 - struct rcar_du_plane_state *state = 175 - to_rcar_plane_state(plane->plane.state); 176 - struct rcar_du_group *rgrp = plane->group; 177 171 u32 ddcr2 = PnDDCR2_CODE; 178 172 u32 ddcr4; 179 173 ··· 181 179 * field in DDCR4. 182 180 */ 183 181 184 - rcar_du_plane_setup_mode(plane, index); 182 + rcar_du_plane_setup_mode(rgrp, index, state); 185 183 186 184 if (state->format->planes == 2) { 187 185 if (state->hwindex != index) { ··· 201 199 rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); 202 200 203 201 ddcr4 = state->format->edf | PnDDCR4_CODE; 202 + if (state->source != RCAR_DU_PLANE_MEMORY) 203 + ddcr4 |= PnDDCR4_VSPS; 204 204 205 205 rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); 206 206 207 207 /* Destination position and size */ 208 - rcar_du_plane_write(rgrp, index, PnDSXR, plane->plane.state->crtc_w); 209 - rcar_du_plane_write(rgrp, index, PnDSYR, plane->plane.state->crtc_h); 210 - rcar_du_plane_write(rgrp, index, PnDPXR, plane->plane.state->crtc_x); 211 - rcar_du_plane_write(rgrp, index, PnDPYR, plane->plane.state->crtc_y); 208 + rcar_du_plane_write(rgrp, index, PnDSXR, state->state.crtc_w); 209 + rcar_du_plane_write(rgrp, index, PnDSYR, state->state.crtc_h); 210 + rcar_du_plane_write(rgrp, index, PnDPXR, state->state.crtc_x); 211 + rcar_du_plane_write(rgrp, index, PnDPYR, state->state.crtc_y); 212 212 213 213 /* Wrap-around and blinking, disabled */ 214 214 rcar_du_plane_write(rgrp, index, PnWASPR, 0); ··· 223 219 { 224 220 struct rcar_du_plane_state *state = 225 221 to_rcar_plane_state(plane->plane.state); 222 + struct rcar_du_group *rgrp = plane->group; 226 223 227 - rcar_du_plane_setup_format(plane, state->hwindex); 224 + rcar_du_plane_setup_format(rgrp, state->hwindex, state); 228 225 if (state->format->planes == 2) 229 - rcar_du_plane_setup_format(plane, (state->hwindex + 1) % 8); 226 + rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8, 227 + state); 230 228 231 - rcar_du_plane_setup_scanout(plane); 229 + rcar_du_plane_setup_scanout(rgrp, state); 230 + 231 + if (state->source == RCAR_DU_PLANE_VSPD1) { 232 + unsigned int vspd1_sink = rgrp->index ? 2 : 0; 233 + struct rcar_du_device *rcdu = rgrp->dev; 234 + 235 + if (rcdu->vspd1_sink != vspd1_sink) { 236 + rcdu->vspd1_sink = vspd1_sink; 237 + rcar_du_set_dpad0_vsp1_routing(rcdu); 238 + } 239 + } 232 240 } 233 241 234 242 static int rcar_du_plane_atomic_check(struct drm_plane *plane,
+1
drivers/gpu/drm/rcar-du/rcar_du_regs.h
··· 389 389 390 390 #define PnDDCR4 0x00190 391 391 #define PnDDCR4_CODE (0x7766 << 16) 392 + #define PnDDCR4_VSPS (1 << 13) 392 393 #define PnDDCR4_SDFS_RGB (0 << 4) 393 394 #define PnDDCR4_SDFS_YC (5 << 4) 394 395 #define PnDDCR4_SDFS_MASK (7 << 4)