[RFC 08/21] drm: rcar-du: Add DPLL support

2016-05-30 Thread Dirk Behme
On 30.05.2016 18:00, Ulrich Hecht wrote:
> From: Koji Matsuoka 
>
> Signed-off-by: Koji Matsuoka 
> Signed-off-by: Geert Uytterhoeven 
> ---
>   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 (0x00ff)


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 >= 4)
> + 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 = >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,
> +  

[RFC 08/21] drm: rcar-du: Add DPLL support

2016-05-30 Thread Ulrich Hecht
From: Koji Matsuoka 

Signed-off-by: Koji Matsuoka 
Signed-off-by: Geert Uytterhoeven 
---
 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_REG0xfff00044
+#define PRODUCT_H3_BIT (0x4f << 8)
+#define PRODUCT_MASK   (0x7f << 8)
+#define CUT_ES1(0x00)
+#define CUT_ES1_MASK   (0x00ff)
+
 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 >= 4)
+   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 = >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)