Index | Thread | Search

From:
Nazarenko Mykyta <mykyta@nazarenko.sbs>
Subject:
Re: riscv: implement clock for Allwinner D1 ( MangoPI MQ Pro )
To:
tech@openbsd.org
Date:
Sat, 18 Jul 2026 12:47:53 +0200

Download raw body.

Thread
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);