On 30.05.2016 18:00, Ulrich Hecht wrote: > From: Koji Matsuoka <koji.matsuoka.xm at renesas.com> > > Signed-off-by: Koji Matsuoka <koji.matsuoka.xm at renesas.com> > Signed-off-by: Geert Uytterhoeven <geert+renesas at glider.be> > --- > drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 97 > ++++++++++++++++++++++++++++++++- > drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 +++ > drivers/gpu/drm/rcar-du/rcar_du_drv.c | 1 + > drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + > drivers/gpu/drm/rcar-du/rcar_du_plane.h | 7 ++- > drivers/gpu/drm/rcar-du/rcar_du_regs.h | 19 +++++++ > 6 files changed, 131 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c > b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c > index 0d8bdda..e10943b 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c > +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c > @@ -30,6 +30,12 @@ > #include "rcar_du_regs.h" > #include "rcar_du_vsp.h" > > +#define PRODUCT_REG 0xfff00044 > +#define PRODUCT_H3_BIT (0x4f << 8) > +#define PRODUCT_MASK (0x7f << 8) > +#define CUT_ES1 (0x00) > +#define CUT_ES1_MASK (0x000000ff)
NACK for the hard coded register. We've already discussed this in the thread https://www.mail-archive.com/linux-renesas-soc at vger.kernel.org/msg04008.html and found that this isn't ready this way: https://www.mail-archive.com/linux-renesas-soc at vger.kernel.org/msg04079.html Best regards Dirk > static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) > { > struct rcar_du_device *rcdu = rcrtc->group->dev; > @@ -106,14 +112,74 @@ static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc) > * Hardware Setup > */ > > +static void rcar_du_dpll_divider(struct dpll_info *dpll, unsigned int extclk, > + unsigned int mode_clock) > +{ > + unsigned long dpllclk; > + unsigned long diff; > + unsigned long n, m, fdpll; > + bool match_flag = false; > + bool clk_diff_set = true; > + > + for (n = 39; n < 120; n++) { > + for (m = 0; m < 4; m++) { > + for (fdpll = 1; fdpll < 32; fdpll++) { > + /* 1/2 (FRQSEL=1) for duty rate 50% */ > + dpllclk = extclk * (n + 1) / (m + 1) > + / (fdpll + 1) / 2; > + if (dpllclk >= 400000000) > + continue; > + > + diff = abs((long)dpllclk - (long)mode_clock); > + if (clk_diff_set || > + ((diff == 0) || (dpll->diff > diff))) { > + dpll->diff = diff; > + dpll->n = n; > + dpll->m = m; > + dpll->fdpll = fdpll; > + dpll->dpllclk = dpllclk; > + > + if (clk_diff_set) > + clk_diff_set = false; > + > + if (diff == 0) { > + match_flag = true; > + break; > + } > + } > + } > + if (match_flag) > + break; > + } > + if (match_flag) > + break; > + } > +} > + > static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) > { > const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; > + struct rcar_du_device *rcdu = rcrtc->group->dev; > unsigned long mode_clock = mode->clock * 1000; > unsigned long clk; > u32 value; > u32 escr; > u32 div; > + u32 dpll_reg = 0; > + struct dpll_info *dpll; > + void __iomem *product_reg; > + bool h3_es1_workaround = false; > + > + dpll = kzalloc(sizeof(*dpll), GFP_KERNEL); > + if (dpll == NULL) > + return; > + > + /* DU2 DPLL Clock Select bit workaround in R-Car H3(ES1.0) */ > + product_reg = ioremap(PRODUCT_REG, 0x04); > + if (((readl(product_reg) & PRODUCT_MASK) == PRODUCT_H3_BIT) > + && ((readl(product_reg) & CUT_ES1_MASK) == CUT_ES1)) > + h3_es1_workaround = true; > + iounmap(product_reg); > > /* Compute the clock divisor and select the internal or external dot > * clock based on the requested frequency. > @@ -130,6 +196,15 @@ static void rcar_du_crtc_set_display_timing(struct > rcar_du_crtc *rcrtc) > u32 extdiv; > > extclk = clk_get_rate(rcrtc->extclock); > + > + if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) { > + rcar_du_dpll_divider(dpll, extclk, mode_clock); > + extclk = dpll->dpllclk; > + dev_dbg(rcrtc->group->dev->dev, > + "dpllclk:%d, fdpll:%d, n:%d, m:%d, diff:%d\n", > + dpll->dpllclk, dpll->fdpll, dpll->n, dpll->m, > + dpll->diff); > + } > extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); > extdiv = clamp(extdiv, 1U, 64U) - 1; > > @@ -140,7 +215,27 @@ static void rcar_du_crtc_set_display_timing(struct > rcar_du_crtc *rcrtc) > abs((long)rate - (long)mode_clock)) { > dev_dbg(rcrtc->group->dev->dev, > "crtc%u: using external clock\n", rcrtc->index); > - escr = extdiv | ESCR_DCLKSEL_DCLKIN; > + if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) { > + escr = ESCR_DCLKSEL_DCLKIN | 0x01; > + dpll_reg = DPLLCR_CODE | DPLLCR_M(dpll->m) | > + DPLLCR_FDPLL(dpll->fdpll) | > + DPLLCR_CLKE | DPLLCR_N(dpll->n) | > + DPLLCR_STBY; > + > + if (rcrtc->index == DU_CH_1) > + dpll_reg |= (DPLLCR_PLCS1 | > + DPLLCR_INCS_DPLL01_DOTCLKIN13); > + if (rcrtc->index == DU_CH_2) { > + dpll_reg |= (DPLLCR_PLCS0 | > + DPLLCR_INCS_DPLL01_DOTCLKIN02); > + if (h3_es1_workaround) > + dpll_reg |= (0x01 << 21); > + } > + > + rcar_du_group_write(rcrtc->group, DPLLCR, > + dpll_reg); > + } else > + escr = extdiv | ESCR_DCLKSEL_DCLKIN; > } > } > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h > b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h > index 459e539..9a56cc7 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h > +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h > @@ -54,6 +54,14 @@ struct rcar_du_crtc { > struct rcar_du_vsp *vsp; > }; > > +struct dpll_info { > + unsigned int dpllclk; > + unsigned int diff; > + unsigned int fdpll; > + unsigned int n; > + unsigned int m; > +}; > + > #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) > > enum rcar_du_output { > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c > b/drivers/gpu/drm/rcar-du/rcar_du_drv.c > index 0a93d2a..5ed0d61 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c > @@ -165,6 +165,7 @@ static const struct rcar_du_device_info > rcar_du_r8a7795_info = { > }, > }, > .num_lvds = 1, > + .dpll_ch = BIT(1) | BIT(2), > }; > > static const struct of_device_id rcar_du_of_table[] = { > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h > b/drivers/gpu/drm/rcar-du/rcar_du_drv.h > index d1d1d8d..790829b 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h > @@ -69,6 +69,7 @@ struct rcar_du_device_info { > unsigned int num_crtcs; > struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; > unsigned int num_lvds; > + unsigned int dpll_ch; > }; > > #define RCAR_DU_MAX_CRTCS 4 > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h > b/drivers/gpu/drm/rcar-du/rcar_du_plane.h > index b18b7b2..47fad23 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h > +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h > @@ -1,7 +1,7 @@ > /* > * rcar_du_plane.h -- R-Car Display Unit Planes > * > - * Copyright (C) 2013-2014 Renesas Electronics Corporation > + * Copyright (C) 2013-2015 Renesas Electronics Corporation > * > * Contact: Laurent Pinchart (laurent.pinchart at ideasonboard.com) > * > @@ -34,6 +34,11 @@ enum rcar_du_plane_source { > RCAR_DU_PLANE_VSPD1, > }; > > +#define DU_CH_0 0 > +#define DU_CH_1 1 > +#define DU_CH_2 2 > +#define DU_CH_3 3 > + > struct rcar_du_plane { > struct drm_plane plane; > struct rcar_du_group *group; > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h > b/drivers/gpu/drm/rcar-du/rcar_du_regs.h > index fedb016..7a34bf3 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h > +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h > @@ -277,6 +277,25 @@ > #define DEFR10_TSEL_H3_TCON1 (0 << 1) /* DEFR102 register only > (DU2/DU3) */ > #define DEFR10_DEFE10 (1 << 0) > > +#define DPLLCR 0x20044 > +#define DPLLCR_CODE (0x95 << 24) > +#define DPLLCR_PLCS1 (1 << 23) > +#define DPLLCR_PLCS0 (1 << 20) > +#define DPLLCR_CLKE (1 << 18) > +#define DPLLCR_FDPLL(n) ((n) << 12) /* n=0 Setting > prohibited */ > +/* H'00 to H'26, H'78 to H'7F: Setting prohibited.*/ > +#define DPLLCR_N(n) ((n) << 5) > +#define DPLLCR_M(n) ((n) << 3) > +#define DPLLCR_STBY (1 << 2) > +#define DPLLCR_INCS_DPLL01_DOTCLKIN02 (0 << 0) > +#define DPLLCR_INCS_DPLL01_DOTCLKIN13 (1 << 1) > + > +#define DPLLC2R 0x20048 > +#define DPLLC2R_CODE (0x95 << 24) > +#define DPLLC2R_SELC (1 << 12) > +#define DPLLC2R_M(n) ((n) << 8) > +#define DPLLC2R_FDPLL(n) ((n) << 0) /* n=0 Setting prohibited */ > + > /* > ----------------------------------------------------------------------------- > * Display Timing Generation Registers > */ >