Commit c25c0136 authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

drm: rcar-du: lvds: D3/E3 support



The LVDS encoders in the D3 and E3 SoCs differ significantly from those
in the other R-Car Gen3 family members:

- The LVDS PLL architecture is more complex and requires computing PLL
  parameters manually.
- The PLL uses external clocks as inputs, which need to be retrieved
  from DT.
- In addition to the different PLL setup, the startup sequence has
  changed *again* (seems someone had trouble making his/her mind).

Supporting all this requires DT bindings extensions for external clocks,
brand new PLL setup code, and a few quirks to handle the differences in
the startup sequence.

The implementation doesn't support all hardware features yet, namely

- Using the LV[01] clocks generated by the CPG as PLL input.
- Providing the LVDS PLL clock to the DU for use with the RGB output.

Those features can be added later when the need will arise.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: default avatarUlrich Hecht <uli+renesas@fpond.eu>
Reviewed-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
parent 399d9f2f
Loading
Loading
Loading
Loading
+315 −44
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@

#include "rcar_lvds_regs.h"

struct rcar_lvds;

/* Keep in sync with the LVDCR0.LVMD hardware register values. */
enum rcar_lvds_mode {
	RCAR_LVDS_MODE_JEIDA = 0,
@@ -31,14 +33,16 @@ enum rcar_lvds_mode {
	RCAR_LVDS_MODE_VESA = 4,
};

#define RCAR_LVDS_QUIRK_LANES	(1 << 0)	/* LVDS lanes 1 and 3 inverted */
#define RCAR_LVDS_QUIRK_GEN2_PLLCR (1 << 1)	/* LVDPLLCR has gen2 layout */
#define RCAR_LVDS_QUIRK_GEN3_LVEN (1 << 2)	/* LVEN bit needs to be set */
						/* on R8A77970/R8A7799x */
#define RCAR_LVDS_QUIRK_LANES		BIT(0)	/* LVDS lanes 1 and 3 inverted */
#define RCAR_LVDS_QUIRK_GEN3_LVEN	BIT(1)	/* LVEN bit needs to be set on R8A77970/R8A7799x */
#define RCAR_LVDS_QUIRK_PWD		BIT(2)	/* PWD bit available (all of Gen3 but E3) */
#define RCAR_LVDS_QUIRK_EXT_PLL		BIT(3)	/* Has extended PLL */
#define RCAR_LVDS_QUIRK_DUAL_LINK	BIT(4)	/* Supports dual-link operation */

struct rcar_lvds_device_info {
	unsigned int gen;
	unsigned int quirks;
	void (*pll_setup)(struct rcar_lvds *lvds, unsigned int freq);
};

struct rcar_lvds {
@@ -52,7 +56,11 @@ struct rcar_lvds {
	struct drm_panel *panel;

	void __iomem *mmio;
	struct clk *clock;
	struct {
		struct clk *mod;		/* CPG module clock */
		struct clk *extal;		/* External clock */
		struct clk *dotclkin[2];	/* External DU clocks */
	} clocks;
	bool enabled;

	struct drm_display_mode display_mode;
@@ -128,33 +136,216 @@ static const struct drm_connector_funcs rcar_lvds_conn_funcs = {
};

/* -----------------------------------------------------------------------------
 * Bridge
 * PLL Setup
 */

static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq)
static void rcar_lvds_pll_setup_gen2(struct rcar_lvds *lvds, unsigned int freq)
{
	if (freq < 39000)
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
	else if (freq < 61000)
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
	else if (freq < 121000)
		return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
	u32 val;

	if (freq < 39000000)
		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
	else if (freq < 61000000)
		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
	else if (freq < 121000000)
		val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
	else
		return LVDPLLCR_PLLDLYCNT_150M;
		val = LVDPLLCR_PLLDLYCNT_150M;

	rcar_lvds_write(lvds, LVDPLLCR, val);
}

static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq)
static void rcar_lvds_pll_setup_gen3(struct rcar_lvds *lvds, unsigned int freq)
{
	if (freq < 42000)
		return LVDPLLCR_PLLDIVCNT_42M;
	else if (freq < 85000)
		return LVDPLLCR_PLLDIVCNT_85M;
	else if (freq < 128000)
		return LVDPLLCR_PLLDIVCNT_128M;
	u32 val;

	if (freq < 42000000)
		val = LVDPLLCR_PLLDIVCNT_42M;
	else if (freq < 85000000)
		val = LVDPLLCR_PLLDIVCNT_85M;
	else if (freq < 128000000)
		val = LVDPLLCR_PLLDIVCNT_128M;
	else
		val = LVDPLLCR_PLLDIVCNT_148M;

	rcar_lvds_write(lvds, LVDPLLCR, val);
}

struct pll_info {
	unsigned long diff;
	unsigned int pll_m;
	unsigned int pll_n;
	unsigned int pll_e;
	unsigned int div;
	u32 clksel;
};

static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
				     unsigned long target, struct pll_info *pll,
				     u32 clksel)
{
	unsigned long output;
	unsigned long fin;
	unsigned int m_min;
	unsigned int m_max;
	unsigned int m;
	int error;

	if (!clk)
		return;

	/*
	 * The LVDS PLL is made of a pre-divider and a multiplier (strangely
	 * enough called M and N respectively), followed by a post-divider E.
	 *
	 *         ,-----.         ,-----.     ,-----.         ,-----.
	 * Fin --> | 1/M | -Fpdf-> | PFD | --> | VCO | -Fvco-> | 1/E | --> Fout
	 *         `-----'     ,-> |     |     `-----'   |     `-----'
	 *                     |   `-----'               |
	 *                     |         ,-----.         |
	 *                     `-------- | 1/N | <-------'
	 *                               `-----'
	 *
	 * The clock output by the PLL is then further divided by a programmable
	 * divider DIV to achieve the desired target frequency. Finally, an
	 * optional fixed /7 divider is used to convert the bit clock to a pixel
	 * clock (as LVDS transmits 7 bits per lane per clock sample).
	 *
	 *          ,-------.     ,-----.     |\
	 * Fout --> | 1/DIV | --> | 1/7 | --> | |
	 *          `-------'  |  `-----'     | | --> dot clock
	 *                     `------------> | |
	 *                                    |/
	 *
	 * The /7 divider is optional when the LVDS PLL is used to generate a
	 * dot clock for the DU RGB output, without using the LVDS encoder. We
	 * don't support this configuration yet.
	 *
	 * The PLL allowed input frequency range is 12 MHz to 192 MHz.
	 */

	fin = clk_get_rate(clk);
	if (fin < 12000000 || fin > 192000000)
		return;

	/*
	 * The comparison frequency range is 12 MHz to 24 MHz, which limits the
	 * allowed values for the pre-divider M (normal range 1-8).
	 *
	 * Fpfd = Fin / M
	 */
	m_min = max_t(unsigned int, 1, DIV_ROUND_UP(fin, 24000000));
	m_max = min_t(unsigned int, 8, fin / 12000000);

	for (m = m_min; m <= m_max; ++m) {
		unsigned long fpfd;
		unsigned int n_min;
		unsigned int n_max;
		unsigned int n;

		/*
		 * The VCO operating range is 900 Mhz to 1800 MHz, which limits
		 * the allowed values for the multiplier N (normal range
		 * 60-120).
		 *
		 * Fvco = Fin * N / M
		 */
		fpfd = fin / m;
		n_min = max_t(unsigned int, 60, DIV_ROUND_UP(900000000, fpfd));
		n_max = min_t(unsigned int, 120, 1800000000 / fpfd);

		for (n = n_min; n < n_max; ++n) {
			unsigned long fvco;
			unsigned int e_min;
			unsigned int e;

			/*
			 * The output frequency is limited to 1039.5 MHz,
			 * limiting again the allowed values for the
			 * post-divider E (normal value 1, 2 or 4).
			 *
			 * Fout = Fvco / E
			 */
			fvco = fpfd * n;
			e_min = fvco > 1039500000 ? 1 : 0;

			for (e = e_min; e < 3; ++e) {
				unsigned long fout;
				unsigned long diff;
				unsigned int div;

				/*
				 * Finally we have a programable divider after
				 * the PLL, followed by a an optional fixed /7
				 * divider.
				 */
				fout = fvco / (1 << e) / 7;
				div = DIV_ROUND_CLOSEST(fout, target);
				diff = abs(fout / div - target);

				if (diff < pll->diff) {
					pll->diff = diff;
					pll->pll_m = m;
					pll->pll_n = n;
					pll->pll_e = e;
					pll->div = div;
					pll->clksel = clksel;

					if (diff == 0)
						goto done;
				}
			}
		}
	}

done:
	output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
	       / 7 / pll->div;
	error = (long)(output - target) * 10000 / (long)target;

	dev_dbg(lvds->dev,
		"%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/E/DIV %u/%u/%u/%u\n",
		clk, fin, output, target, error / 100,
		error < 0 ? -error % 100 : error % 100,
		pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
}

static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
{
	struct pll_info pll = { .diff = (unsigned long)-1 };
	u32 lvdpllcr;

	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
				 LVDPLLCR_CKSEL_DU_DOTCLKIN(0));
	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
				 LVDPLLCR_CKSEL_DU_DOTCLKIN(1));
	rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
				 LVDPLLCR_CKSEL_EXTAL);

	lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
		 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);

	if (pll.pll_e > 0)
		lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
			 |  LVDPLLCR_PLLE(pll.pll_e - 1);

	rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);

	if (pll.div > 1)
		/*
		 * The DIVRESET bit is a misnomer, setting it to 1 deasserts the
		 * divisor reset.
		 */
		rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL |
				LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1));
	else
		return LVDPLLCR_PLLDIVCNT_148M;
		rcar_lvds_write(lvds, LVDDIV, 0);
}

/* -----------------------------------------------------------------------------
 * Bridge
 */

static void rcar_lvds_enable(struct drm_bridge *bridge)
{
	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
@@ -164,14 +355,13 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
	 * do we get a state pointer?
	 */
	struct drm_crtc *crtc = lvds->bridge.encoder->crtc;
	u32 lvdpllcr;
	u32 lvdhcr;
	u32 lvdcr0;
	int ret;

	WARN_ON(lvds->enabled);

	ret = clk_prepare_enable(lvds->clock);
	ret = clk_prepare_enable(lvds->clocks.mod);
	if (ret < 0)
		return;

@@ -196,12 +386,13 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)

	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);

	if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) {
		/* Disable dual-link mode. */
		rcar_lvds_write(lvds, LVDSTRIPE, 0);
	}

	/* PLL clock configuration. */
	if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN2_PLLCR)
		lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock);
	else
		lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock);
	rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
	lvds->info->pll_setup(lvds, mode->clock * 1000);

	/* Set the LVDS mode and select the input. */
	lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT;
@@ -220,11 +411,16 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
	}

	/* Turn the PLL on. */
	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
		/*
		 * Turn the PLL on (simple PLL only, extended PLL is fully
		 * controlled through LVDPLLCR).
		 */
		lvdcr0 |= LVDCR0_PLLON;
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
	}

	if (lvds->info->gen > 2) {
	if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
		/* Set LVDS normal mode. */
		lvdcr0 |= LVDCR0_PWD;
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
@@ -236,8 +432,10 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
		rcar_lvds_write(lvds, LVDCR0, lvdcr0);
	}

	/* Wait for the startup delay. */
	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
		/* Wait for the PLL startup delay (simple PLL only). */
		usleep_range(100, 150);
	}

	/* Turn the output on. */
	lvdcr0 |= LVDCR0_LVRES;
@@ -264,8 +462,9 @@ static void rcar_lvds_disable(struct drm_bridge *bridge)

	rcar_lvds_write(lvds, LVDCR0, 0);
	rcar_lvds_write(lvds, LVDCR1, 0);
	rcar_lvds_write(lvds, LVDPLLCR, 0);

	clk_disable_unprepare(lvds->clock);
	clk_disable_unprepare(lvds->clocks.mod);

	lvds->enabled = false;
}
@@ -446,6 +645,60 @@ done:
	return ret;
}

static struct clk *rcar_lvds_get_clock(struct rcar_lvds *lvds, const char *name,
				       bool optional)
{
	struct clk *clk;

	clk = devm_clk_get(lvds->dev, name);
	if (!IS_ERR(clk))
		return clk;

	if (PTR_ERR(clk) == -ENOENT && optional)
		return NULL;

	if (PTR_ERR(clk) != -EPROBE_DEFER)
		dev_err(lvds->dev, "failed to get %s clock\n",
			name ? name : "module");

	return clk;
}

static int rcar_lvds_get_clocks(struct rcar_lvds *lvds)
{
	lvds->clocks.mod = rcar_lvds_get_clock(lvds, NULL, false);
	if (IS_ERR(lvds->clocks.mod))
		return PTR_ERR(lvds->clocks.mod);

	/*
	 * LVDS encoders without an extended PLL have no external clock inputs.
	 */
	if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))
		return 0;

	lvds->clocks.extal = rcar_lvds_get_clock(lvds, "extal", true);
	if (IS_ERR(lvds->clocks.extal))
		return PTR_ERR(lvds->clocks.extal);

	lvds->clocks.dotclkin[0] = rcar_lvds_get_clock(lvds, "dclkin.0", true);
	if (IS_ERR(lvds->clocks.dotclkin[0]))
		return PTR_ERR(lvds->clocks.dotclkin[0]);

	lvds->clocks.dotclkin[1] = rcar_lvds_get_clock(lvds, "dclkin.1", true);
	if (IS_ERR(lvds->clocks.dotclkin[1]))
		return PTR_ERR(lvds->clocks.dotclkin[1]);

	/* At least one input to the PLL must be available. */
	if (!lvds->clocks.extal && !lvds->clocks.dotclkin[0] &&
	    !lvds->clocks.dotclkin[1]) {
		dev_err(lvds->dev,
			"no input clock (extal, dclkin.0 or dclkin.1)\n");
		return -EINVAL;
	}

	return 0;
}

static int rcar_lvds_probe(struct platform_device *pdev)
{
	struct rcar_lvds *lvds;
@@ -475,11 +728,9 @@ static int rcar_lvds_probe(struct platform_device *pdev)
	if (IS_ERR(lvds->mmio))
		return PTR_ERR(lvds->mmio);

	lvds->clock = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(lvds->clock)) {
		dev_err(&pdev->dev, "failed to get clock\n");
		return PTR_ERR(lvds->clock);
	}
	ret = rcar_lvds_get_clocks(lvds);
	if (ret < 0)
		return ret;

	drm_bridge_add(&lvds->bridge);

@@ -497,21 +748,39 @@ static int rcar_lvds_remove(struct platform_device *pdev)

static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
	.gen = 2,
	.quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR,
	.pll_setup = rcar_lvds_pll_setup_gen2,
};

static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = {
	.gen = 2,
	.quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_LANES,
	.quirks = RCAR_LVDS_QUIRK_LANES,
	.pll_setup = rcar_lvds_pll_setup_gen2,
};

static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
	.gen = 3,
	.quirks = RCAR_LVDS_QUIRK_PWD,
	.pll_setup = rcar_lvds_pll_setup_gen3,
};

static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = {
	.gen = 3,
	.quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_GEN3_LVEN,
	.quirks = RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_GEN3_LVEN,
	.pll_setup = rcar_lvds_pll_setup_gen2,
};

static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = {
	.gen = 3,
	.quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL
		| RCAR_LVDS_QUIRK_DUAL_LINK,
	.pll_setup = rcar_lvds_pll_setup_d3_e3,
};

static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = {
	.gen = 3,
	.quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD
		| RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK,
	.pll_setup = rcar_lvds_pll_setup_d3_e3,
};

static const struct of_device_id rcar_lvds_of_table[] = {
@@ -523,6 +792,8 @@ static const struct of_device_id rcar_lvds_of_table[] = {
	{ .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
	{ .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
	{ .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info },
	{ .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info },
	{ .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_r8a77995_info },
	{ }
};

+40 −3
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#define LVDCR0_PLLON			(1 << 4)
#define LVDCR0_PWD			(1 << 2)		/* Gen3 only */
#define LVDCR0_BEN			(1 << 2)		/* Gen2 only */
#define LVDCR0_LVEN			(1 << 1)		/* Gen2 only */
#define LVDCR0_LVEN			(1 << 1)
#define LVDCR0_LVRES			(1 << 0)

#define LVDCR1				0x0004
@@ -27,21 +27,36 @@
#define LVDCR1_CLKSTBY			(3 << 0)

#define LVDPLLCR			0x0008
/* Gen2 & V3M */
#define LVDPLLCR_CEEN			(1 << 14)
#define LVDPLLCR_FBEN			(1 << 13)
#define LVDPLLCR_COSEL			(1 << 12)
/* Gen2 */
#define LVDPLLCR_PLLDLYCNT_150M		(0x1bf << 0)
#define LVDPLLCR_PLLDLYCNT_121M		(0x22c << 0)
#define LVDPLLCR_PLLDLYCNT_60M		(0x77b << 0)
#define LVDPLLCR_PLLDLYCNT_38M		(0x69a << 0)
#define LVDPLLCR_PLLDLYCNT_MASK		(0x7ff << 0)
/* Gen3 */
/* Gen3 but V3M,D3 and E3 */
#define LVDPLLCR_PLLDIVCNT_42M		(0x014cb << 0)
#define LVDPLLCR_PLLDIVCNT_85M		(0x00a45 << 0)
#define LVDPLLCR_PLLDIVCNT_128M		(0x006c3 << 0)
#define LVDPLLCR_PLLDIVCNT_148M		(0x046c1 << 0)
#define LVDPLLCR_PLLDIVCNT_MASK		(0x7ffff << 0)
/* D3 and E3 */
#define LVDPLLCR_PLLON			(1 << 22)
#define LVDPLLCR_PLLSEL_PLL0		(0 << 20)
#define LVDPLLCR_PLLSEL_LVX		(1 << 20)
#define LVDPLLCR_PLLSEL_PLL1		(2 << 20)
#define LVDPLLCR_CKSEL_LVX		(1 << 17)
#define LVDPLLCR_CKSEL_EXTAL		(3 << 17)
#define LVDPLLCR_CKSEL_DU_DOTCLKIN(n)	((5 + (n) * 2) << 17)
#define LVDPLLCR_OCKSEL			(1 << 16)
#define LVDPLLCR_STP_CLKOUTE		(1 << 14)
#define LVDPLLCR_OUTCLKSEL		(1 << 12)
#define LVDPLLCR_CLKOUT			(1 << 11)
#define LVDPLLCR_PLLE(n)		((n) << 10)
#define LVDPLLCR_PLLN(n)		((n) << 3)
#define LVDPLLCR_PLLM(n)		((n) << 0)

#define LVDCTRCR			0x000c
#define LVDCTRCR_CTR3SEL_ZERO		(0 << 12)
@@ -71,4 +86,26 @@
#define LVDCHCR_CHSEL_CH(n, c)		((((c) - (n)) & 3) << ((n) * 4))
#define LVDCHCR_CHSEL_MASK(n)		(3 << ((n) * 4))

/* All registers below are specific to D3 and E3 */
#define LVDSTRIPE			0x0014
#define LVDSTRIPE_ST_TRGSEL_DISP	(0 << 2)
#define LVDSTRIPE_ST_TRGSEL_HSYNC_R	(1 << 2)
#define LVDSTRIPE_ST_TRGSEL_HSYNC_F	(2 << 2)
#define LVDSTRIPE_ST_SWAP		(1 << 1)
#define LVDSTRIPE_ST_ON			(1 << 0)

#define LVDSCR				0x0018
#define LVDSCR_DEPTH(n)			(((n) - 1) << 29)
#define LVDSCR_BANDSET			(1 << 28)
#define LVDSCR_TWGCNT(n)		((((n) - 256) / 16) << 24)
#define LVDSCR_SDIV(n)			((n) << 22)
#define LVDSCR_MODE			(1 << 21)
#define LVDSCR_RSTN			(1 << 20)

#define LVDDIV				0x001c
#define LVDDIV_DIVSEL			(1 << 8)
#define LVDDIV_DIVRESET			(1 << 7)
#define LVDDIV_DIVSTP			(1 << 6)
#define LVDDIV_DIV(n)			((n) << 0)

#endif /* __RCAR_LVDS_REGS_H__ */