This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit f447346895c44e0117d7416bface98ddf41a0d5a
Author: Jorge Guzman <[email protected]>
AuthorDate: Sun Oct 25 18:40:49 2026 -0300

    arch/risc-v/gd32vw55x: set the clocks up as the firmware library V1.6.0
    
    - The GigaDevice firmware library V1.6.0 changed SystemInit(): it waits
      for the IRC16M to be stable, lowers the AHB clock in two steps (/2,
      then /4) when the system still runs from the PLL, and waits after the
      switch back to the IRC16M, to limit the core voltage swings.  This
      matters when an image is started by a bootloader that already raised
      the clock.  Do the same before the clock tree is set up again.
    - The HXTAL stable flag never sets on the GD32VW553, and the firmware
      library does not wait for it.  But the PLL locked to the 40 MHz
      crystal while it is still starting runs about 12 percent slow for
      about 0.5 ms: measured against the RTC right after deep-sleep, where
      the clock tree is set up again on every wake-up.  Wait 1 ms on the
      IRC16M before the PLL, counted by the system timer, whose clock
      source is now selected before the wait.
    
    Tested with a direct boot on the GD32VW553K-START: "sleep 10" lasts
    10.05 s on the host.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Jorge Guzman <[email protected]>
---
 arch/risc-v/src/gd32vw55x/gd32vw55x_clockconfig.c  | 85 ++++++++++++++++++++--
 arch/risc-v/src/gd32vw55x/hardware/gd32vw55x_rcu.h |  3 +
 2 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/arch/risc-v/src/gd32vw55x/gd32vw55x_clockconfig.c 
b/arch/risc-v/src/gd32vw55x/gd32vw55x_clockconfig.c
index 5a97a027c81..9266484e2af 100644
--- a/arch/risc-v/src/gd32vw55x/gd32vw55x_clockconfig.c
+++ b/arch/risc-v/src/gd32vw55x/gd32vw55x_clockconfig.c
@@ -36,11 +36,51 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* SysTimer MTIMECTL register (Nuclei core-local, not in the RCU) */
+/* SysTimer registers (Nuclei core-local, not in the RCU) */
 
+#define GD32VW55X_SYSTIMER_MTIME     (GD32VW55X_SYSTIMER_BASE + 0x0000)
 #define GD32VW55X_SYSTIMER_MTIMECTL  (GD32VW55X_SYSTIMER_BASE + 0x0ff8)
 #define SYSTIMER_MTIMECTL_CLKSRC     (1 << 2)  /* 1: mtime = sysclock */
 
+/* The HXTAL stable flag never sets, and the firmware library does not wait
+ * for it.  But the PLL locked to the crystal while it starts runs about 12
+ * percent slow for about 0.5 ms (measured after deep-sleep, against the
+ * RTC): wait for the crystal on the IRC16M, counted by the system timer.
+ */
+
+#define GD32VW55X_IRC16M_FREQ        16000000
+#define GD32VW55X_HXTAL_SETTLE_US    1000
+
+/* Busy loop counts while the system clock changes: after each AHB
+ * prescaler step (RCU_MODIFY(0x50)) and after the switch back to the
+ * IRC16M (_soft_delay_(200)) in the firmware library V1.6.0.
+ */
+
+#define GD32VW55X_AHB_STEP_DELAY     0x50
+#define GD32VW55X_SWITCH_DELAY       2000
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: gd32vw55x_clockdelay
+ *
+ * Description:
+ *   Busy loop used while the system clock changes, before any timer runs
+ *   (the counts of the firmware library V1.6.0).
+ *
+ ****************************************************************************/
+
+static void gd32vw55x_clockdelay(uint32_t loops)
+{
+  volatile uint32_t i;
+
+  for (i = 0; i < loops; i++)
+    {
+    }
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -58,11 +98,33 @@
 void gd32vw55x_clockconfig(void)
 {
   uint32_t regval;
+  uint32_t start;
 
-  /* Reset the RCU to a known state (SDK SystemInit sequence) */
+  /* Reset the RCU to a known state (SDK SystemInit sequence).  When the
+   * system still runs from the PLL, started by a bootloader, lower the AHB
+   * clock in steps before going back to the IRC16M, and let the core
+   * voltage settle after the switch, as the firmware library V1.6.0 does.
+   */
 
   modifyreg32(GD32VW55X_RCU_CTL, 0, RCU_CTL_IRC16MEN);
+
+  while ((getreg32(GD32VW55X_RCU_CTL) & RCU_CTL_IRC16MSTB) == 0)
+    {
+    }
+
+  if ((getreg32(GD32VW55X_RCU_CFG0) & RCU_CFG0_SCSS_MASK) ==
+      RCU_CFG0_SCSS_PLLDIG)
+    {
+      modifyreg32(GD32VW55X_RCU_CFG0, RCU_CFG0_AHBPSC_MASK,
+                  RCU_CFG0_AHBPSC_DIV2);
+      gd32vw55x_clockdelay(GD32VW55X_AHB_STEP_DELAY);
+      modifyreg32(GD32VW55X_RCU_CFG0, RCU_CFG0_AHBPSC_MASK,
+                  RCU_CFG0_AHBPSC_DIV4);
+      gd32vw55x_clockdelay(GD32VW55X_AHB_STEP_DELAY);
+    }
+
   modifyreg32(GD32VW55X_RCU_CFG0, RCU_CFG0_SCS_MASK, 0);
+  gd32vw55x_clockdelay(GD32VW55X_SWITCH_DELAY);
   putreg32(0, GD32VW55X_RCU_CFG0);
   modifyreg32(GD32VW55X_RCU_CFG1,
               RCU_CFG1_RFPLLCALEN | RCU_CFG1_RFPLLPU, 0);
@@ -78,6 +140,19 @@ void gd32vw55x_clockconfig(void)
 
   modifyreg32(GD32VW55X_RCU_CTL, 0, RCU_CTL_HXTALPU);
   modifyreg32(GD32VW55X_RCU_CTL, 0, RCU_CTL_HXTALEN);
+
+  /* SysTimer clock source = sysclock (not sysclock/4), still the IRC16M,
+   * then the PLL: the mtime tick runs at 160 MHz
+   */
+
+  modifyreg32(GD32VW55X_SYSTIMER_MTIMECTL, 0, SYSTIMER_MTIMECTL_CLKSRC);
+
+  start = getreg32(GD32VW55X_SYSTIMER_MTIME);
+  while (getreg32(GD32VW55X_SYSTIMER_MTIME) - start <
+         GD32VW55X_IRC16M_FREQ / 1000000 * GD32VW55X_HXTAL_SETTLE_US)
+    {
+    }
+
   modifyreg32(GD32VW55X_RCU_CTL, 0, RCU_CTL_HXTALREADY);
 
   /* Bus prescalers: AHB = SYSCLK, APB2 = AHB, APB1 = AHB/2 */
@@ -118,10 +193,4 @@ void gd32vw55x_clockconfig(void)
          RCU_CFG0_SCSS_PLLDIG)
     {
     }
-
-  /* SysTimer clock source = sysclock (not sysclock/4) so that the
-   * mtime tick runs at 160 MHz
-   */
-
-  modifyreg32(GD32VW55X_SYSTIMER_MTIMECTL, 0, SYSTIMER_MTIMECTL_CLKSRC);
 }
diff --git a/arch/risc-v/src/gd32vw55x/hardware/gd32vw55x_rcu.h 
b/arch/risc-v/src/gd32vw55x/hardware/gd32vw55x_rcu.h
index 8ec1db9d9e7..a36bd2554b0 100644
--- a/arch/risc-v/src/gd32vw55x/hardware/gd32vw55x_rcu.h
+++ b/arch/risc-v/src/gd32vw55x/hardware/gd32vw55x_rcu.h
@@ -55,6 +55,7 @@
 /* CTL register */
 
 #define RCU_CTL_IRC16MEN            (1 << 0)   /* IRC16M enable */
+#define RCU_CTL_IRC16MSTB           (1 << 1)   /* IRC16M stable flag */
 #define RCU_CTL_HXTALEN             (1 << 16)  /* HXTAL enable */
 #define RCU_CTL_HXTALSTB            (1 << 17)  /* HXTAL stable flag */
 #define RCU_CTL_PLLDIGPU            (1 << 20)  /* PLLDIG power up */
@@ -78,6 +79,8 @@
 #define RCU_CFG0_SCSS_PLLDIG        (2 << 2)
 #define RCU_CFG0_AHBPSC_MASK        (15 << 4)  /* AHB prescaler */
 #define RCU_CFG0_AHBPSC_DIV1        (0 << 4)
+#define RCU_CFG0_AHBPSC_DIV2        (8 << 4)
+#define RCU_CFG0_AHBPSC_DIV4        (9 << 4)
 #define RCU_CFG0_APB1PSC_MASK       (7 << 10)  /* APB1 prescaler */
 #define RCU_CFG0_APB1PSC_DIV2       (4 << 10)
 #define RCU_CFG0_APB2PSC_MASK       (7 << 13)  /* APB2 prescaler */

Reply via email to