From: Nazarenko Mykyta Subject: Re: riscv: implement clock for Allwinner D1 ( MangoPI MQ Pro ) To: tech@openbsd.org Date: Sat, 18 Jul 2026 12:47:53 +0200 On Sat, 18 Jul 2026 12:23:11 +0200 Nazarenko Mykyta 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);