Instead of adjusting PLL0 to scale the CPU frequency, use the divider
authorkettenis <kettenis@openbsd.org>
Tue, 19 Sep 2023 19:15:08 +0000 (19:15 +0000)
committerkettenis <kettenis@openbsd.org>
Tue, 19 Sep 2023 19:15:08 +0000 (19:15 +0000)
of the actual CPU clock.  This prevents one of the GMAC0 clocks changing
when we change the CPU frequency, which would break one of the Ethernet
ports on the VisionFive 2 v1.2a.

However, since the firmware configures PLL0 to 1 GHz, we still need to
bump it up to 1.5 GHz in order to reach the highest supported CPU clock
rates.

ok jmatthew@, jca@, jsing@

sys/arch/riscv64/dev/stfclock.c

index 2871bbf..8684cbd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: stfclock.c,v 1.10 2023/08/30 19:07:23 kettenis Exp $  */
+/*     $OpenBSD: stfclock.c,v 1.11 2023/09/19 19:15:08 kettenis Exp $  */
 /*
  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
  * Copyright (c) 2023 Joel Sing <jsing@openbsd.org>
@@ -966,15 +966,31 @@ stfclock_set_frequency_jh7110_sys(void *cookie, uint32_t *cells, uint32_t freq)
        uint32_t reg, div, mux;
 
        switch (idx) {
-       case JH7110_SYSCLK_CPU_ROOT:
-               return clock_set_frequency(sc->sc_node, "pll0_out", freq);
-       case JH7110_SYSCLK_CPU_CORE:
-               parent = JH7110_SYSCLK_CPU_ROOT;
-               return stfclock_set_frequency_jh7110_sys(sc, &parent, freq);
        case JH7110_SYSCLK_GMAC1_RMII_REFIN:
                return clock_set_frequency(sc->sc_node, "gmac1_rmii_refin", freq);
        }
 
+       /*
+        * Firmware on the VisionFive 2 initializes PLL0 to 1 GHz and
+        * runs the CPU cores at this frequency.  But there is no
+        * operating point in the device tree with this frequency and
+        * it means we can't run at the supported maximum frequency of
+        * 1.5 GHz.
+        *
+        * So if we're switching away from the 1 GHz boot frequency,
+        * bump the PLL0 frequency up to 1.5 GHz.  But set the divider
+        * for the CPU clock to 2 to make sure we don't run at a
+        * frequency that is too high for the default CPU voltage.
+        */
+       if (idx == JH7110_SYSCLK_CPU_CORE && freq != 1000000000 &&
+           stfclock_get_frequency_jh7110_sys(sc, &idx) == 1000000000) {
+               reg = HREAD4(sc, idx * 4);
+               reg &= ~CLKDIV_MASK;
+               reg |= (2 << CLKDIV_SHIFT);
+               HWRITE4(sc, idx * 4, reg);
+               clock_set_frequency(sc->sc_node, "pll0_out", 1500000000);
+       }
+
        reg = HREAD4(sc, idx * 4);
        mux = (reg & CLKMUX_MASK) >> CLKMUX_SHIFT;
 
@@ -989,6 +1005,9 @@ stfclock_set_frequency_jh7110_sys(void *cookie, uint32_t *cells, uint32_t freq)
        }
 
        switch (idx) {
+       case JH7110_SYSCLK_CPU_CORE:
+               parent = JH7110_SYSCLK_CPU_ROOT;
+               break;
        case JH7110_SYSCLK_GMAC1_GTXCLK:
                parent = JH7110_SYSCLK_PLL0_OUT;
                break;