Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e240bee authored by Dave Airlie's avatar Dave Airlie
Browse files

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



R-Car DU support for the D3 and E3 SoCs (v4.20)

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/3289904.RCOHkcp7u8@avalon
parents 36c9c3c9 12270207
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -15,10 +15,21 @@ Required properties:
  - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders
  - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders
  - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders
  - "renesas,r8a77990-lvds" for R8A77990 (R-Car E3) compatible LVDS encoders
  - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders

- reg: Base address and length for the memory-mapped registers
- clocks: A phandle + clock-specifier pair for the functional clock
- clocks: A list of phandles + clock-specifier pairs, one for each entry in
  the clock-names property.
- clock-names: Name of the clocks. This property is model-dependent.
  - The functional clock, which mandatory for all models, shall be listed
    first, and shall be named "fck".
  - On R8A77990 and R8A77995, the LVDS encoder can use the EXTAL or
    DU_DOTCLKINx clocks. Those clocks are optional. When supplied they must be
    named "extal" and "dclkin.x" respectively, with "x" being the DU_DOTCLKIN
    numerical index.
  - When the clocks property only contains the functional clock, the
    clock-names property may be omitted.
- resets: A phandle + reset specifier for the module reset

Required nodes:
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ Required Properties:
    - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU
    - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU
    - "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU
    - "renesas,du-r8a77990" for R8A77990 (R-Car E3) compatible DU
    - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU

  - reg: the memory-mapped I/O registers base address and length
@@ -63,6 +64,7 @@ corresponding to each DU output.
 R8A77965 (R-Car M3-N)  DPAD 0         HDMI 0         LVDS 0         -
 R8A77970 (R-Car V3M)   DPAD 0         LVDS 0         -              -
 R8A77980 (R-Car V3H)   DPAD 0         LVDS 0         -              -
 R8A77990 (R-Car E3)    DPAD 0         LVDS 0         LVDS 1         -
 R8A77995 (R-Car D3)    DPAD 0         LVDS 0         LVDS 1         -


+18 −0
Original line number Diff line number Diff line
@@ -45,6 +45,23 @@ static int thc63_attach(struct drm_bridge *bridge)
	return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
}

static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
					const struct drm_display_mode *mode)
{
	/*
	 * The THC63LVD1024 clock frequency range is 8 to 135 MHz in single-in
	 * mode. Note that the limits are different in dual-in, single-out mode,
	 * and will need to be adjusted accordingly.
	 */
	if (mode->clock < 8000)
		return MODE_CLOCK_LOW;

	if (mode->clock > 135000)
		return MODE_CLOCK_HIGH;

	return MODE_OK;
}

static void thc63_enable(struct drm_bridge *bridge)
{
	struct thc63_dev *thc63 = to_thc63(bridge);
@@ -77,6 +94,7 @@ static void thc63_disable(struct drm_bridge *bridge)

static const struct drm_bridge_funcs thc63_bridge_func = {
	.attach	= thc63_attach,
	.mode_valid = thc63_mode_valid,
	.enable = thc63_enable,
	.disable = thc63_disable,
};
+77 −59
Original line number Diff line number Diff line
@@ -57,46 +57,12 @@ static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
		      rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
}

static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
				 u32 clr, u32 set)
void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set)
{
	struct rcar_du_device *rcdu = rcrtc->group->dev;
	u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg);

	rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
}

static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
{
	int ret;

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

	ret = clk_prepare_enable(rcrtc->extclock);
	if (ret < 0)
		goto error_clock;

	ret = rcar_du_group_get(rcrtc->group);
	if (ret < 0)
		goto error_group;

	return 0;

error_group:
	clk_disable_unprepare(rcrtc->extclock);
error_clock:
	clk_disable_unprepare(rcrtc->clock);
	return ret;
}

static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
{
	rcar_du_group_put(rcrtc->group);

	clk_disable_unprepare(rcrtc->extclock);
	clk_disable_unprepare(rcrtc->clock);
	rcrtc->dsysr = (rcrtc->dsysr & ~clr) | set;
	rcar_du_write(rcdu, rcrtc->mmio_offset + DSYSR, rcrtc->dsysr);
}

/* -----------------------------------------------------------------------------
@@ -294,6 +260,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 | div;
	} else if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) {
		/*
		 * Use the LVDS PLL output as the dot clock when outputting to
		 * the LVDS encoder on an SoC that supports this clock routing
		 * option. We use the clock directly in that case, without any
		 * additional divider.
		 */
		escr = ESCR_DCLKSEL_DCLKIN;
	} else {
		struct du_clk_params params = { .diff = (unsigned long)-1 };

@@ -546,6 +520,51 @@ static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
	drm_crtc_vblank_on(&rcrtc->crtc);
}

static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
{
	int ret;

	/*
	 * Guard against double-get, as the function is called from both the
	 * .atomic_enable() and .atomic_begin() handlers.
	 */
	if (rcrtc->initialized)
		return 0;

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

	ret = clk_prepare_enable(rcrtc->extclock);
	if (ret < 0)
		goto error_clock;

	ret = rcar_du_group_get(rcrtc->group);
	if (ret < 0)
		goto error_group;

	rcar_du_crtc_setup(rcrtc);
	rcrtc->initialized = true;

	return 0;

error_group:
	clk_disable_unprepare(rcrtc->extclock);
error_clock:
	clk_disable_unprepare(rcrtc->clock);
	return ret;
}

static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
{
	rcar_du_group_put(rcrtc->group);

	clk_disable_unprepare(rcrtc->extclock);
	clk_disable_unprepare(rcrtc->clock);

	rcrtc->initialized = false;
}

static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{
	bool interlaced;
@@ -556,7 +575,7 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
	 * actively driven).
	 */
	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
	rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
				   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
				   DSYSR_TVM_MASTER);

@@ -624,8 +643,13 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
	/*
	 * Select switch sync mode. This stops display operation and configures
	 * the HSYNC and VSYNC signals as inputs.
	 *
	 * TODO: Find another way to stop the display for DUs that don't support
	 * TVM sync.
	 */
	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
	if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_TVM_SYNC))
		rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK,
					   DSYSR_TVM_SWITCH);

	rcar_du_group_start_stop(rcrtc->group, false);
}
@@ -639,16 +663,7 @@ 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);
}

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

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

@@ -680,14 +694,17 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,

	/*
	 * 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.
	 * We thus need to first get and setup the CRTC in order to configure
	 * planes. We must *not* put the CRTC in .atomic_flush(), as it must be
	 * kept awake until the .atomic_enable() call that will follow. The get
	 * operation in .atomic_enable() will in that case be a no-op, and the
	 * CRTC will be put later in .atomic_disable().
	 *
	 * If a mode set is not in progress the CRTC is enabled, and the
	 * following get call will be a no-op. There is thus no need to belance
	 * it in .atomic_flush() either.
	 */
	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);
@@ -1108,6 +1125,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
	rcrtc->group = rgrp;
	rcrtc->mmio_offset = mmio_offsets[hwindex];
	rcrtc->index = hwindex;
	rcrtc->dsysr = (rcrtc->index % 2 ? 0 : DSYSR_DRES) | DSYSR_TVM_TVSYNC;

	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
		primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe].plane;
+5 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ struct rcar_du_vsp;
 * @mmio_offset: offset of the CRTC registers in the DU MMIO block
 * @index: CRTC software and hardware index
 * @initialized: whether the CRTC has been initialized and clocks enabled
 * @dsysr: cached value of the DSYSR register
 * @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
@@ -50,6 +51,8 @@ struct rcar_du_crtc {
	unsigned int index;
	bool initialized;

	u32 dsysr;

	bool vblank_enable;
	struct drm_pending_vblank_event *event;
	wait_queue_head_t flip_wait;
@@ -103,4 +106,6 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
			       enum rcar_du_output output);
void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);

void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set);

#endif /* __RCAR_DU_CRTC_H__ */
Loading