diff --git a/bdk/display/vic.c b/bdk/display/vic.c
index 145eb09..4611eb4 100644
--- a/bdk/display/vic.c
+++ b/bdk/display/vic.c
@@ -1,7 +1,7 @@
/*
* VIC driver for Tegra X1
*
- * Copyright (c) 2018-2023 CTCaer
+ * Copyright (c) 2018-2024 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,
@@ -539,14 +539,8 @@ int vic_compose()
int vic_init()
{
- // Ease the stress to APB.
- bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
-
clock_enable_vic();
- // Restore sys clock.
- bpmp_clk_rate_set(prev_fid);
-
// Load Fetch Control Engine microcode.
for (u32 i = 0; i < sizeof(vic_fce_ucode) / sizeof(u32); i++)
{
diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c
index ed38cbd..c34eff0 100644
--- a/bdk/input/joycon.c
+++ b/bdk/input/joycon.c
@@ -1215,17 +1215,11 @@ void jc_init_hw()
pinmux_config_uart(UART_B);
pinmux_config_uart(UART_C);
- // Ease the stress to APB.
- bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
-
// Enable UART B and C clocks.
if (!jc_gamepad.sio_mode)
clock_enable_uart(UART_B);
clock_enable_uart(UART_C);
- // Restore OC.
- bpmp_clk_rate_set(prev_fid);
-
jc_init_done = true;
#endif
}
diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c
index 687af40..de2dbbb 100644
--- a/bdk/sec/tsec.c
+++ b/bdk/sec/tsec.c
@@ -75,7 +75,7 @@ int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
void *ptb;
bpmp_mmu_disable();
- bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
+ bpmp_clk_rate_relaxed(true);
// Enable clocks.
clock_enable_tsec();
@@ -305,7 +305,7 @@ out:
clock_disable_sor_safe();
clock_disable_tsec();
bpmp_mmu_enable();
- bpmp_clk_rate_set(prev_fid);
+ bpmp_clk_rate_relaxed(false);
#ifdef BDK_MC_ENABLE_AHB_REDIRECT
// Re-enable AHB aperture.
diff --git a/bdk/soc/bpmp.c b/bdk/soc/bpmp.c
index 669dcc2..b35e737 100644
--- a/bdk/soc/bpmp.c
+++ b/bdk/soc/bpmp.c
@@ -1,7 +1,7 @@
/*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
*
- * Copyright (c) 2019-2023 CTCaer
+ * Copyright (c) 2019-2024 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,
@@ -200,10 +200,44 @@ void bpmp_mmu_disable()
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
}
+
+/*
+ * CLK_RST_CONTROLLER_SCLK_BURST_POLICY:
+ * 0 = CLKM
+ * 1 = PLLC_OUT1
+ * 2 = PLLC4_OUT3
+ * 3 = PLLP_OUT0
+ * 4 = PLLP_OUT2
+ * 5 = PLLC4_OUT1
+ * 6 = CLK_S
+ * 7 = PLLC4_OUT2
+ */
+
+bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;
+
+void bpmp_clk_rate_relaxed(bool enable)
+{
+ // This is a glitch-free way to reduce the SCLK timings.
+ if (enable)
+ {
+ // Restore to PLLP source during PLLC configuration.
+ CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT.
+ usleep(100); // Wait a bit for clock source change.
+ CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
+ }
+ else if (bpmp_fid_current)
+ {
+ // Restore to PLLC_OUT1.
+ CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
+ CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 and CLKM for idle.
+ usleep(100); // Wait a bit for clock source change.
+ }
+}
+
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
-const u8 pll_divn[] = {
+static const u8 pll_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
88, // BPMP_CLK_HIGH2_BOOST: 563MHz 38% - 141MHz APB.
@@ -213,8 +247,6 @@ const u8 pll_divn[] = {
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
};
-bpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;
-
void bpmp_clk_rate_get()
{
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
@@ -237,45 +269,35 @@ void bpmp_clk_rate_get()
}
}
-bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid)
+void bpmp_clk_rate_set(bpmp_freq_t fid)
{
- bpmp_freq_t prev_fid = bpmp_fid_current;
-
if (fid > (BPMP_CLK_MAX - 1))
fid = BPMP_CLK_MAX - 1;
- if (prev_fid == fid)
- return prev_fid;
+ if (bpmp_fid_current == fid)
+ return;
+
+ bpmp_fid_current = fid;
if (fid)
{
- if (prev_fid)
- {
- // Restore to PLLP source during PLLC configuration.
- CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
- msleep(1); // Wait a bit for clock source change.
- }
+ // Use default SCLK / HCLK / PCLK clocks.
+ bpmp_clk_rate_relaxed(true);
// Configure and enable PLLC.
clock_enable_pllc(pll_divn[fid]);
- // Set SCLK / HCLK / PCLK.
- CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
- CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
+ // Set new source and SCLK / HCLK / PCLK dividers.
+ bpmp_clk_rate_relaxed(false);
}
else
{
- CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
- msleep(1); // Wait a bit for clock source change.
- CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
+ // Use default SCLK / HCLK / PCLK clocks.
+ bpmp_clk_rate_relaxed(true);
// Disable PLLC to save power.
clock_disable_pllc();
}
- bpmp_fid_current = fid;
-
- // Return old fid in case of temporary swap.
- return prev_fid;
}
// The following functions halt BPMP to reduce power while sleeping.
diff --git a/bdk/soc/bpmp.h b/bdk/soc/bpmp.h
index 0c55147..77dfd5a 100644
--- a/bdk/soc/bpmp.h
+++ b/bdk/soc/bpmp.h
@@ -1,7 +1,7 @@
/*
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
*
- * Copyright (c) 2019-2023 CTCaer
+ * Copyright (c) 2019-2024 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,
@@ -62,8 +62,9 @@ void bpmp_mmu_maintenance(u32 op, bool force);
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_enable();
void bpmp_mmu_disable();
+void bpmp_clk_rate_relaxed(bool enable);
void bpmp_clk_rate_get();
-bpmp_freq_t bpmp_clk_rate_set(bpmp_freq_t fid);
+void bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_usleep(u32 us);
void bpmp_msleep(u32 ms);
void bpmp_halt();
diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c
index 083a0ed..90538cb 100644
--- a/bdk/soc/clock.c
+++ b/bdk/soc/clock.c
@@ -15,6 +15,7 @@
* along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -153,7 +154,13 @@ void clock_enable_fuse(bool enable)
void clock_enable_uart(u32 idx)
{
+ // Ease the stress to APB.
+ bpmp_clk_rate_relaxed(true);
+
clock_enable(&_clock_uart[idx]);
+
+ // Restore OC.
+ bpmp_clk_rate_relaxed(false);
}
void clock_disable_uart(u32 idx)
@@ -247,7 +254,13 @@ void clock_disable_nvjpg()
void clock_enable_vic()
{
+ // Ease the stress to APB.
+ bpmp_clk_rate_relaxed(true);
+
clock_enable(&_clock_vic);
+
+ // Restore sys clock.
+ bpmp_clk_rate_relaxed(false);
}
void clock_disable_vic()
@@ -323,7 +336,13 @@ void clock_disable_coresight()
void clock_enable_pwm()
{
+ // Ease the stress to APB.
+ bpmp_clk_rate_relaxed(true);
+
clock_enable(&_clock_pwm);
+
+ // Restore OC.
+ bpmp_clk_rate_relaxed(false);
}
void clock_disable_pwm()
@@ -464,10 +483,10 @@ void clock_enable_pllc(u32 divn)
;
// Disable PLLC_OUT1, enable reset and set div to 1.5.
- CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = BIT(8);
+ CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 1 << 8;
// Enable PLLC_OUT1 and bring it out of reset.
- CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
+ CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR;
msleep(1); // Wait a bit for PLL to stabilize.
}
diff --git a/bdk/thermal/fan.c b/bdk/thermal/fan.c
index 6927fe4..5f52118 100644
--- a/bdk/thermal/fan.c
+++ b/bdk/thermal/fan.c
@@ -1,7 +1,7 @@
/*
* Fan driver for Nintendo Switch
*
- * Copyright (c) 2018-2023 CTCaer
+ * Copyright (c) 2018-2024 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,
@@ -49,16 +49,8 @@ void set_fan_duty(u32 duty)
// Enable PWM if disabled.
if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA)
- {
- // Ease the stress to APB.
- bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
-
clock_enable_pwm();
- // Restore OC.
- bpmp_clk_rate_set(prev_fid);
- }
-
PWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Max PWM to disable fan.
PINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1.