@@ -279,16 +279,14 @@ static inline void mb(void)
279279 __asm__ volatile ("fence iorw, iorw" ::: "memory" );
280280}
281281
282- /* Simple busy-loop delay
283- * Approximately us microseconds at ~40MHz (early boot clock)
284- * This is used before the timer is fully reliable */
282+ /* DDR-init delay. Forwards to rdcycle-based udelay() so the effective
283+ * delay tracks the current CPU frequency. The previous implementation
284+ * was a hardcoded ~40 MHz busy loop; after mss_pll_init() switches the
285+ * CPU clock to ~600 MHz it ran ~15x too short, silently violating
286+ * LPDDR4 reset / MR-write timing windows. */
285287static void ddr_delay (uint32_t us )
286288{
287- volatile uint32_t i ;
288- /* At ~40MHz, ~10 loop iterations per microsecond */
289- for (i = 0 ; i < us * 10 ; i ++ ) {
290- __asm__ volatile ("nop" );
291- }
289+ udelay (us );
292290}
293291
294292/* IOSCB Bank Controllers and DLL bases */
@@ -559,8 +557,13 @@ static int mss_pll_init(void)
559557 }
560558 }
561559
562- /* Reinitialize UART for new clock frequency */
560+ /* Reinitialize UART for new clock frequency. hal_uart_reinit
561+ * is defined under #ifdef DEBUG_UART (the only path that uses
562+ * the UART driver); skip the call when that block is absent so
563+ * the build links cleanly without DEBUG_UART. */
564+ #ifdef DEBUG_UART
563565 hal_uart_reinit ();
566+ #endif
564567 return 0 ;
565568 }
566569 if ((timeout % 100000 ) == 0 ) {
@@ -1953,18 +1956,37 @@ static int run_training(void)
19531956 uint32_t div0_1_orig = DDR_PLL_REG (PLL_DIV_0_1 );
19541957 uint32_t div2_3_orig = DDR_PLL_REG (PLL_DIV_2_3 );
19551958 {
1956- uint32_t div0 = div0_1_orig & 0x3F00UL ;
1957- uint32_t div1 = div0_1_orig & 0x3F000000UL ;
1958- uint32_t div2 = div2_3_orig & 0x3F00UL ;
1959- uint32_t div3 = div2_3_orig & 0x3F000000UL ;
1960- uint32_t mult = 2 ;
1961-
1962- /* Double the dividers for MR writes */
1963- DDR_PLL_REG (PLL_DIV_0_1 ) = (div0 | div1 ) * mult ;
1964- DDR_PLL_REG (PLL_DIV_2_3 ) = (div2 | div3 ) * mult ;
1965-
1966- /* Wait for PHY PLL to lock */
1967- while ((DDRPHY_REG (PHY_PLL_CTRL_MAIN ) & 0x2000000UL ) == 0 ) {}
1959+ /* Each register holds two 6-bit divider fields at bits [13:8] and
1960+ * [29:24]. Extract numeric values, double (LPDDR4 MR writes need a
1961+ * slower PLL output), clamp to the 6-bit field max so the doubled
1962+ * value cannot overflow into adjacent bits, then re-encode while
1963+ * preserving all other bits of the original register. */
1964+ uint32_t f0 = (div0_1_orig >> 8 ) & 0x3FUL ;
1965+ uint32_t f1 = (div0_1_orig >> 24 ) & 0x3FUL ;
1966+ uint32_t f2 = (div2_3_orig >> 8 ) & 0x3FUL ;
1967+ uint32_t f3 = (div2_3_orig >> 24 ) & 0x3FUL ;
1968+
1969+ f0 = (f0 > 0x1FUL ) ? 0x3FUL : (f0 << 1 );
1970+ f1 = (f1 > 0x1FUL ) ? 0x3FUL : (f1 << 1 );
1971+ f2 = (f2 > 0x1FUL ) ? 0x3FUL : (f2 << 1 );
1972+ f3 = (f3 > 0x1FUL ) ? 0x3FUL : (f3 << 1 );
1973+
1974+ DDR_PLL_REG (PLL_DIV_0_1 ) = (div0_1_orig & ~0x3F003F00UL ) |
1975+ (f0 << 8 ) | (f1 << 24 );
1976+ DDR_PLL_REG (PLL_DIV_2_3 ) = (div2_3_orig & ~0x3F003F00UL ) |
1977+ (f2 << 8 ) | (f3 << 24 );
1978+
1979+ /* Wait for PHY PLL to lock. Bounded at 100 ms so a bad refclk,
1980+ * power glitch, or mis-programmed divider cannot brick boot in
1981+ * an infinite spin -- bail out so the caller can fail cleanly. */
1982+ timeout = 100000 ;
1983+ while ((DDRPHY_REG (PHY_PLL_CTRL_MAIN ) & 0x2000000UL ) == 0 ) {
1984+ if (timeout -- == 0 ) {
1985+ wolfBoot_printf ("DDR: PHY PLL lock timeout (post-doubling)\n" );
1986+ return -1 ;
1987+ }
1988+ udelay (1 );
1989+ }
19681990 ddr_delay (5000 );
19691991
19701992 /* Reset delay lines after frequency change */
@@ -2075,8 +2097,15 @@ static int run_training(void)
20752097 DDR_PLL_REG (PLL_DIV_0_1 ) = div0_1_orig ;
20762098 DDR_PLL_REG (PLL_DIV_2_3 ) = div2_3_orig ;
20772099
2078- /* Wait for PHY PLL to lock */
2079- while ((DDRPHY_REG (PHY_PLL_CTRL_MAIN ) & 0x2000000UL ) == 0 ) {}
2100+ /* Wait for PHY PLL to lock; bounded as in the post-doubling wait above. */
2101+ timeout = 100000 ;
2102+ while ((DDRPHY_REG (PHY_PLL_CTRL_MAIN ) & 0x2000000UL ) == 0 ) {
2103+ if (timeout -- == 0 ) {
2104+ wolfBoot_printf ("DDR: PHY PLL lock timeout (post-restore)\n" );
2105+ return -1 ;
2106+ }
2107+ udelay (1 );
2108+ }
20802109 ddr_delay (500 );
20812110
20822111 /* Reset delay lines after frequency change */
0 commit comments