Commit 9f589b20 authored by Dave Airlie's avatar Dave Airlie
Browse files

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

rcar-du updates, contains vsp1 updates as well.

* tag 'drm-next-du-20170803' of git://linuxtv.org/pinchartl/media: (24 commits)
  drm: rcar-du: Use new iterator macros
  drm: rcar-du: Repair vblank for DRM page flips using the VSP
  drm: rcar-du: Fix race condition when disabling planes at CRTC stop
  drm: rcar-du: Wait for flip completion instead of vblank in commit tail
  drm: rcar-du: Use the VBK interrupt for vblank events
  drm: rcar-du: Add HDMI outputs to R8A7796 device description
  drm: rcar-du: Remove an unneeded NULL check
  drm: rcar-du: Setup planes before enabling CRTC to avoid flicker
  drm: rcar-du: Configure DPAD0 routing through last group on Gen3
  drm: rcar-du: Restrict DPLL duty cycle workaround to H3 ES1.x
  drm: rcar-du: Support multiple sources from the same VSP
  drm: rcar-du: Fix comments to comply with the kernel coding style
  drm: rcar-du: Use of_graph_get_remote_endpoint()
  v4l: vsp1: Add support for header display lists in continuous mode
  v4l: vsp1: Add support for multiple DRM pipelines
  v4l: vsp1: Add support for multiple LIF instances
  v4l: vsp1: Add support for new VSP2-BS, VSP2-DL and VSP2-D instances
  v4l: vsp1: Add support for the BRS entity
  v4l: vsp1: Add pipe index argument to the VSP-DU API
  v4l: vsp1: Don't create links for DRM pipeline
  ...
parents dd24df65 a01ce667
Loading
Loading
Loading
Loading
+138 −51
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/sys_soc.h>

#include <drm/drmP.h>
#include <drm/drm_atomic.h>
@@ -129,10 +130,8 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc,
			for (fdpll = 1; fdpll < 32; fdpll++) {
				unsigned long output;

				/* 1/2 (FRQSEL=1) for duty rate 50% */
				output = input * (n + 1) / (m + 1)
				       / (fdpll + 1) / 2;

				       / (fdpll + 1);
				if (output >= 400000000)
					continue;

@@ -158,6 +157,11 @@ done:
		 best_diff);
}

static const struct soc_device_attribute rcar_du_r8a7795_es1[] = {
	{ .soc_id = "r8a7795", .revision = "ES1.*" },
	{ /* sentinel */ }
};

static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
	const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
@@ -168,7 +172,8 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
	u32 escr;
	u32 div;

	/* Compute the clock divisor and select the internal or external dot
	/*
	 * Compute the clock divisor and select the internal or external dot
	 * clock based on the requested frequency.
	 */
	clk = clk_get_rate(rcrtc->clock);
@@ -185,7 +190,20 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)

		extclk = clk_get_rate(rcrtc->extclock);
		if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
			rcar_du_dpll_divider(rcrtc, &dpll, extclk, mode_clock);
			unsigned long target = mode_clock;

			/*
			 * The H3 ES1.x exhibits dot clock duty cycle stability
			 * issues. We can work around them by configuring the
			 * DPLL to twice the desired frequency, coupled with a
			 * /2 post-divider. This isn't needed on other SoCs and
			 * breaks HDMI output on M3-W for a currently unknown
			 * reason, so restrict the workaround to H3 ES1.x.
			 */
			if (soc_device_match(rcar_du_r8a7795_es1))
				target *= 2;

			rcar_du_dpll_divider(rcrtc, &dpll, extclk, target);
			extclk = dpll.output;
		}

@@ -197,8 +215,6 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)

		if (abs((long)extrate - (long)mode_clock) <
		    abs((long)rate - (long)mode_clock)) {
			dev_dbg(rcrtc->group->dev->dev,
				"crtc%u: using external clock\n", rcrtc->index);

			if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
				u32 dpllcr = DPLLCR_CODE | DPLLCR_CLKE
@@ -215,12 +231,14 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)

				rcar_du_group_write(rcrtc->group, DPLLCR,
						    dpllcr);
			}

				escr = ESCR_DCLKSEL_DCLKIN | 1;
			} else {
			escr = ESCR_DCLKSEL_DCLKIN | extdiv;
		}
		}

		dev_dbg(rcrtc->group->dev->dev,
			"mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
			mode_clock, extrate, rate, escr);
	}

	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
@@ -261,12 +279,14 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
	struct rcar_du_device *rcdu = rcrtc->group->dev;

	/* Store the route from the CRTC output to the DU output. The DU will be
	/*
	 * Store the route from the CRTC output to the DU output. The DU will be
	 * configured when starting the CRTC.
	 */
	rcrtc->outputs |= BIT(output);

	/* Store RGB routing to DPAD0, the hardware will be configured when
	/*
	 * Store RGB routing to DPAD0, the hardware will be configured when
	 * starting the CRTC.
	 */
	if (output == RCAR_DU_OUTPUT_DPAD0)
@@ -342,7 +362,8 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
		}
	}

	/* Update the planes to display timing and dot clock generator
	/*
	 * Update the planes to display timing and dot clock generator
	 * associations.
	 *
	 * Updating the DPTSR register requires restarting the CRTC group,
@@ -431,14 +452,8 @@ static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc)
 * Start/Stop and Suspend/Resume
 */

static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
{
	struct drm_crtc *crtc = &rcrtc->crtc;
	bool interlaced;

	if (rcrtc->started)
		return;

	/* Set display off and background to black */
	rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
	rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
@@ -450,7 +465,20 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
	/* Start with all planes disabled. */
	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);

	/* Select master sync mode. This enables display operation in master
	/* Enable the VSP compositor. */
	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
		rcar_du_vsp_enable(rcrtc);

	/* Turn vertical blanking interrupt reporting on. */
	drm_crtc_vblank_on(&rcrtc->crtc);
}

static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{
	bool interlaced;

	/*
	 * Select master sync mode. This enables display operation in master
	 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
	 * actively driven).
	 */
@@ -460,38 +488,56 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
			     DSYSR_TVM_MASTER);

	rcar_du_group_start_stop(rcrtc->group, true);
}

	/* Enable the VSP compositor. */
	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
		rcar_du_vsp_enable(rcrtc);
static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
{
	struct rcar_du_device *rcdu = rcrtc->group->dev;
	struct drm_crtc *crtc = &rcrtc->crtc;
	u32 status;

	/* Make sure vblank interrupts are enabled. */
	drm_crtc_vblank_get(crtc);

	/*
	 * Disable planes and calculate how many vertical blanking interrupts we
	 * have to wait for. If a vertical blanking interrupt has been triggered
	 * but not processed yet, we don't know whether it occurred before or
	 * after the planes got disabled. We thus have to wait for two vblank
	 * interrupts in that case.
	 */
	spin_lock_irq(&rcrtc->vblank_lock);
	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
	status = rcar_du_crtc_read(rcrtc, DSSR);
	rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
	spin_unlock_irq(&rcrtc->vblank_lock);

	/* Turn vertical blanking interrupt reporting back on. */
	drm_crtc_vblank_on(crtc);
	if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
				msecs_to_jiffies(100)))
		dev_warn(rcdu->dev, "vertical blanking timeout\n");

	rcrtc->started = true;
	drm_crtc_vblank_put(crtc);
}

static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
{
	struct drm_crtc *crtc = &rcrtc->crtc;

	if (!rcrtc->started)
		return;

	/* Disable all planes and wait for the change to take effect. This is
	 * required as the DSnPR registers are updated on vblank, and no vblank
	 * will occur once the CRTC is stopped. Disabling planes when starting
	 * the CRTC thus wouldn't be enough as it would start scanning out
	 * immediately from old frame buffers until the next vblank.
	/*
	 * Disable all planes and wait for the change to take effect. This is
	 * required as the plane enable registers are updated on vblank, and no
	 * vblank will occur once the CRTC is stopped. Disabling planes when
	 * starting the CRTC thus wouldn't be enough as it would start scanning
	 * out immediately from old frame buffers until the next vblank.
	 *
	 * This increases the CRTC stop delay, especially when multiple CRTCs
	 * are stopped in one operation as we now wait for one vblank per CRTC.
	 * Whether this can be improved needs to be researched.
	 */
	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
	drm_crtc_wait_one_vblank(crtc);
	rcar_du_crtc_disable_planes(rcrtc);

	/* Disable vertical blanking interrupt reporting. We first need to wait
	/*
	 * Disable vertical blanking interrupt reporting. We first need to wait
	 * for page flip completion before stopping the CRTC as userspace
	 * expects page flips to eventually complete.
	 */
@@ -502,14 +548,13 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
		rcar_du_vsp_disable(rcrtc);

	/* Select switch sync mode. This stops display operation and configures
	/*
	 * Select switch sync mode. This stops display operation and configures
	 * the HSYNC and VSYNC signals as inputs.
	 */
	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);

	rcar_du_group_start_stop(rcrtc->group, false);

	rcrtc->started = false;
}

void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
@@ -529,12 +574,10 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
		return;

	rcar_du_crtc_get(rcrtc);
	rcar_du_crtc_start(rcrtc);
	rcar_du_crtc_setup(rcrtc);

	/* Commit the planes state. */
	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
		rcar_du_vsp_enable(rcrtc);
	} else {
	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];

@@ -546,6 +589,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
	}

	rcar_du_crtc_update_planes(rcrtc);
	rcar_du_crtc_start(rcrtc);
}

/* -----------------------------------------------------------------------------
@@ -557,7 +601,16 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
{
	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);

	/*
	 * If the CRTC has already been setup by the .atomic_begin() handler we
	 * can skip the setup stage.
	 */
	if (!rcrtc->initialized) {
		rcar_du_crtc_get(rcrtc);
		rcar_du_crtc_setup(rcrtc);
		rcrtc->initialized = true;
	}

	rcar_du_crtc_start(rcrtc);
}

@@ -576,6 +629,7 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
	}
	spin_unlock_irq(&crtc->dev->event_lock);

	rcrtc->initialized = false;
	rcrtc->outputs = 0;
}

@@ -584,6 +638,19 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
{
	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);

	WARN_ON(!crtc->state->enable);

	/*
	 * If a mode set is in progress we can be called with the CRTC disabled.
	 * We then need to first setup the CRTC in order to configure planes.
	 * The .atomic_enable() handler will notice and skip the CRTC setup.
	 */
	if (!rcrtc->initialized) {
		rcar_du_crtc_get(rcrtc);
		rcar_du_crtc_setup(rcrtc);
		rcrtc->initialized = true;
	}

	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
		rcar_du_vsp_atomic_begin(rcrtc);
}
@@ -623,6 +690,7 @@ static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc)

	rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL);
	rcar_du_crtc_set(rcrtc, DIER, DIER_VBE);
	rcrtc->vblank_enable = true;

	return 0;
}
@@ -632,6 +700,7 @@ static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc)
	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);

	rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE);
	rcrtc->vblank_enable = false;
}

static const struct drm_crtc_funcs crtc_funcs = {
@@ -656,14 +725,30 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
	irqreturn_t ret = IRQ_NONE;
	u32 status;

	spin_lock(&rcrtc->vblank_lock);

	status = rcar_du_crtc_read(rcrtc, DSSR);
	rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);

	if (status & DSSR_FRM) {
		drm_crtc_handle_vblank(&rcrtc->crtc);
	if (status & DSSR_VBK) {
		/*
		 * Wake up the vblank wait if the counter reaches 0. This must
		 * be protected by the vblank_lock to avoid races in
		 * rcar_du_crtc_disable_planes().
		 */
		if (rcrtc->vblank_count) {
			if (--rcrtc->vblank_count == 0)
				wake_up(&rcrtc->vblank_wait);
		}
	}

		if (rcdu->info->gen < 3)
	spin_unlock(&rcrtc->vblank_lock);

	if (status & DSSR_VBK) {
		if (rcdu->info->gen < 3) {
			drm_crtc_handle_vblank(&rcrtc->crtc);
			rcar_du_crtc_finish_page_flip(rcrtc);
		}

		ret = IRQ_HANDLED;
	}
@@ -717,13 +802,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
	}

	init_waitqueue_head(&rcrtc->flip_wait);
	init_waitqueue_head(&rcrtc->vblank_wait);
	spin_lock_init(&rcrtc->vblank_lock);

	rcrtc->group = rgrp;
	rcrtc->mmio_offset = mmio_offsets[index];
	rcrtc->index = index;

	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
		primary = &rcrtc->vsp->planes[0].plane;
		primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe].plane;
	else
		primary = &rgrp->planes[index % 2].plane;

+15 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define __RCAR_DU_CRTC_H__

#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/wait.h>

#include <drm/drmP.h>
@@ -30,11 +31,17 @@ struct rcar_du_vsp;
 * @extclock: external pixel dot clock (optional)
 * @mmio_offset: offset of the CRTC registers in the DU MMIO block
 * @index: CRTC software and hardware index
 * @started: whether the CRTC has been started and is running
 * @initialized: whether the CRTC has been initialized and clocks enabled
 * @vblank_enable: whether vblank events are enabled on this CRTC
 * @event: event to post when the pending page flip completes
 * @flip_wait: wait queue used to signal page flip completion
 * @vblank_lock: protects vblank_wait and vblank_count
 * @vblank_wait: wait queue used to signal vertical blanking
 * @vblank_count: number of vertical blanking interrupts to wait for
 * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
 * @group: CRTC group this CRTC belongs to
 * @vsp: VSP feeding video to this CRTC
 * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
 */
struct rcar_du_crtc {
	struct drm_crtc crtc;
@@ -43,15 +50,21 @@ struct rcar_du_crtc {
	struct clk *extclock;
	unsigned int mmio_offset;
	unsigned int index;
	bool started;
	bool initialized;

	bool vblank_enable;
	struct drm_pending_vblank_event *event;
	wait_queue_head_t flip_wait;

	spinlock_t vblank_lock;
	wait_queue_head_t vblank_wait;
	unsigned int vblank_count;

	unsigned int outputs;

	struct rcar_du_group *group;
	struct rcar_du_vsp *vsp;
	unsigned int vsp_pipe;
};

#define to_rcar_crtc(c)	container_of(c, struct rcar_du_crtc, crtc)
+20 −8
Original line number Diff line number Diff line
@@ -39,7 +39,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
	.features = 0,
	.num_crtcs = 2,
	.routes = {
		/* R8A7779 has two RGB outputs and one (currently unsupported)
		/*
		 * R8A7779 has two RGB outputs and one (currently unsupported)
		 * TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
@@ -61,7 +62,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
	.num_crtcs = 3,
	.routes = {
		/* R8A7790 has one RGB output, two LVDS outputs and one
		/*
		 * R8A7790 has one RGB output, two LVDS outputs and one
		 * (currently unsupported) TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
@@ -87,7 +89,8 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = {
		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
	.num_crtcs = 2,
	.routes = {
		/* R8A779[13] has one RGB output, one LVDS output and one
		/*
		 * R8A779[13] has one RGB output, one LVDS output and one
		 * (currently unsupported) TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
@@ -127,7 +130,8 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = {
		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
	.num_crtcs = 2,
	.routes = {
		/* R8A7794 has two RGB outputs and one (currently unsupported)
		/*
		 * R8A7794 has two RGB outputs and one (currently unsupported)
		 * TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
@@ -149,7 +153,8 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
		  | RCAR_DU_FEATURE_VSP1_SOURCE,
	.num_crtcs = 4,
	.routes = {
		/* R8A7795 has one RGB output, two HDMI outputs and one
		/*
		 * R8A7795 has one RGB output, two HDMI outputs and one
		 * LVDS output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
@@ -180,19 +185,25 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
		  | RCAR_DU_FEATURE_VSP1_SOURCE,
	.num_crtcs = 3,
	.routes = {
		/* R8A7796 has one RGB output, one LVDS output and one
		 * (currently unsupported) HDMI output.
		/*
		 * R8A7796 has one RGB output, one LVDS output and one HDMI
		 * output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
			.possible_crtcs = BIT(2),
			.port = 0,
		},
		[RCAR_DU_OUTPUT_HDMI0] = {
			.possible_crtcs = BIT(1),
			.port = 1,
		},
		[RCAR_DU_OUTPUT_LVDS0] = {
			.possible_crtcs = BIT(0),
			.port = 2,
		},
	},
	.num_lvds = 1,
	.dpll_ch =  BIT(1),
};

static const struct of_device_id rcar_du_of_table[] = {
@@ -341,7 +352,8 @@ static int rcar_du_probe(struct platform_device *pdev)

	ddev->irq_enabled = 1;

	/* Register the DRM device with the core and the connectors with
	/*
	 * Register the DRM device with the core and the connectors with
	 * sysfs.
	 */
	ret = drm_dev_register(ddev, 0);
+26 −12
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
	if (rcdu->info->gen < 3) {
		defr8 |= DEFR8_DEFE8;

		/* On Gen2 the DEFR8 register for the first group also controls
		/*
		 * On Gen2 the DEFR8 register for the first group also controls
		 * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for
		 * DU instances that support it.
		 */
@@ -75,7 +76,8 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
				defr8 |= DEFR8_VSCS;
		}
	} else {
		/* On Gen3 VSPD routing can't be configured, but DPAD routing
		/*
		 * On Gen3 VSPD routing can't be configured, but DPAD routing
		 * needs to be set despite having a single option available.
		 */
		u32 crtc = ffs(possible_crtcs) - 1;
@@ -124,7 +126,8 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
	if (rcdu->info->gen >= 3)
		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);

	/* Use DS1PR and DS2PR to configure planes priorities and connects the
	/*
	 * Use DS1PR and DS2PR to configure planes priorities and connects the
	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
	 */
	rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
@@ -177,7 +180,8 @@ static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)

void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
{
	/* Many of the configuration bits are only updated when the display
	/*
	 * Many of the configuration bits are only updated when the display
	 * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some
	 * of those bits could be pre-configured, but others (especially the
	 * bits related to plane assignment to display timing controllers) need
@@ -208,23 +212,32 @@ void rcar_du_group_restart(struct rcar_du_group *rgrp)

int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu)
{
	struct rcar_du_group *rgrp;
	struct rcar_du_crtc *crtc;
	unsigned int index;
	int ret;

	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
		return 0;

	/* RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are
	 * configured in the DEFR8 register of the first group. As this function
	 * can be called with the DU0 and DU1 CRTCs disabled, we need to enable
	 * the first group clock before accessing the register.
	/*
	 * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are
	 * configured in the DEFR8 register of the first group on Gen2 and the
	 * last group on Gen3. As this function can be called with the DU
	 * channels of the corresponding CRTCs disabled, we need to enable the
	 * group clock before accessing the register.
	 */
	ret = clk_prepare_enable(rcdu->crtcs[0].clock);
	index = rcdu->info->gen < 3 ? 0 : DIV_ROUND_UP(rcdu->num_crtcs, 2) - 1;
	rgrp = &rcdu->groups[index];
	crtc = &rcdu->crtcs[index * 2];

	ret = clk_prepare_enable(crtc->clock);
	if (ret < 0)
		return ret;

	rcar_du_group_setup_defr8(&rcdu->groups[0]);
	rcar_du_group_setup_defr8(rgrp);

	clk_disable_unprepare(rcdu->crtcs[0].clock);
	clk_disable_unprepare(crtc->clock);

	return 0;
}
@@ -236,7 +249,8 @@ int rcar_du_group_set_routing(struct rcar_du_group *rgrp)

	dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);

	/* Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and
	/*
	 * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and
	 * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1
	 * by default.
	 */
+93 −20
Original line number Diff line number Diff line
@@ -96,7 +96,8 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = {
		.pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
		.edf = PnDDCR4_EDF_NONE,
	},
	/* The following formats are not supported on Gen2 and thus have no
	/*
	 * The following formats are not supported on Gen2 and thus have no
	 * associated .pnmr or .edf settings.
	 */
	{
@@ -153,7 +154,8 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
	unsigned int align;

	/* The R8A7779 DU requires a 16 pixels pitch alignment as documented,
	/*
	 * The R8A7779 DU requires a 16 pixels pitch alignment as documented,
	 * but the R8A7790 DU seems to require a 128 bytes pitch alignment.
	 */
	if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
@@ -255,12 +257,12 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)

	/* Apply the atomic update. */
	drm_atomic_helper_commit_modeset_disables(dev, old_state);
	drm_atomic_helper_commit_modeset_enables(dev, old_state);
	drm_atomic_helper_commit_planes(dev, old_state,
					DRM_PLANE_COMMIT_ACTIVE_ONLY);
	drm_atomic_helper_commit_modeset_enables(dev, old_state);

	drm_atomic_helper_commit_hw_done(old_state);
	drm_atomic_helper_wait_for_vblanks(dev, old_state);
	drm_atomic_helper_wait_for_flip_done(dev, old_state);

	drm_atomic_helper_cleanup_planes(dev, old_state);
}
@@ -309,7 +311,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
		return -ENODEV;
	}

	entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
	entity_ep_node = of_graph_get_remote_endpoint(ep->local_node);

	for_each_endpoint_of_node(entity, ep_node) {
		if (ep_node == entity_ep_node)
@@ -419,7 +421,8 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu)
	if (rcdu->props.alpha == NULL)
		return -ENOMEM;

	/* The color key is expressed as an RGB888 triplet stored in a 32-bit
	/*
	 * The color key is expressed as an RGB888 triplet stored in a 32-bit
	 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
	 * or enable source color keying (1).
	 */
@@ -432,6 +435,81 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu)
	return 0;
}

static int rcar_du_vsps_init(struct rcar_du_device *rcdu)
{
	const struct device_node *np = rcdu->dev->of_node;
	struct of_phandle_args args;
	struct {
		struct device_node *np;
		unsigned int crtcs_mask;
	} vsps[RCAR_DU_MAX_VSPS] = { { 0, }, };
	unsigned int vsps_count = 0;
	unsigned int cells;
	unsigned int i;
	int ret;

	/*
	 * First parse the DT vsps property to populate the list of VSPs. Each
	 * entry contains a pointer to the VSP DT node and a bitmask of the
	 * connected DU CRTCs.
	 */
	cells = of_property_count_u32_elems(np, "vsps") / rcdu->num_crtcs - 1;
	if (cells > 1)
		return -EINVAL;

	for (i = 0; i < rcdu->num_crtcs; ++i) {
		unsigned int j;

		ret = of_parse_phandle_with_fixed_args(np, "vsps", cells, i,
						       &args);
		if (ret < 0)
			goto error;

		/*
		 * Add the VSP to the list or update the corresponding existing
		 * entry if the VSP has already been added.
		 */
		for (j = 0; j < vsps_count; ++j) {
			if (vsps[j].np == args.np)
				break;
		}

		if (j < vsps_count)
			of_node_put(args.np);
		else
			vsps[vsps_count++].np = args.np;

		vsps[j].crtcs_mask |= BIT(i);

		/* Store the VSP pointer and pipe index in the CRTC. */
		rcdu->crtcs[i].vsp = &rcdu->vsps[j];
		rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0;
	}

	/*
	 * Then initialize all the VSPs from the node pointers and CRTCs bitmask
	 * computed previously.
	 */
	for (i = 0; i < vsps_count; ++i) {
		struct rcar_du_vsp *vsp = &rcdu->vsps[i];

		vsp->index = i;
		vsp->dev = rcdu;

		ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask);
		if (ret < 0)
			goto error;
	}

	return 0;

error:
	for (i = 0; i < ARRAY_SIZE(vsps); ++i)
		of_node_put(vsps[i].np);

	return ret;
}

int rcar_du_modeset_init(struct rcar_du_device *rcdu)
{
	static const unsigned int mmio_offsets[] = {
@@ -461,7 +539,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
	if (ret < 0)
		return ret;

	/* Initialize vertical blanking interrupts handling. Start with vblank
	/*
	 * Initialize vertical blanking interrupts handling. Start with vblank
	 * disabled for all CRTCs.
	 */
	ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
@@ -481,7 +560,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
		rgrp->index = i;
		rgrp->num_crtcs = min(rcdu->num_crtcs - 2 * i, 2U);

		/* If we have more than one CRTCs in this group pre-associate
		/*
		 * If we have more than one CRTCs in this group pre-associate
		 * the low-order planes with CRTC 0 and the high-order planes
		 * with CRTC 1 to minimize flicker occurring when the
		 * association is changed.
@@ -499,18 +579,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)

	/* Initialize the compositors. */
	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
		for (i = 0; i < rcdu->num_crtcs; ++i) {
			struct rcar_du_vsp *vsp = &rcdu->vsps[i];

			vsp->index = i;
			vsp->dev = rcdu;
			rcdu->crtcs[i].vsp = vsp;

			ret = rcar_du_vsp_init(vsp);
		ret = rcar_du_vsps_init(rcdu);
		if (ret < 0)
			return ret;
	}
	}

	/* Create the CRTCs. */
	for (i = 0; i < rcdu->num_crtcs; ++i) {
@@ -537,7 +609,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)

	num_encoders = ret;

	/* Set the possible CRTCs and possible clones. There's always at least
	/*
	 * Set the possible CRTCs and possible clones. There's always at least
	 * one way for all encoders to clone each other, set all bits in the
	 * possible clones field.
	 */
Loading