Author: mmel
Date: Tue Apr  5 09:20:52 2016
New Revision: 297576
URL: https://svnweb.freebsd.org/changeset/base/297576

Log:
  TEGRA: Fix CPU frequency switching.
  The PLL_X, base CPU frequency source, doesn't have a bypass switch and thus
  we must use another frequency source for CPU while changing its frequency.
  PLL_P is ideal for this, it runs at 480MHz and CPU can be clocked at this
  frequency at any CPU voltage.

Modified:
  head/sys/arm/nvidia/tegra124/tegra124_clk_pll.c
  head/sys/arm/nvidia/tegra124/tegra124_clk_super.c
  head/sys/arm/nvidia/tegra124/tegra124_cpufreq.c

Modified: head/sys/arm/nvidia/tegra124/tegra124_clk_pll.c
==============================================================================
--- head/sys/arm/nvidia/tegra124/tegra124_clk_pll.c     Tue Apr  5 08:37:21 
2016        (r297575)
+++ head/sys/arm/nvidia/tegra124/tegra124_clk_pll.c     Tue Apr  5 09:20:52 
2016        (r297576)
@@ -823,12 +823,10 @@ pllx_set_freq(struct pll_sc *sc, uint64_
                return (0);
        }
 
-       /* Set bypass. */
+       /* PLLX doesn't have bypass, disable it first. */
        RD4(sc, sc->base_reg, &reg);
-       reg |= PLL_BASE_BYPASS;
+       reg &= ~PLL_BASE_ENABLE;
        WR4(sc, sc->base_reg, reg);
-       RD4(sc, sc->base_reg, &reg);
-       DELAY(100);
 
        /* Set PLL. */
        RD4(sc, sc->base_reg, &reg);
@@ -840,16 +838,16 @@ pllx_set_freq(struct pll_sc *sc, uint64_
        RD4(sc, sc->base_reg, &reg);
        DELAY(100);
 
+       /* Enable lock detection. */
+       RD4(sc, sc->misc_reg, &reg);
+       reg |= sc->lock_enable;
+       WR4(sc, sc->misc_reg, reg);
+
        /* Enable PLL. */
        RD4(sc, sc->base_reg, &reg);
        reg |= PLL_BASE_ENABLE;
        WR4(sc, sc->base_reg, reg);
 
-       /* Enable lock detection */
-       RD4(sc, sc->misc_reg, &reg);
-       reg |= sc->lock_enable;
-       WR4(sc, sc->misc_reg, reg);
-
        rv = wait_for_lock(sc);
        if (rv != 0) {
                /* Disable PLL */
@@ -860,10 +858,6 @@ pllx_set_freq(struct pll_sc *sc, uint64_
        }
        RD4(sc, sc->misc_reg, &reg);
 
-       /* Clear bypass. */
-       RD4(sc, sc->base_reg, &reg);
-       reg &= ~PLL_BASE_BYPASS;
-       WR4(sc, sc->base_reg, reg);
        *fout = ((fin / m) * n) / p;
        return (0);
 }

Modified: head/sys/arm/nvidia/tegra124/tegra124_clk_super.c
==============================================================================
--- head/sys/arm/nvidia/tegra124/tegra124_clk_super.c   Tue Apr  5 08:37:21 
2016        (r297575)
+++ head/sys/arm/nvidia/tegra124/tegra124_clk_super.c   Tue Apr  5 09:20:52 
2016        (r297576)
@@ -205,8 +205,7 @@ super_mux_set_mux(struct clknode *clk, i
            (state != SUPER_MUX_STATE_IDLE)) {
                panic("Unexpected super mux state: %u", state);
        }
-
-       shift = state * SUPER_MUX_MUX_WIDTH;
+       shift = (state - 1) * SUPER_MUX_MUX_WIDTH;
        sc->mux = idx;
        if (sc->flags & SMF_HAVE_DIVIDER_2) {
                if (idx == sc->src_div2) {
@@ -222,6 +221,7 @@ super_mux_set_mux(struct clknode *clk, i
        }
        reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
        reg |= idx << shift;
+
        WR4(sc, sc->base_reg, reg);
        RD4(sc, sc->base_reg, &dummy);
        DEVICE_UNLOCK(sc);

Modified: head/sys/arm/nvidia/tegra124/tegra124_cpufreq.c
==============================================================================
--- head/sys/arm/nvidia/tegra124/tegra124_cpufreq.c     Tue Apr  5 08:37:21 
2016        (r297575)
+++ head/sys/arm/nvidia/tegra124/tegra124_cpufreq.c     Tue Apr  5 09:20:52 
2016        (r297576)
@@ -335,12 +335,27 @@ set_cpu_freq(struct tegra124_cpufreq_sof
                if (rv != 0)
                        return (rv);
        }
-       rv = clk_set_freq(sc->clk_cpu_g, point->freq, CLK_SET_ROUND_DOWN);
+
+       /* Switch supermux to PLLP first */
+       rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p);
+       if (rv != 0) {
+               device_printf(sc->dev, "Can't set parent to PLLP\n");
+               return (rv);
+       }
+
+       /* Set PLLX frequency */
+       rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN);
        if (rv != 0) {
                device_printf(sc->dev, "Can't set CPU clock frequency\n");
                return (rv);
        }
 
+       rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x);
+       if (rv != 0) {
+               device_printf(sc->dev, "Can't set parent to PLLX\n");
+               return (rv);
+       }
+
        if (sc->act_speed_point->uvolt > point->uvolt) {
                /* set cpu voltage */
                rv = regulator_set_voltage(sc->supply_vdd_cpu,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to