From 7a74761da98d92933c5c0045bc78d7adb9a9268a Mon Sep 17 00:00:00 2001 From: CTCaer Date: Sun, 2 Jun 2024 06:51:06 +0300 Subject: [PATCH] bdk: bpmp: add and use bpmp_clk_rate_relaxed --- bdk/display/vic.c | 8 +----- bdk/input/joycon.c | 6 ---- bdk/sec/tsec.c | 4 +-- bdk/soc/bpmp.c | 72 ++++++++++++++++++++++++++++++---------------- bdk/soc/bpmp.h | 5 ++-- bdk/soc/clock.c | 23 +++++++++++++-- bdk/thermal/fan.c | 10 +------ 7 files changed, 75 insertions(+), 53 deletions(-) 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.