Download raw body.
riscv: implement clock for Allwinner D1 ( MangoPI MQ Pro )
On Sat, 18 Jul 2026 12:23:11 +0200
Nazarenko Mykyta <mykyta@nazarenko.sbs> wrote:
> Hola, tech!
>
> I noticed that the clock for the Allwinner D1 hasn't been implemented
> at all; it would be a good idea to implement it and remove the
> current stub. In addition, I'm trying to get DVFS to work on this SBC.
>
> I'm not sure if this is written really well, but seems like it's
> working.
>
> Tested on MangoPI MQ Pro ( rev 1.4 ).
> + reg &= ~(D1_PLL_CPU_FACTOR_N_MASK) |
> (D1_PLL_CPU_FACTOR_M_MASK);
> + reg |= ((n - 1) << 8) | ((m - 1) << 0);
> + reg |= D1_PLL_CPU_ENABLE) | D1_PLL_CPU_LDO_EN;
Sorry, when I was adding masks and refactoring the previous code, I
messed up the parentheses a little bit. My apologies for the noise.
Fixed.
Index: sxiccmu.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu.c,v
diff -u -p -u -r1.38 sxiccmu.c
--- sxiccmu.c 7 Mar 2024 01:04:16 -0000 1.38
+++ sxiccmu.c 18 Jul 2026 10:14:51 -0000
@@ -1260,11 +1260,19 @@ sxiccmu_a80_get_frequency(struct sxiccmu
#define D1_PLL_CPU_CTRL_REG 0x0000
#define D1_PLL_CPU_FACTOR_M(x) (((x) >> 0) & 0x3)
#define D1_PLL_CPU_FACTOR_N(x) (((x) >> 8) & 0xff)
+#define D1_PLL_CPU_ENABLE (1U << 31)
+#define D1_PLL_CPU_LDO_EN (1U << 30)
+#define D1_PLL_CPU_LOCK_EN (1U << 29)
+#define D1_PLL_CPU_LOCK (1U << 28)
+#define D1_PLL_CPU_OUT_EN (1U << 27)
+#define D1_PLL_CPU_FACTOR_M_MASK (0x3 << 0)
+#define D1_PLL_CPU_FACTOR_N_MASK (0xff << 8)
#define D1_RISCV_CLK_REG 0x0d00
#define D1_RISCV_CLK_SEL (7 << 24)
#define D1_RISCV_CLK_SEL_HOSC (0 << 24)
#define D1_RISCV_CLK_SEL_PLL_CPU (5 << 24)
#define D1_RISCV_DIV_CFG_FACTOR_M(x) (((x) >> 0) & 0x1f)
+#define D1_RISCV_DIV_CFG_FACTOR_M_MASK (0x1f << 0)
#define D1_PSI_CLK_REG 0x0510
#define D1_PSI_CLK_FACTOR_N(x) (((x) >> 8) & 0x3)
#define D1_PSI_CLK_FACTOR_M(x) (((x) >> 0) & 0x3)
@@ -1965,6 +1973,48 @@ sxiccmu_d1_mmc_set_frequency(struct sxic
}
int
+sxiccmu_d1_riscv_set_frequency(struct sxiccmu_softc *sc, uint32_t freq)
+{
+ uint32_t reg, m, n;
+ int lock_timeout = 1000;
+
+ if (freq < 24000000)
+ return -1;
+ n = freq / 24000000;
+ if (n > 256)
+ n = 256;
+ m = 1;
+
+ SXICMS4(sc, D1_RISCV_CLK_REG, D1_RISCV_CLK_SEL,
D1_RISCV_CLK_SEL_HOSC);
+ delay(10);
+
+ SXICLR4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_OUT_EN);
+ reg = SXIREAD4(sc, D1_PLL_CPU_CTRL_REG);
+ reg &= ~(D1_PLL_CPU_FACTOR_N_MASK | D1_PLL_CPU_FACTOR_M_MASK);
+ reg |= ((n - 1) << 8) | ((m - 1) << 0);
+ reg |= D1_PLL_CPU_ENABLE | D1_PLL_CPU_LDO_EN;
+ SXIWRITE4(sc, D1_PLL_CPU_CTRL_REG, reg);
+ SXICLR4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_LOCK_EN);
+ SXISET4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_LOCK_EN);
+
+ while ((SXIREAD4(sc, D1_PLL_CPU_CTRL_REG) & D1_PLL_CPU_LOCK)
== 0) {
+ if (--lock_timeout == 0)
+ return -1;
+ delay(10);
+ }
+
+ delay(20);
+
+ SXISET4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_OUT_EN);
+ reg = SXIREAD4(sc, D1_RISCV_CLK_REG);
+ reg &= ~(D1_RISCV_CLK_SEL | D1_RISCV_DIV_CFG_FACTOR_M_MASK);
+ reg |= D1_RISCV_CLK_SEL_PLL_CPU;
+ SXIWRITE4(sc, D1_RISCV_CLK_REG, reg);
+
+ return 0;
+}
+
+int
sxiccmu_d1_set_frequency(struct sxiccmu_softc *sc, uint32_t idx,
uint32_t freq) {
switch (idx) {
@@ -1974,6 +2024,8 @@ sxiccmu_d1_set_frequency(struct sxiccmu_
return sxiccmu_d1_mmc_set_frequency(sc,
D1_SMHC1_CLK_REG, freq); case D1_CLK_MMC2:
return sxiccmu_d1_mmc_set_frequency(sc,
D1_SMHC2_CLK_REG, freq);
+ case D1_CLK_RISCV:
+ return sxiccmu_d1_riscv_set_frequency(sc, freq);
}
printf("%s: 0x%08x\n", __func__, idx);
Index: sxiccmu.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sxiccmu.c,v
diff -u -p -u -r1.38 sxiccmu.c
--- sxiccmu.c 7 Mar 2024 01:04:16 -0000 1.38
+++ sxiccmu.c 18 Jul 2026 10:14:51 -0000
@@ -1260,11 +1260,19 @@ sxiccmu_a80_get_frequency(struct sxiccmu
#define D1_PLL_CPU_CTRL_REG 0x0000
#define D1_PLL_CPU_FACTOR_M(x) (((x) >> 0) & 0x3)
#define D1_PLL_CPU_FACTOR_N(x) (((x) >> 8) & 0xff)
+#define D1_PLL_CPU_ENABLE (1U << 31)
+#define D1_PLL_CPU_LDO_EN (1U << 30)
+#define D1_PLL_CPU_LOCK_EN (1U << 29)
+#define D1_PLL_CPU_LOCK (1U << 28)
+#define D1_PLL_CPU_OUT_EN (1U << 27)
+#define D1_PLL_CPU_FACTOR_M_MASK (0x3 << 0)
+#define D1_PLL_CPU_FACTOR_N_MASK (0xff << 8)
#define D1_RISCV_CLK_REG 0x0d00
#define D1_RISCV_CLK_SEL (7 << 24)
#define D1_RISCV_CLK_SEL_HOSC (0 << 24)
#define D1_RISCV_CLK_SEL_PLL_CPU (5 << 24)
#define D1_RISCV_DIV_CFG_FACTOR_M(x) (((x) >> 0) & 0x1f)
+#define D1_RISCV_DIV_CFG_FACTOR_M_MASK (0x1f << 0)
#define D1_PSI_CLK_REG 0x0510
#define D1_PSI_CLK_FACTOR_N(x) (((x) >> 8) & 0x3)
#define D1_PSI_CLK_FACTOR_M(x) (((x) >> 0) & 0x3)
@@ -1965,6 +1973,48 @@ sxiccmu_d1_mmc_set_frequency(struct sxic
}
int
+sxiccmu_d1_riscv_set_frequency(struct sxiccmu_softc *sc, uint32_t freq)
+{
+ uint32_t reg, m, n;
+ int lock_timeout = 1000;
+
+ if (freq < 24000000)
+ return -1;
+ n = freq / 24000000;
+ if (n > 256)
+ n = 256;
+ m = 1;
+
+ SXICMS4(sc, D1_RISCV_CLK_REG, D1_RISCV_CLK_SEL, D1_RISCV_CLK_SEL_HOSC);
+ delay(10);
+
+ SXICLR4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_OUT_EN);
+ reg = SXIREAD4(sc, D1_PLL_CPU_CTRL_REG);
+ reg &= ~(D1_PLL_CPU_FACTOR_N_MASK | D1_PLL_CPU_FACTOR_M_MASK);
+ reg |= ((n - 1) << 8) | ((m - 1) << 0);
+ reg |= D1_PLL_CPU_ENABLE | D1_PLL_CPU_LDO_EN;
+ SXIWRITE4(sc, D1_PLL_CPU_CTRL_REG, reg);
+ SXICLR4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_LOCK_EN);
+ SXISET4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_LOCK_EN);
+
+ while ((SXIREAD4(sc, D1_PLL_CPU_CTRL_REG) & D1_PLL_CPU_LOCK) == 0) {
+ if (--lock_timeout == 0)
+ return -1;
+ delay(10);
+ }
+
+ delay(20);
+
+ SXISET4(sc, D1_PLL_CPU_CTRL_REG, D1_PLL_CPU_OUT_EN);
+ reg = SXIREAD4(sc, D1_RISCV_CLK_REG);
+ reg &= ~(D1_RISCV_CLK_SEL | D1_RISCV_DIV_CFG_FACTOR_M_MASK);
+ reg |= D1_RISCV_CLK_SEL_PLL_CPU;
+ SXIWRITE4(sc, D1_RISCV_CLK_REG, reg);
+
+ return 0;
+}
+
+int
sxiccmu_d1_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq)
{
switch (idx) {
@@ -1974,6 +2024,8 @@ sxiccmu_d1_set_frequency(struct sxiccmu_
return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC1_CLK_REG, freq);
case D1_CLK_MMC2:
return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC2_CLK_REG, freq);
+ case D1_CLK_RISCV:
+ return sxiccmu_d1_riscv_set_frequency(sc, freq);
}
printf("%s: 0x%08x\n", __func__, idx);
riscv: implement clock for Allwinner D1 ( MangoPI MQ Pro )