From 19285745b5ffdf5f61ac75d59cb494a2880a457b Mon Sep 17 00:00:00 2001 From: CTCaer Date: Wed, 26 Nov 2025 14:48:47 +0200 Subject: [PATCH] bdk: clock: improve PLLC init - Use 6 as divm and div1 for OUT1 to avoid having very high frequency on OUT0 There seems to be an undocumented silicon errata where PLLC OUT0 produces EMI to input mux logic in modules, even when not using it. - Always check if PLL is enabled and disable first in order to avoid a silicon errata with hybrid PLLs - Fix PLLC_FLL_LD_MEM value --- bdk/mem/sdram.c | 4 ++-- bdk/soc/clock.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/bdk/mem/sdram.c b/bdk/mem/sdram.c index 53bf609d..9eacf0fa 100644 --- a/bdk/mem/sdram.c +++ b/bdk/mem/sdram.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2023 CTCaer + * Copyright (c) 2019-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -204,7 +204,7 @@ void sdram_src_pllc(bool enable) return; // Set source as PLLC_OUT0. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = 0x20188004; + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = 0x20188002; } else { diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c index ff504b3c..28d442e9 100644 --- a/bdk/soc/clock.c +++ b/bdk/soc/clock.c @@ -520,16 +520,20 @@ void clock_enable_pllx() void clock_enable_pllc(u32 divn) { + u32 enabled = CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_ENABLE; u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF; // Check if already enabled and configured. - if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_ENABLE) && (pll_divn_curr == divn)) + if (enabled && (pll_divn_curr == divn)) return; - // Take PLLC out of reset and set basic misc parameters. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = - ((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x8000 << 4); // PLLC_EXT_FRU. - CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM. + // WAR: Disable first to avoid HPLL overshoot. + if (enabled) + clock_disable_pllc(); + + // Take PLLC out of reset (misc) and set misc2 parameters. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) = (0x8000 << 4); // PLLC_EXT_FRU. + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF << 8; // PLLC_FLL_LD_MEM. // Disable PLL and IDDQ in case they are on. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLL_BASE_ENABLE; @@ -537,15 +541,15 @@ void clock_enable_pllc(u32 divn) usleep(10); // Set PLLC dividers. - CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1. + CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 6; // DIVM: 6, DIVP: 1. // Enable PLLC and wait for Phase and Frequency lock. CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLL_BASE_ENABLE; while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_LOCK)) ; - // Disable PLLC_OUT1, enable reset and set div to 1.5. - CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 1 << 8; + // Disable PLLC_OUT1, enable reset and set div to 1. + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 0; // Enable PLLC_OUT1 and bring it out of reset. CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR;