Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/media into drm-next

The series contains one patch that touches the V4L2 VSP driver. Mauro has
acked it for merge through your tree, it doesn't conflict with anything
scheduled for merge in v4.16 through Mauro's tree.

* 'drm/next/du' of git://linuxtv.org/pinchartl/media:
  drm: rcar-du: Clip planes to screen boundaries
  drm: rcar-du: Share plane atomic check code between Gen2 and Gen3
  v4l: vsp1: Start and stop DRM pipeline independently of planes
  drm: rcar-du: Remove unused CRTC suspend/resume functions
  drm: rcar-du: Implement system suspend/resume support
  drm: rcar-du: Don't set connector DPMS property
  drm: rcar-du: Add R8A7745 support
  drm: rcar-du: Add R8A7743 support
  dt-bindings: display: rcar-du: Document R8A774[35] DU
This commit is contained in:
Dave Airlie 2017-12-05 10:34:46 +10:00
commit c5dd52f653
9 changed files with 187 additions and 128 deletions

View File

@ -3,6 +3,8 @@
Required Properties:
- compatible: must be one of the following.
- "renesas,du-r8a7743" for R8A7743 (RZ/G1M) compatible DU
- "renesas,du-r8a7745" for R8A7745 (RZ/G1E) compatible DU
- "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
- "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
- "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU
@ -27,10 +29,10 @@ Required Properties:
- clock-names: Name of the clocks. This property is model-dependent.
- R8A7779 uses a single functional clock. The clock doesn't need to be
named.
- R8A779[0123456] use one functional clock per channel and one clock per
LVDS encoder (if available). The functional clocks must be named "du.x"
with "x" being the channel numerical index. The LVDS clocks must be
named "lvds.x" with "x" being the LVDS encoder numerical index.
- All other DU instances use one functional clock per channel and one
clock per LVDS encoder (if available). The functional clocks must be
named "du.x" with "x" being the channel numerical index. The LVDS clocks
must be named "lvds.x" with "x" being the LVDS encoder numerical index.
- In addition to the functional and encoder clocks, all DU versions also
support externally supplied pixel clocks. Those clocks are optional.
When supplied they must be named "dclkin.x" with "x" being the input
@ -49,16 +51,18 @@ bindings specified in Documentation/devicetree/bindings/graph.txt.
The following table lists for each supported model the port number
corresponding to each DU output.
Port 0 Port1 Port2 Port3
Port0 Port1 Port2 Port3
-----------------------------------------------------------------------------
R8A7779 (H1) DPAD 0 DPAD 1 - -
R8A7790 (H2) DPAD LVDS 0 LVDS 1 -
R8A7791 (M2-W) DPAD LVDS 0 - -
R8A7792 (V2H) DPAD 0 DPAD 1 - -
R8A7793 (M2-N) DPAD LVDS 0 - -
R8A7794 (E2) DPAD 0 DPAD 1 - -
R8A7795 (H3) DPAD HDMI 0 HDMI 1 LVDS
R8A7796 (M3-W) DPAD HDMI LVDS -
R8A7743 (RZ/G1M) DPAD 0 LVDS 0 - -
R8A7745 (RZ/G1E) DPAD 0 DPAD 1 - -
R8A7779 (R-Car H1) DPAD 0 DPAD 1 - -
R8A7790 (R-Car H2) DPAD 0 LVDS 0 LVDS 1 -
R8A7791 (R-Car M2-W) DPAD 0 LVDS 0 - -
R8A7792 (R-Car V2H) DPAD 0 DPAD 1 - -
R8A7793 (R-Car M2-N) DPAD 0 LVDS 0 - -
R8A7794 (R-Car E2) DPAD 0 DPAD 1 - -
R8A7795 (R-Car H3) DPAD 0 HDMI 0 HDMI 1 LVDS 0
R8A7796 (R-Car M3-W) DPAD 0 HDMI 0 LVDS 0 -
Example: R8A7795 (R-Car H3) ES2.0 DU

View File

@ -319,7 +319,8 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
struct rcar_du_plane *plane = &rcrtc->group->planes[i];
unsigned int j;
if (plane->plane.state->crtc != &rcrtc->crtc)
if (plane->plane.state->crtc != &rcrtc->crtc ||
!plane->plane.state->visible)
continue;
/* Insert the plane in the sorted planes array. */
@ -557,41 +558,6 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
rcar_du_group_start_stop(rcrtc->group, false);
}
void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
{
if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
rcar_du_vsp_disable(rcrtc);
rcar_du_crtc_stop(rcrtc);
rcar_du_crtc_put(rcrtc);
}
void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
{
unsigned int i;
if (!rcrtc->crtc.state->active)
return;
rcar_du_crtc_get(rcrtc);
rcar_du_crtc_setup(rcrtc);
/* Commit the planes state. */
if (!rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
for (i = 0; i < rcrtc->group->num_planes; ++i) {
struct rcar_du_plane *plane = &rcrtc->group->planes[i];
if (plane->plane.state->crtc != &rcrtc->crtc)
continue;
rcar_du_plane_setup(plane);
}
}
rcar_du_crtc_update_planes(rcrtc);
rcar_du_crtc_start(rcrtc);
}
/* -----------------------------------------------------------------------------
* CRTC Functions
*/

View File

@ -22,6 +22,7 @@
#include <linux/wait.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@ -34,6 +35,48 @@
* Device Information
*/
static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
.gen = 2,
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS,
.num_crtcs = 2,
.routes = {
/*
* R8A7743 has one RGB output and one LVDS output
*/
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(1) | BIT(0),
.port = 0,
},
[RCAR_DU_OUTPUT_LVDS0] = {
.possible_crtcs = BIT(0),
.port = 1,
},
},
.num_lvds = 1,
};
static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
.gen = 2,
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS,
.num_crtcs = 2,
.routes = {
/*
* R8A7745 has two RGB outputs
*/
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(0),
.port = 0,
},
[RCAR_DU_OUTPUT_DPAD1] = {
.possible_crtcs = BIT(1),
.port = 1,
},
},
.num_lvds = 0,
};
static const struct rcar_du_device_info rcar_du_r8a7779_info = {
.gen = 2,
.features = 0,
@ -207,6 +250,8 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
};
static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
{ .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
{ .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
{ .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
{ .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
@ -265,9 +310,19 @@ static struct drm_driver rcar_du_driver = {
static int rcar_du_pm_suspend(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
struct drm_atomic_state *state;
drm_kms_helper_poll_disable(rcdu->ddev);
/* TODO Suspend the CRTC */
drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
state = drm_atomic_helper_suspend(rcdu->ddev);
if (IS_ERR(state)) {
drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
drm_kms_helper_poll_enable(rcdu->ddev);
return PTR_ERR(state);
}
rcdu->suspend_state = state;
return 0;
}
@ -276,9 +331,10 @@ static int rcar_du_pm_resume(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
/* TODO Resume the CRTC */
drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
drm_kms_helper_poll_enable(rcdu->ddev);
return 0;
}
#endif

View File

@ -81,6 +81,7 @@ struct rcar_du_device {
struct drm_device *ddev;
struct drm_fbdev_cma *fbdev;
struct drm_atomic_state *suspend_state;
struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
unsigned int num_crtcs;

View File

@ -79,10 +79,6 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
drm_connector_helper_add(connector, &connector_helper_funcs);
connector->dpms = DRM_MODE_DPMS_OFF;
drm_object_property_set_value(&connector->base,
rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
ret = drm_mode_connector_attach_encoder(connector, encoder);
if (ret < 0)
return ret;

View File

@ -332,8 +332,8 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp,
static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp,
const struct rcar_du_plane_state *state)
{
unsigned int src_x = state->state.src_x >> 16;
unsigned int src_y = state->state.src_y >> 16;
unsigned int src_x = state->state.src.x1 >> 16;
unsigned int src_y = state->state.src.y1 >> 16;
unsigned int index = state->hwindex;
unsigned int pitch;
bool interlaced;
@ -357,7 +357,7 @@ static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp,
dma[i] = gem->paddr + fb->offsets[i];
}
} else {
pitch = state->state.src_w >> 16;
pitch = drm_rect_width(&state->state.src) >> 16;
dma[0] = 0;
dma[1] = 0;
}
@ -521,6 +521,7 @@ static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp,
const struct rcar_du_plane_state *state)
{
struct rcar_du_device *rcdu = rgrp->dev;
const struct drm_rect *dst = &state->state.dst;
if (rcdu->info->gen < 3)
rcar_du_plane_setup_format_gen2(rgrp, index, state);
@ -528,10 +529,10 @@ static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp,
rcar_du_plane_setup_format_gen3(rgrp, index, state);
/* Destination position and size */
rcar_du_plane_write(rgrp, index, PnDSXR, state->state.crtc_w);
rcar_du_plane_write(rgrp, index, PnDSYR, state->state.crtc_h);
rcar_du_plane_write(rgrp, index, PnDPXR, state->state.crtc_x);
rcar_du_plane_write(rgrp, index, PnDPYR, state->state.crtc_y);
rcar_du_plane_write(rgrp, index, PnDSXR, drm_rect_width(dst));
rcar_du_plane_write(rgrp, index, PnDSYR, drm_rect_height(dst));
rcar_du_plane_write(rgrp, index, PnDPXR, dst->x1);
rcar_du_plane_write(rgrp, index, PnDPYR, dst->y1);
if (rcdu->info->gen < 3) {
/* Wrap-around and blinking, disabled */
@ -565,27 +566,49 @@ void __rcar_du_plane_setup(struct rcar_du_group *rgrp,
}
}
static int rcar_du_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
int __rcar_du_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state,
const struct rcar_du_format_info **format)
{
struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_device *rcdu = rplane->group->dev;
struct drm_device *dev = plane->dev;
struct drm_crtc_state *crtc_state;
struct drm_rect clip;
int ret;
if (!state->fb || !state->crtc) {
rstate->format = NULL;
if (!state->crtc) {
/*
* The visible field is not reset by the DRM core but only
* updated by drm_plane_helper_check_state(), set it manually.
*/
state->visible = false;
*format = NULL;
return 0;
}
if (state->src_w >> 16 != state->crtc_w ||
state->src_h >> 16 != state->crtc_h) {
dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
return -EINVAL;
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
clip.x1 = 0;
clip.y1 = 0;
clip.x2 = crtc_state->mode.hdisplay;
clip.y2 = crtc_state->mode.vdisplay;
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
if (ret < 0)
return ret;
if (!state->visible) {
*format = NULL;
return 0;
}
rstate->format = rcar_du_format_info(state->fb->format->format);
if (rstate->format == NULL) {
dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
*format = rcar_du_format_info(state->fb->format->format);
if (*format == NULL) {
dev_dbg(dev->dev, "%s: unsupported format %08x\n", __func__,
state->fb->format->format);
return -EINVAL;
}
@ -593,6 +616,14 @@ static int rcar_du_plane_atomic_check(struct drm_plane *plane,
return 0;
}
static int rcar_du_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
return __rcar_du_plane_atomic_check(plane, state, &rstate->format);
}
static void rcar_du_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@ -600,7 +631,7 @@ static void rcar_du_plane_atomic_update(struct drm_plane *plane,
struct rcar_du_plane_state *old_rstate;
struct rcar_du_plane_state *new_rstate;
if (!plane->state->crtc)
if (!plane->state->visible)
return;
rcar_du_plane_setup(rplane);

View File

@ -73,6 +73,10 @@ to_rcar_plane_state(struct drm_plane_state *state)
int rcar_du_atomic_check_planes(struct drm_device *dev,
struct drm_atomic_state *state);
int __rcar_du_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state,
const struct rcar_du_format_info **format);
int rcar_du_planes_init(struct rcar_du_group *rgrp);
void __rcar_du_plane_setup(struct rcar_du_group *rgrp,

View File

@ -55,14 +55,14 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
struct rcar_du_plane_state state = {
.state = {
.crtc = &crtc->crtc,
.crtc_x = 0,
.crtc_y = 0,
.crtc_w = mode->hdisplay,
.crtc_h = mode->vdisplay,
.src_x = 0,
.src_y = 0,
.src_w = mode->hdisplay << 16,
.src_h = mode->vdisplay << 16,
.dst.x1 = 0,
.dst.y1 = 0,
.dst.x2 = mode->hdisplay,
.dst.y2 = mode->vdisplay,
.src.x1 = 0,
.src.y1 = 0,
.src.x2 = mode->hdisplay << 16,
.src.y2 = mode->vdisplay << 16,
.zpos = 0,
},
.format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
@ -178,15 +178,15 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
};
unsigned int i;
cfg.src.left = state->state.src_x >> 16;
cfg.src.top = state->state.src_y >> 16;
cfg.src.width = state->state.src_w >> 16;
cfg.src.height = state->state.src_h >> 16;
cfg.src.left = state->state.src.x1 >> 16;
cfg.src.top = state->state.src.y1 >> 16;
cfg.src.width = drm_rect_width(&state->state.src) >> 16;
cfg.src.height = drm_rect_height(&state->state.src) >> 16;
cfg.dst.left = state->state.crtc_x;
cfg.dst.top = state->state.crtc_y;
cfg.dst.width = state->state.crtc_w;
cfg.dst.height = state->state.crtc_h;
cfg.dst.left = state->state.dst.x1;
cfg.dst.top = state->state.dst.y1;
cfg.dst.width = drm_rect_width(&state->state.dst);
cfg.dst.height = drm_rect_height(&state->state.dst);
for (i = 0; i < state->format->planes; ++i)
cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl)
@ -212,7 +212,11 @@ static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane,
unsigned int i;
int ret;
if (!state->fb)
/*
* There's no need to prepare (and unprepare) the framebuffer when the
* plane is not visible, as it will not be displayed.
*/
if (!state->visible)
return 0;
for (i = 0; i < rstate->format->planes; ++i) {
@ -253,7 +257,7 @@ static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane,
struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp;
unsigned int i;
if (!state->fb)
if (!state->visible)
return;
for (i = 0; i < rstate->format->planes; ++i) {
@ -268,28 +272,8 @@ static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
struct rcar_du_device *rcdu = rplane->vsp->dev;
if (!state->fb || !state->crtc) {
rstate->format = NULL;
return 0;
}
if (state->src_w >> 16 != state->crtc_w ||
state->src_h >> 16 != state->crtc_h) {
dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
return -EINVAL;
}
rstate->format = rcar_du_format_info(state->fb->format->format);
if (rstate->format == NULL) {
dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
state->fb->format->format);
return -EINVAL;
}
return 0;
return __rcar_du_plane_atomic_check(plane, state, &rstate->format);
}
static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
@ -298,7 +282,7 @@ static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc);
if (plane->state->crtc)
if (plane->state->visible)
rcar_du_vsp_plane_setup(rplane);
else
vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe,

View File

@ -84,8 +84,12 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
struct vsp1_drm_pipeline *drm_pipe;
struct vsp1_pipeline *pipe;
struct vsp1_bru *bru;
struct vsp1_entity *entity;
struct vsp1_entity *next;
struct vsp1_dl_list *dl;
struct v4l2_subdev_format format;
const char *bru_name;
unsigned long flags;
unsigned int i;
int ret;
@ -250,6 +254,29 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
/* Configure all entities in the pipeline. */
dl = vsp1_dl_list_get(pipe->output->dlm);
list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity, pipe, dl);
if (entity->ops->configure) {
entity->ops->configure(entity, pipe, dl,
VSP1_ENTITY_PARAMS_INIT);
entity->ops->configure(entity, pipe, dl,
VSP1_ENTITY_PARAMS_RUNTIME);
entity->ops->configure(entity, pipe, dl,
VSP1_ENTITY_PARAMS_PARTITION);
}
}
vsp1_dl_list_commit(dl);
/* Start the pipeline. */
spin_lock_irqsave(&pipe->irqlock, flags);
vsp1_pipeline_run(pipe);
spin_unlock_irqrestore(&pipe->irqlock, flags);
dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
return 0;
@ -488,7 +515,6 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
struct vsp1_entity *next;
struct vsp1_dl_list *dl;
const char *bru_name;
unsigned long flags;
unsigned int i;
int ret;
@ -570,15 +596,6 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
}
vsp1_dl_list_commit(dl);
/* Start or stop the pipeline if needed. */
if (!drm_pipe->enabled && pipe->num_inputs) {
spin_lock_irqsave(&pipe->irqlock, flags);
vsp1_pipeline_run(pipe);
spin_unlock_irqrestore(&pipe->irqlock, flags);
} else if (drm_pipe->enabled && !pipe->num_inputs) {
vsp1_pipeline_stop(pipe);
}
}
EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);