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

Commit e53a2079 authored by Dave Airlie's avatar Dave Airlie
Browse files

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

LVDS startup fixes, enable VSP compositor on GEN3

* 'drm/next/du' of git://linuxtv.org/pinchartl/media:
  drm: rcar-du: lvds: Refactor LVDS startup
  drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen3
  drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen2
  drm: rcar-du: lvds: Fix LVDS clock frequency range
  drm: rcar-du: lvds: Fix LVDCR1 for R-Car gen3
  drm: rcar-du: Enable VSP compositor by default on Gen3
  drm: rcar-du: Calculate DPLLCR to be more small jitter
  drm: rcar-du: Use 1000 to avoid misunderstanding in rcar_du_dpll_divider()
  drm: rcar-du: Remove zpos field from rcar_du_vsp_plane_state structure
parents 933519a5 871dfe7b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -26,7 +26,8 @@ config DRM_RCAR_LVDS
	  Enable support for the R-Car Display Unit embedded LVDS encoders.

config DRM_RCAR_VSP
	bool "R-Car DU VSP Compositor Support"
	bool "R-Car DU VSP Compositor Support" if ARM
	default y if ARM64
	depends on DRM_RCAR_DU
	depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m)
	help
+46 −5
Original line number Diff line number Diff line
@@ -125,14 +125,55 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc,
	unsigned int m;
	unsigned int n;

	for (n = 39; n < 120; n++) {
	/*
	 *   fin                                 fvco        fout       fclkout
	 * in --> [1/M] --> |PD| -> [LPF] -> [VCO] -> [1/P] -+-> [1/FDPLL] -> out
	 *              +-> |  |                             |
	 *              |                                    |
	 *              +---------------- [1/N] <------------+
	 *
	 *	fclkout = fvco / P / FDPLL -- (1)
	 *
	 * fin/M = fvco/P/N
	 *
	 *	fvco = fin * P *  N / M -- (2)
	 *
	 * (1) + (2) indicates
	 *
	 *	fclkout = fin * N / M / FDPLL
	 *
	 * NOTES
	 *	N	: (n + 1)
	 *	M	: (m + 1)
	 *	FDPLL	: (fdpll + 1)
	 *	P	: 2
	 *	2kHz < fvco < 4096MHz
	 *
	 * To minimize the jitter,
	 * N : as large as possible
	 * M : as small as possible
	 */
	for (m = 0; m < 4; m++) {
		for (n = 119; n > 38; n--) {
			/*
			 * This code only runs on 64-bit architectures, the
			 * unsigned long type can thus be used for 64-bit
			 * computation. It will still compile without any
			 * warning on 32-bit architectures.
			 *
			 * To optimize calculations, use fout instead of fvco
			 * to verify the VCO frequency constraint.
			 */
			unsigned long fout = input * (n + 1) / (m + 1);

			if (fout < 1000 || fout > 2048 * 1000 * 1000U)
				continue;

			for (fdpll = 1; fdpll < 32; fdpll++) {
				unsigned long output;

				output = input * (n + 1) / (m + 1)
				       / (fdpll + 1);
				if (output >= 400000000)
				output = fout / (fdpll + 1);
				if (output >= 400 * 1000 * 1000)
					continue;

				diff = abs((long)output - (long)target);
+53 −87
Original line number Diff line number Diff line
@@ -39,100 +39,37 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
	iowrite32(data, lvds->mmio + reg);
}

static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
				       struct rcar_du_crtc *rcrtc)
static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq)
{
	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
	unsigned int freq = mode->clock;
	u32 lvdcr0;
	u32 pllcr;

	/* PLL clock configuration */
	if (freq < 39000)
		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
	else if (freq < 61000)
		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
	else if (freq < 121000)
		pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
	else
		pllcr = LVDPLLCR_PLLDLYCNT_150M;

	rcar_lvds_write(lvds, LVDPLLCR, pllcr);

	/*
	 * Select the input, hardcode mode 0, enable LVDS operation and turn
	 * bias circuitry on.
	 */
	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN;
	if (rcrtc->index == 2)
		lvdcr0 |= LVDCR0_DUSEL;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	/* Turn all the channels on. */
	rcar_lvds_write(lvds, LVDCR1,
			LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) |
			LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) |
			LVDCR1_CLKSTBY_GEN2);

	/*
	 * Turn the PLL on, wait for the startup delay, and turn the output
	 * on.
	 */
	lvdcr0 |= LVDCR0_PLLON;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	usleep_range(100, 150);

	lvdcr0 |= LVDCR0_LVRES;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
		return LVDPLLCR_PLLDLYCNT_150M;
}

static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
				       struct rcar_du_crtc *rcrtc)
static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq)
{
	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
	unsigned int freq = mode->clock;
	u32 lvdcr0;
	u32 pllcr;

	/* PLL clock configuration */
	if (freq < 42000)
		pllcr = LVDPLLCR_PLLDIVCNT_42M;
		return LVDPLLCR_PLLDIVCNT_42M;
	else if (freq < 85000)
		pllcr = LVDPLLCR_PLLDIVCNT_85M;
		return LVDPLLCR_PLLDIVCNT_85M;
	else if (freq < 128000)
		pllcr = LVDPLLCR_PLLDIVCNT_128M;
		return LVDPLLCR_PLLDIVCNT_128M;
	else
		pllcr = LVDPLLCR_PLLDIVCNT_148M;

	rcar_lvds_write(lvds, LVDPLLCR, pllcr);

	/* Turn all the channels on. */
	rcar_lvds_write(lvds, LVDCR1,
			LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
			LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
			LVDCR1_CLKSTBY_GEN3);

	/*
	 * Turn the PLL on, set it to LVDS normal mode, wait for the startup
	 * delay and turn the output on.
	 */
	lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	lvdcr0 |= LVDCR0_PWD;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	usleep_range(100, 150);

	lvdcr0 |= LVDCR0_LVRES;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
		return LVDPLLCR_PLLDIVCNT_148M;
}

static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
				 struct rcar_du_crtc *rcrtc)
{
	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
	u32 lvdpllcr;
	u32 lvdhcr;
	u32 lvdcr0;
	int ret;

	if (lvds->enabled)
@@ -163,11 +100,46 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,

	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);

	/* Perform generation-specific initialization. */
	/* PLL clock configuration. */
	if (lvds->dev->info->gen < 3)
		rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
		lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock);
	else
		rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
		lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock);
	rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);

	/* Set the LVDS mode and select the input. */
	lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT;
	if (rcrtc->index == 2)
		lvdcr0 |= LVDCR0_DUSEL;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	/* Turn all the channels on. */
	rcar_lvds_write(lvds, LVDCR1,
			LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);

	if (lvds->dev->info->gen < 3) {
		/* Enable LVDS operation and turn the bias circuitry on. */
		lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN;
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
	}

	/* Turn the PLL on. */
	lvdcr0 |= LVDCR0_PLLON;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	if (lvds->dev->info->gen > 2) {
		/* Set LVDS normal mode. */
		lvdcr0 |= LVDCR0_PWD;
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
	}

	/* Wait for the startup delay. */
	usleep_range(100, 150);

	/* Turn the output on. */
	lvdcr0 |= LVDCR0_LVRES;
	rcar_lvds_write(lvds, LVDCR0, lvdcr0);

	lvds->enabled = true;

@@ -203,17 +175,11 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
				  struct drm_display_mode *mode)
{
	struct rcar_du_device *rcdu = lvds->dev;

	/*
	 * The internal LVDS encoder has a restricted clock frequency operating
	 * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp
	 * the clock accordingly.
	 * range (31MHz to 148.5MHz). Clamp the clock accordingly.
	 */
	if (rcdu->info->gen < 3)
		mode->clock = clamp(mode->clock, 30000, 150000);
	else
		mode->clock = clamp(mode->clock, 25175, 148500);
	mode->clock = clamp(mode->clock, 31000, 148500);
}

void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
+0 −2
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p)
 * @format: information about the pixel format used by the plane
 * @sg_tables: scatter-gather tables for the frame buffer memory
 * @alpha: value of the plane alpha property
 * @zpos: value of the plane zpos property
 */
struct rcar_du_vsp_plane_state {
	struct drm_plane_state state;
@@ -54,7 +53,6 @@ struct rcar_du_vsp_plane_state {
	struct sg_table sg_tables[3];

	unsigned int alpha;
	unsigned int zpos;
};

static inline struct rcar_du_vsp_plane_state *
+2 −4
Original line number Diff line number Diff line
@@ -26,10 +26,8 @@

#define LVDCR1				0x0004
#define LVDCR1_CKSEL			(1 << 15)		/* Gen2 only */
#define LVDCR1_CHSTBY_GEN2(n)		(3 << (2 + (n) * 2))	/* Gen2 only */
#define LVDCR1_CHSTBY_GEN3(n)		(1 << (2 + (n) * 2))	/* Gen3 only */
#define LVDCR1_CLKSTBY_GEN2		(3 << 0)		/* Gen2 only */
#define LVDCR1_CLKSTBY_GEN3		(1 << 0)		/* Gen3 only */
#define LVDCR1_CHSTBY(n)		(3 << (2 + (n) * 2))
#define LVDCR1_CLKSTBY			(3 << 0)

#define LVDPLLCR			0x0008
#define LVDPLLCR_CEEN			(1 << 14)