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