Hi Laurent, On Fri, Sep 14, 2018 at 12:10:35PM +0300, Laurent Pinchart wrote: > 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: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> > Tested-by: Jacopo Mondi <jacopo+renesas@xxxxxxxxxx> please add my Reviewed-by: Jacopo Mondi <jacopo+renesas@xxxxxxxxxx> > --- > Changes since v1: > > - Don't compile-out debug code based on DEBUG and CONFIG_DYNAMIC_DEBUG > - Test all three input clocks (DOTCLKIN[01] and EXTAL) and pick the best > one > --- > drivers/gpu/drm/rcar-du/rcar_lvds.c | 355 +++++++++++++++++++++++++++---- > drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 43 +++- > 2 files changed, 351 insertions(+), 47 deletions(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c > index ce0eb68c3416..23e7743144c8 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c > @@ -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,212 @@ 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 > - return LVDPLLCR_PLLDIVCNT_148M; > + 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 (strangerly > + * 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) > + rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL | > + LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1)); > + else > + 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 +351,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 +382,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 +407,16 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) > rcar_lvds_write(lvds, LVDCR0, lvdcr0); > } > > - /* Turn the PLL on. */ > - lvdcr0 |= LVDCR0_PLLON; > - rcar_lvds_write(lvds, LVDCR0, lvdcr0); > + 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 +428,10 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) > rcar_lvds_write(lvds, LVDCR0, lvdcr0); > } > > - /* Wait for the startup delay. */ > - usleep_range(100, 150); > + 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 +458,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 +641,60 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds) > 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 +724,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 +744,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 +788,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 }, > { } > }; > > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h > index 4870f50d9bec..87149f2f8056 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h > @@ -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__ */ > -- > Regards, > > Laurent Pinchart >
Attachment:
signature.asc
Description: PGP signature