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
This commit is contained in:
CTCaer
2025-11-26 14:48:47 +02:00
parent 9c028cd94a
commit 19285745b5
2 changed files with 14 additions and 10 deletions

View File

@@ -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
{

View File

@@ -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;