|
@@ -106,9 +106,62 @@ static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
|
|
* Hardware Setup
|
|
* Hardware Setup
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+struct dpll_info {
|
|
|
|
+ unsigned int output;
|
|
|
|
+ unsigned int fdpll;
|
|
|
|
+ unsigned int n;
|
|
|
|
+ unsigned int m;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc,
|
|
|
|
+ struct dpll_info *dpll,
|
|
|
|
+ unsigned long input,
|
|
|
|
+ unsigned long target)
|
|
|
|
+{
|
|
|
|
+ unsigned long best_diff = (unsigned long)-1;
|
|
|
|
+ unsigned long diff;
|
|
|
|
+ unsigned int fdpll;
|
|
|
|
+ unsigned int m;
|
|
|
|
+ unsigned int n;
|
|
|
|
+
|
|
|
|
+ for (n = 39; n < 120; n++) {
|
|
|
|
+ for (m = 0; m < 4; m++) {
|
|
|
|
+ for (fdpll = 1; fdpll < 32; fdpll++) {
|
|
|
|
+ unsigned long output;
|
|
|
|
+
|
|
|
|
+ /* 1/2 (FRQSEL=1) for duty rate 50% */
|
|
|
|
+ output = input * (n + 1) / (m + 1)
|
|
|
|
+ / (fdpll + 1) / 2;
|
|
|
|
+
|
|
|
|
+ if (output >= 400000000)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ diff = abs((long)output - (long)target);
|
|
|
|
+ if (best_diff > diff) {
|
|
|
|
+ best_diff = diff;
|
|
|
|
+ dpll->n = n;
|
|
|
|
+ dpll->m = m;
|
|
|
|
+ dpll->fdpll = fdpll;
|
|
|
|
+ dpll->output = output;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (diff == 0)
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ dev_dbg(rcrtc->group->dev->dev,
|
|
|
|
+ "output:%u, fdpll:%u, n:%u, m:%u, diff:%lu\n",
|
|
|
|
+ dpll->output, dpll->fdpll, dpll->n, dpll->m,
|
|
|
|
+ best_diff);
|
|
|
|
+}
|
|
|
|
+
|
|
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
|
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
|
{
|
|
{
|
|
const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
|
|
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 mode_clock = mode->clock * 1000;
|
|
unsigned long clk;
|
|
unsigned long clk;
|
|
u32 value;
|
|
u32 value;
|
|
@@ -124,12 +177,18 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
|
escr = div | ESCR_DCLKSEL_CLKS;
|
|
escr = div | ESCR_DCLKSEL_CLKS;
|
|
|
|
|
|
if (rcrtc->extclock) {
|
|
if (rcrtc->extclock) {
|
|
|
|
+ struct dpll_info dpll = { 0 };
|
|
unsigned long extclk;
|
|
unsigned long extclk;
|
|
unsigned long extrate;
|
|
unsigned long extrate;
|
|
unsigned long rate;
|
|
unsigned long rate;
|
|
u32 extdiv;
|
|
u32 extdiv;
|
|
|
|
|
|
extclk = clk_get_rate(rcrtc->extclock);
|
|
extclk = clk_get_rate(rcrtc->extclock);
|
|
|
|
+ if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
|
|
|
|
+ rcar_du_dpll_divider(rcrtc, &dpll, extclk, mode_clock);
|
|
|
|
+ extclk = dpll.output;
|
|
|
|
+ }
|
|
|
|
+
|
|
extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
|
|
extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
|
|
extdiv = clamp(extdiv, 1U, 64U) - 1;
|
|
extdiv = clamp(extdiv, 1U, 64U) - 1;
|
|
|
|
|
|
@@ -140,7 +199,27 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
|
|
abs((long)rate - (long)mode_clock)) {
|
|
abs((long)rate - (long)mode_clock)) {
|
|
dev_dbg(rcrtc->group->dev->dev,
|
|
dev_dbg(rcrtc->group->dev->dev,
|
|
"crtc%u: using external clock\n", rcrtc->index);
|
|
"crtc%u: using external clock\n", rcrtc->index);
|
|
- escr = extdiv | ESCR_DCLKSEL_DCLKIN;
|
|
|
|
|
|
+
|
|
|
|
+ if (rcdu->info->dpll_ch & (1 << rcrtc->index)) {
|
|
|
|
+ u32 dpllcr = DPLLCR_CODE | DPLLCR_CLKE
|
|
|
|
+ | DPLLCR_FDPLL(dpll.fdpll)
|
|
|
|
+ | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
|
|
|
|
+ | DPLLCR_STBY;
|
|
|
|
+
|
|
|
|
+ if (rcrtc->index == 1)
|
|
|
|
+ dpllcr |= DPLLCR_PLCS1
|
|
|
|
+ | DPLLCR_INCS_DOTCLKIN1;
|
|
|
|
+ else
|
|
|
|
+ dpllcr |= DPLLCR_PLCS0
|
|
|
|
+ | DPLLCR_INCS_DOTCLKIN0;
|
|
|
|
+
|
|
|
|
+ rcar_du_group_write(rcrtc->group, DPLLCR,
|
|
|
|
+ dpllcr);
|
|
|
|
+
|
|
|
|
+ escr = ESCR_DCLKSEL_DCLKIN | 1;
|
|
|
|
+ } else {
|
|
|
|
+ escr = ESCR_DCLKSEL_DCLKIN | extdiv;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|