Commit 34a04f2b authored by Laurent Pinchart's avatar Laurent Pinchart

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: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
parent af8ad962
...@@ -90,6 +90,8 @@ struct rcar_du_device { ...@@ -90,6 +90,8 @@ struct rcar_du_device {
} props; } props;
unsigned int dpad0_source; unsigned int dpad0_source;
unsigned int vspd1_sink;
struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS]; struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
struct { struct {
......
...@@ -49,11 +49,15 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) ...@@ -49,11 +49,15 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
u32 defr8 = DEFR8_CODE | DEFR8_DEFE8; u32 defr8 = DEFR8_CODE | DEFR8_DEFE8;
/* The DEFR8 register for the first group also controls RGB output /* The DEFR8 register for the first group also controls RGB output
* routing to DPAD0 for DU instances that support it. * routing to DPAD0 and VSPD1 routing to DU0/1/2 for DU instances that
* support it.
*/ */
if (rgrp->dev->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs > 1 && if (rgrp->index == 0) {
rgrp->index == 0) if (rgrp->dev->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs > 1)
defr8 |= DEFR8_DRGBS_DU(rgrp->dev->dpad0_source); defr8 |= DEFR8_DRGBS_DU(rgrp->dev->dpad0_source);
if (rgrp->dev->vspd1_sink == 2)
defr8 |= DEFR8_VSCS;
}
rcar_du_group_write(rgrp, DEFR8, defr8); rcar_du_group_write(rgrp, DEFR8, defr8);
} }
...@@ -162,17 +166,17 @@ void rcar_du_group_restart(struct rcar_du_group *rgrp) ...@@ -162,17 +166,17 @@ void rcar_du_group_restart(struct rcar_du_group *rgrp)
__rcar_du_group_start_stop(rgrp, true); __rcar_du_group_start_stop(rgrp, true);
} }
static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu) int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu)
{ {
int ret; int ret;
if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS)) if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
return 0; return 0;
/* RGB output routing to DPAD0 is configured in the DEFR8 register of /* RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are
* the first group. As this function can be called with the DU0 and DU1 * configured in the DEFR8 register of the first group. As this function
* CRTCs disabled, we need to enable the first group clock before * can be called with the DU0 and DU1 CRTCs disabled, we need to enable
* accessing the register. * the first group clock before accessing the register.
*/ */
ret = clk_prepare_enable(rcdu->crtcs[0].clock); ret = clk_prepare_enable(rcdu->crtcs[0].clock);
if (ret < 0) if (ret < 0)
...@@ -203,5 +207,5 @@ int rcar_du_group_set_routing(struct rcar_du_group *rgrp) ...@@ -203,5 +207,5 @@ int rcar_du_group_set_routing(struct rcar_du_group *rgrp)
rcar_du_group_write(rgrp, DORCR, dorcr); rcar_du_group_write(rgrp, DORCR, dorcr);
return rcar_du_set_dpad0_routing(rgrp->dev); return rcar_du_set_dpad0_vsp1_routing(rgrp->dev);
} }
...@@ -58,4 +58,6 @@ void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start); ...@@ -58,4 +58,6 @@ void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start);
void rcar_du_group_restart(struct rcar_du_group *rgrp); void rcar_du_group_restart(struct rcar_du_group *rgrp);
int rcar_du_group_set_routing(struct rcar_du_group *rgrp); int rcar_du_group_set_routing(struct rcar_du_group *rgrp);
int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu);
#endif /* __RCAR_DU_GROUP_H__ */ #endif /* __RCAR_DU_GROUP_H__ */
...@@ -217,17 +217,25 @@ static void rcar_du_output_poll_changed(struct drm_device *dev) ...@@ -217,17 +217,25 @@ static void rcar_du_output_poll_changed(struct drm_device *dev)
*/ */
static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane, static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
struct rcar_du_plane_state *state) struct rcar_du_plane_state *new_state)
{ {
const struct rcar_du_format_info *cur_format; struct rcar_du_plane_state *cur_state;
cur_format = to_rcar_plane_state(plane->plane.state)->format; cur_state = to_rcar_plane_state(plane->plane.state);
/* Lowering the number of planes doesn't strictly require reallocation /* Lowering the number of planes doesn't strictly require reallocation
* as the extra hardware plane will be freed when committing, but doing * as the extra hardware plane will be freed when committing, but doing
* so could lead to more fragmentation. * so could lead to more fragmentation.
*/ */
return !cur_format || cur_format->planes != state->format->planes; if (!cur_state->format ||
cur_state->format->planes != new_state->format->planes)
return true;
/* Reallocate hardware planes if the source has changed. */
if (cur_state->source != new_state->source)
return true;
return false;
} }
static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include "rcar_du_drv.h" #include "rcar_du_drv.h"
#include "rcar_du_group.h"
#include "rcar_du_kms.h" #include "rcar_du_kms.h"
#include "rcar_du_plane.h" #include "rcar_du_plane.h"
#include "rcar_du_regs.h" #include "rcar_du_regs.h"
...@@ -35,37 +36,42 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp, ...@@ -35,37 +36,42 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp,
data); data);
} }
static void rcar_du_plane_setup_scanout(struct rcar_du_plane *plane) static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp,
const struct rcar_du_plane_state *state)
{ {
struct rcar_du_plane_state *state =
to_rcar_plane_state(plane->plane.state);
struct drm_framebuffer *fb = plane->plane.state->fb;
struct rcar_du_group *rgrp = plane->group;
unsigned int src_x = state->state.src_x >> 16; unsigned int src_x = state->state.src_x >> 16;
unsigned int src_y = state->state.src_y >> 16; unsigned int src_y = state->state.src_y >> 16;
unsigned int index = state->hwindex; unsigned int index = state->hwindex;
struct drm_gem_cma_object *gem;
unsigned int pitch; unsigned int pitch;
bool interlaced; bool interlaced;
unsigned int i;
u32 dma[2]; u32 dma[2];
interlaced = state->state.crtc->state->adjusted_mode.flags interlaced = state->state.crtc->state->adjusted_mode.flags
& DRM_MODE_FLAG_INTERLACE; & DRM_MODE_FLAG_INTERLACE;
/* Memory pitch (expressed in pixels). Must be doubled for interlaced if (state->source == RCAR_DU_PLANE_MEMORY) {
* operation with 32bpp formats. struct drm_framebuffer *fb = state->state.fb;
*/ struct drm_gem_cma_object *gem;
if (state->format->planes == 2) unsigned int i;
pitch = fb->pitches[0];
else if (state->format->planes == 2)
pitch = fb->pitches[0] * 8 / state->format->bpp; pitch = fb->pitches[0];
else
pitch = fb->pitches[0] * 8 / state->format->bpp;
for (i = 0; i < state->format->planes; ++i) { for (i = 0; i < state->format->planes; ++i) {
gem = drm_fb_cma_get_gem_obj(fb, i); gem = drm_fb_cma_get_gem_obj(fb, i);
dma[i] = gem->paddr + fb->offsets[i]; dma[i] = gem->paddr + fb->offsets[i];
}
} else {
pitch = state->state.src_w >> 16;
dma[0] = 0;
dma[1] = 0;
} }
/* Memory pitch (expressed in pixels). Must be doubled for interlaced
* operation with 32bpp formats.
*/
rcar_du_plane_write(rgrp, index, PnMWR, rcar_du_plane_write(rgrp, index, PnMWR,
(interlaced && state->format->bpp == 32) ? (interlaced && state->format->bpp == 32) ?
pitch * 2 : pitch); pitch * 2 : pitch);
...@@ -101,12 +107,10 @@ static void rcar_du_plane_setup_scanout(struct rcar_du_plane *plane) ...@@ -101,12 +107,10 @@ static void rcar_du_plane_setup_scanout(struct rcar_du_plane *plane)
} }
} }
static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp,
unsigned int index) unsigned int index,
const struct rcar_du_plane_state *state)
{ {
struct rcar_du_plane_state *state =
to_rcar_plane_state(plane->plane.state);
struct rcar_du_group *rgrp = plane->group;
u32 colorkey; u32 colorkey;
u32 pnmr; u32 pnmr;
...@@ -164,12 +168,10 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, ...@@ -164,12 +168,10 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
} }
} }
static void rcar_du_plane_setup_format(struct rcar_du_plane *plane, static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp,
unsigned int index) unsigned int index,
const struct rcar_du_plane_state *state)
{ {
struct rcar_du_plane_state *state =
to_rcar_plane_state(plane->plane.state);
struct rcar_du_group *rgrp = plane->group;
u32 ddcr2 = PnDDCR2_CODE; u32 ddcr2 = PnDDCR2_CODE;
u32 ddcr4; u32 ddcr4;
...@@ -179,7 +181,7 @@ static void rcar_du_plane_setup_format(struct rcar_du_plane *plane, ...@@ -179,7 +181,7 @@ static void rcar_du_plane_setup_format(struct rcar_du_plane *plane,
* field in DDCR4. * field in DDCR4.
*/ */
rcar_du_plane_setup_mode(plane, index); rcar_du_plane_setup_mode(rgrp, index, state);
if (state->format->planes == 2) { if (state->format->planes == 2) {
if (state->hwindex != index) { if (state->hwindex != index) {
...@@ -199,14 +201,16 @@ static void rcar_du_plane_setup_format(struct rcar_du_plane *plane, ...@@ -199,14 +201,16 @@ static void rcar_du_plane_setup_format(struct rcar_du_plane *plane,
rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2);
ddcr4 = state->format->edf | PnDDCR4_CODE; ddcr4 = state->format->edf | PnDDCR4_CODE;
if (state->source != RCAR_DU_PLANE_MEMORY)
ddcr4 |= PnDDCR4_VSPS;
rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
/* Destination position and size */ /* Destination position and size */
rcar_du_plane_write(rgrp, index, PnDSXR, plane->plane.state->crtc_w); rcar_du_plane_write(rgrp, index, PnDSXR, state->state.crtc_w);
rcar_du_plane_write(rgrp, index, PnDSYR, plane->plane.state->crtc_h); rcar_du_plane_write(rgrp, index, PnDSYR, state->state.crtc_h);
rcar_du_plane_write(rgrp, index, PnDPXR, plane->plane.state->crtc_x); rcar_du_plane_write(rgrp, index, PnDPXR, state->state.crtc_x);
rcar_du_plane_write(rgrp, index, PnDPYR, plane->plane.state->crtc_y); rcar_du_plane_write(rgrp, index, PnDPYR, state->state.crtc_y);
/* Wrap-around and blinking, disabled */ /* Wrap-around and blinking, disabled */
rcar_du_plane_write(rgrp, index, PnWASPR, 0); rcar_du_plane_write(rgrp, index, PnWASPR, 0);
...@@ -219,12 +223,24 @@ void rcar_du_plane_setup(struct rcar_du_plane *plane) ...@@ -219,12 +223,24 @@ void rcar_du_plane_setup(struct rcar_du_plane *plane)
{ {
struct rcar_du_plane_state *state = struct rcar_du_plane_state *state =
to_rcar_plane_state(plane->plane.state); to_rcar_plane_state(plane->plane.state);
struct rcar_du_group *rgrp = plane->group;
rcar_du_plane_setup_format(plane, state->hwindex); rcar_du_plane_setup_format(rgrp, state->hwindex, state);
if (state->format->planes == 2) if (state->format->planes == 2)
rcar_du_plane_setup_format(plane, (state->hwindex + 1) % 8); rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8,
state);
rcar_du_plane_setup_scanout(rgrp, state);
rcar_du_plane_setup_scanout(plane); if (state->source == RCAR_DU_PLANE_VSPD1) {
unsigned int vspd1_sink = rgrp->index ? 2 : 0;
struct rcar_du_device *rcdu = rgrp->dev;
if (rcdu->vspd1_sink != vspd1_sink) {
rcdu->vspd1_sink = vspd1_sink;
rcar_du_set_dpad0_vsp1_routing(rcdu);
}
}
} }
static int rcar_du_plane_atomic_check(struct drm_plane *plane, static int rcar_du_plane_atomic_check(struct drm_plane *plane,
......
...@@ -389,6 +389,7 @@ ...@@ -389,6 +389,7 @@
#define PnDDCR4 0x00190 #define PnDDCR4 0x00190
#define PnDDCR4_CODE (0x7766 << 16) #define PnDDCR4_CODE (0x7766 << 16)
#define PnDDCR4_VSPS (1 << 13)
#define PnDDCR4_SDFS_RGB (0 << 4) #define PnDDCR4_SDFS_RGB (0 << 4)
#define PnDDCR4_SDFS_YC (5 << 4) #define PnDDCR4_SDFS_YC (5 << 4)
#define PnDDCR4_SDFS_MASK (7 << 4) #define PnDDCR4_SDFS_MASK (7 << 4)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment