diff --git a/LICENSE b/LICENSE index 1ccef1f1..f3642129 100644 --- a/LICENSE +++ b/LICENSE @@ -4,8 +4,9 @@ - Tinymembench is under MIT license, which is compatible with GPL v2. -- Although "sys-clk" uses permissive license, all modifications towards it in this repo ("hoc-sys") are licensed under GPL v2. +- Although "sys-clk" uses a permissive license, all modifications towards it in this repo ("hoc-sys") are licensed under GPL v2. +- Hekate Power BDK is made by CtCaer and licensed under GPLv2 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 diff --git a/README.md b/README.md index 73219487..2c4f812f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ --- -![License: GPL-2.0](https://img.shields.io/badge/GPL--2.0-red?style=for-the-badge) +![License: GPLv2](https://img.shields.io/badge/GPL--2.0-red?style=for-the-badge) ![Nintendo Switch](https://img.shields.io/badge/Nintendo_Switch-E60012?style=for-the-badge\&logo=nintendo-switch\&logoColor=white) [![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge\&logo=discord\&logoColor=white)](https://discord.com/invite/S3eX47dHsB) ![VSCode](https://img.shields.io/badge/VSCode-0078D4?style=for-the-badge\&logo=visual%20studio%20code\&logoColor=white) @@ -14,98 +14,51 @@ --- - +### DISCLAIMER: THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION +* Due to the design of Horizon OS, overclocking RAM can cause **NAND DAMAGE**. Ensure to have a NAND Backup
-## ⚠️ Disclaimer +A open source overclocking tool for Nintendo Switch consoles running Atmosphere custom firmware
-> **THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION.** -> Due to the design of Horizon OS, **overclocking RAM can cause NAND DAMAGE.** -> Ensure you have a **full NAND backup** before proceeding. ---- +## Features: +CPU overclock up to 2397MHz on Mariko units, 2091MHz on Erista units
+GPU up to 1305MHz on Mariko units, 998MHz on Erista units
+RAM up to 3200MHz on Mariko units, 2360MHz on Erista units
+Over/undervolting
+Configurator
+Works with most homebrew
-## 🌀 About +*Higher (potentially dangerous) frequencies are unlockable*
+*The exact maximum overclock varies per console*
+## Installation +Ensure you have the latest version of [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere) and [Ultrahand](https://github.com/ppkantorski/Ultrahand-Overlay) installed before continuing
+Grab latest hoc.kip from releases tab
+If using hekate, edit hekate_ipl.ini to include "kip1=atmosphere/kips/*". No need for editing if using fusee
+Download latest Horizon OC sysmodule from releases tab
+Extract sysmodule into root of SD card
-**Horizon OC** is an open-source overclocking tool for Nintendo Switch consoles running **Atmosphere custom firmware**. -It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration tools. +Alternatively, you can download the configurator and click the two install buttons
---- -## 🚀 Features +## Configuration +Download the latest configurator on your computer
+Run the file
+Select the drive your SD card or UMS device is mounted as
+Configure the kip to your liking, and in the end, save it
-* **CPU:** Up to `2397MHz` (Mariko) / `2091MHz` (Erista) -* **GPU:** Up to `1305MHz` (Mariko) / `998MHz` (Erista) -* **RAM:** Up to `3200MHz` (Mariko) / `2360MHz` (Erista) -* Over/undervolting support -* Built-in configurator -* Compatible with most homebrew +## Building +Set up a development enviorment ready to compile Atmosphere
+Git clone Atmosphere, and move the cloned folder into build/
+Insert Source/stratosphere folder into build/
+Run build.sh -> ⚡ *Higher (potentially dangerous) frequencies are unlockable.* -> ⚙️ *Exact maximum values vary per console.* +To build the configurator, cd into Source/Configurator
+Run build.bat or run "python -m PyInstaller --onefile --add-data "assets;assets" --icon=assets/icon.ico --noconsole src/main.py"
---- - -## 🧩 Installation - -1. Ensure you have the latest versions of - - * [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere) - * [Ultrahand Overlay](https://github.com/ppkantorski/Ultrahand-Overlay) -2. Download the latest **hoc.kip** file from the [Releases](../../releases) tab. -3. If using **Hekate**, edit `hekate_ipl.ini` to include: - - ``` - kip1=atmosphere/kips/* - ``` - - *(No changes needed if using fusee.)* -4. Download and extract the **Horizon OC sysmodule** to the root of your SD card. -5. Alternatively, use the **Configurator** and click the **Install** buttons for automatic setup. - ---- - -## ⚙️ Configuration - -1. Download the latest **Configurator** on your computer. -2. Run the executable. -3. Select your SD card or UMS drive. -4. Adjust overclocking settings as desired. -5. Click **Save** to apply your configuration. - ---- - -## 🧱 Building from Source - -1. Set up a development environment for compiling **Atmosphere**. -2. Clone Atmosphere: - - ```bash - git clone https://github.com/Atmosphere-NX/Atmosphere.git - ``` -3. Move the cloned folder into `build/`. -4. Insert your `Source/stratosphere` folder into `build/`. -5. Run: - - ```bash - ./build.sh - ``` - -To build the Configurator: - -```bash -cd Source/Configurator -build.bat -# or -python -m PyInstaller --onefile --add-data "assets;assets" --icon=assets/icon.ico --noconsole src/main.py -``` - ---- - -## 💎 Credits - -* **Lightos** & **Dominatorul** – RAM timings -* **KazushiMe** & **meha** – Switch-OC-Suite -* **sys-clk team** – sys-clk -* **b0rd2death** – Ultrahand sys-clk fork -* **Lightos** & **Sammybigio2011** – Early testing +## Credits +Lightos for RAM timings
+KazushiMe and meha for Switch-Oc-Suite
+sys-clk team for sys-clk
+b0rd2death for Ultrahand sys-clk fork
+Lightos and Sammybigio2011 for early testing
\ No newline at end of file diff --git a/Source/sys-clk/common/include/sysclk/board.h b/Source/sys-clk/common/include/sysclk/board.h index 04dbbe2c..85dd484c 100644 --- a/Source/sys-clk/common/include/sysclk/board.h +++ b/Source/sys-clk/common/include/sysclk/board.h @@ -62,6 +62,9 @@ typedef enum SysClkThermalSensor_SOC = 0, SysClkThermalSensor_PCB, SysClkThermalSensor_Skin, +// HocClkThermalSensor_BQ24193, + HocClkThermalSensor_Battery, + HocClkThermalSensor_PMIC, SysClkThermalSensor_EnumMax } SysClkThermalSensor; @@ -87,6 +90,16 @@ typedef enum ReverseNX_Docked, } ReverseNXMode; +typedef enum { + HocClkConsoleType_V1 = 0, + HocClkConsoleType_UnreleasedErista, + HocClkConsoleType_UnreleasedMariko, + HocClkConsoleType_V2, + HocClkConsoleType_Lite, + HocClkConsoleType_UnreleasedMariko2, + HocClkConsoleType_OLED, + HocClkConsoleType_EnumMax, +} HocClkConsoleType; #define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax) diff --git a/Source/sys-clk/common/include/sysclk/config.h b/Source/sys-clk/common/include/sysclk/config.h index a29137ec..1d8f6bc7 100644 --- a/Source/sys-clk/common/include/sysclk/config.h +++ b/Source/sys-clk/common/include/sysclk/config.h @@ -60,6 +60,15 @@ typedef enum { HocClkConfigValue_EnforceBoardLimit, + HocClkConfigValue_EristaBoostClock, + HocClkConfigValue_MarikoBoostClock, + + HocClkConfigValue_EMCEnableUnsafeVoltages, + HocClkConfigValue_EMCVdd2VoltageuV, + HocClkConfigValue_EMCVddqVoltageuV, + + HocClkConfigValue_PWMDimming, + SysClkConfigValue_EnumMax, } SysClkConfigValue; @@ -122,7 +131,20 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr case HocClkConfigValue_TDPCycleLimit: return pretty ? "TDP Cycle Limit" : "tdp_limit_c"; - + case HocClkConfigValue_EnforceBoardLimit: + return pretty ? "Enforce Board Limit" : "enforce_board_limit"; + case HocClkConfigValue_EristaBoostClock: + return pretty ? "Boost Clock" : "e_boost_clock"; + case HocClkConfigValue_MarikoBoostClock: + return pretty ? "Boost Clock" : "m_boost_clock"; + case HocClkConfigValue_EMCEnableUnsafeVoltages: + return pretty ? "EMC Unsafe Voltages" : "emc_unsafe_voltages"; + case HocClkConfigValue_EMCVdd2VoltageuV: + return pretty ? "EMC VDD2 Voltage (mV)" : "emc_vdd2_voltage_uv"; + case HocClkConfigValue_EMCVddqVoltageuV: + return pretty ? "EMC VDDQ Voltage (mV)" : "emc_vddq_voltage_uv"; + case HocClkConfigValue_PWMDimming: + return pretty ? "PWM Dimming" : "pwm_dimming"; default: return pretty ? "Null" : "null"; } @@ -140,8 +162,10 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) case SysClkConfigValue_CsvWriteIntervalMs: case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_OverwriteBoostMode: + case HocClkConfigValue_EMCEnableUnsafeVoltages: return 0ULL; case HocClkConfigValue_EristaMaxCpuClock: + case HocClkConfigValue_EristaBoostClock: return 1785ULL; case HocClkConfigValue_EristaMaxGpuClock: return 921ULL; @@ -149,16 +173,18 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) return 1600ULL; case HocClkConfigValue_MarikoMaxCpuClock: + case HocClkConfigValue_MarikoBoostClock: return 1963ULL; case HocClkConfigValue_MarikoMaxGpuClock: return 1075ULL; case HocClkConfigValue_MarikoMaxMemClock: return 1862ULL; - case HocClkConfigValue_ThermalThrottle: case HocClkConfigValue_DockedGovernor: case HocClkConfigValue_HandheldGovernor: case HocClkConfigValue_HandheldTDP: + case HocClkConfigValue_EnforceBoardLimit: + case HocClkConfigValue_PWMDimming: return 1ULL; case HocClkConfigValue_ThermalThrottleThreshold: return 70ULL; @@ -168,6 +194,10 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val) return 6400ULL; case HocClkConfigValue_TDPCycleLimit: return 10ULL; + case HocClkConfigValue_EMCVdd2VoltageuV: + return 1175000ULL; + case HocClkConfigValue_EMCVddqVoltageuV: + return 600000ULL; default: return 0ULL; } @@ -193,6 +223,10 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in case SysClkConfigValue_PowerLogIntervalMs: case SysClkConfigValue_CsvWriteIntervalMs: case HocClkConfigValue_TDPCycleLimit: + case HocClkConfigValue_EristaBoostClock: + case HocClkConfigValue_MarikoBoostClock: + case HocClkConfigValue_EMCVdd2VoltageuV: + case HocClkConfigValue_EMCVddqVoltageuV: return input >= 0; case HocClkConfigValue_UncappedClocks: case HocClkConfigValue_OverwriteBoostMode: @@ -200,7 +234,11 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in case HocClkConfigValue_DockedGovernor: case HocClkConfigValue_HandheldGovernor: case HocClkConfigValue_HandheldTDP: + case HocClkConfigValue_EnforceBoardLimit: + case HocClkConfigValue_EMCEnableUnsafeVoltages: + case HocClkConfigValue_PWMDimming: return (input & 0x1) == input; + default: return false; } diff --git a/Source/sys-clk/common/include/sysclk/ipc.h b/Source/sys-clk/common/include/sysclk/ipc.h index 51474458..72f11ee3 100644 --- a/Source/sys-clk/common/include/sysclk/ipc.h +++ b/Source/sys-clk/common/include/sysclk/ipc.h @@ -49,7 +49,7 @@ enum SysClkIpcCmd SysClkIpcCmd_SetConfigValues = 10, SysClkIpcCmd_GetFreqList = 11, SysClkIpcCmd_SetReverseNXRTMode = 12, - HocClkIpcCmd_UpdateEMCRegs = 13, + HocClkIpcCmd_UpdateEMC = 13, }; diff --git a/Source/sys-clk/common/src/client/ipc.c b/Source/sys-clk/common/src/client/ipc.c index c982759e..bd77738b 100644 --- a/Source/sys-clk/common/src/client/ipc.c +++ b/Source/sys-clk/common/src/client/ipc.c @@ -152,5 +152,5 @@ Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode) Result hocClkIpcUpdateEmcRegs() { int nil = 0; - return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, nil); + return serviceDispatchIn(&g_sysclkSrv, HocClkIpcCmd_UpdateEMC, nil); } diff --git a/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp index 545f402a..4a928403 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/base_gui.cpp @@ -23,20 +23,13 @@ * stuff is worth it, you can buy us a beer in return. - The sys-clk authors * -------------------------------------------------------------------------- */ - - #include "base_gui.h" - #include "../elements/base_frame.h" #include "logo_rgba_bin.h" - - - #define LOGO_X 20 #define LOGO_Y 45 #define LOGO_LABEL_FONT_SIZE 35 - #define VERSION_X (LOGO_X + 250) #define VERSION_Y LOGO_Y-40 #define VERSION_FONT_SIZE 15 @@ -52,9 +45,12 @@ std::string getVersionString() { void BaseGui::preDraw(tsl::gfx::Renderer* renderer) { -// renderer->drawBitmap(LOGO_X, LOGO_Y, LOGO_WIDTH, LOGO_HEIGHT, logo_rgba_bin); - renderer->drawString("Horizon OC overlay", false, LOGO_X, LOGO_Y, LOGO_LABEL_FONT_SIZE, renderer->a(TEXT_COLOR)); -// renderer->drawString(TARGET_VERSION, false, VERSION_X, VERSION_Y, VERSION_FONT_SIZE, tsl::bannerVersionTextColor); + // Draw "Horizon OC " in default color + renderer->drawString("Horizon OC ", false, LOGO_X, LOGO_Y, LOGO_LABEL_FONT_SIZE, renderer->a(TEXT_COLOR)); + + // Draw "Gaea" in green + tsl::Color greenColor(40, 204, 40, 255); // Light green + renderer->drawString("Gaea", false, LOGO_X + 225, LOGO_Y, LOGO_LABEL_FONT_SIZE, greenColor); } tsl::elm::Element* BaseGui::createUI() @@ -67,4 +63,4 @@ tsl::elm::Element* BaseGui::createUI() void BaseGui::update() { this->refresh(); -} +} \ No newline at end of file diff --git a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp index 21f3e0bb..5d75392b 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.cpp @@ -1,4 +1,15 @@ /* + * -------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * , , + * wrote this file. As long as you retain this notice you can do whatever you + * want with this stuff. If you meet any of us some day, and you think this + * stuff is worth it, you can buy us a beer in return. - The sys-clk authors + * -------------------------------------------------------------------------- + */ + +/* + * * Copyright (c) Souldbminer and Horizon OC Contributors * * This program is free software; you can redistribute it and/or modify it @@ -12,297 +23,322 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * */ + + #include "base_menu_gui.h" + #include "fatal_gui.h" -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ + // Cache hardware model to avoid repeated syscalls + + BaseMenuGui::BaseMenuGui() + { + tsl::initializeThemeVars(); + this->context = nullptr; + this->lastContextUpdate = 0; + this->listElement = nullptr; + + // Initialize all voltages to zero once + memset(&cpuVoltageUv, 0, sizeof(u32) * 5); // Zero all 5 voltage values at once + + // Pre-cache hardware model during initialization + IsMariko(); + + // Initialize display strings + memset(displayStrings, 0, sizeof(displayStrings)); + } + + BaseMenuGui::~BaseMenuGui() { + delete this->context; // delete handles nullptr automatically + } + + // Fast preDraw - just renders pre-computed strings + void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) { + BaseGui::preDraw(renderer); + if(!this->context) [[unlikely]] return; + + // All constants pre-calculated and cached + static constexpr const char* const labels[] = { + "App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg", "CPU", "GPU", "PLL", "PMIC", "BAT" + }; + + static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1}; + + static u32 labelWidths[10]; + static bool positionsInitialized = false; + + if (!positionsInitialized) { + for (int i = 0; i < 10; i++) { + labelWidths[i] = renderer->getTextDimensions(labels[i], false, SMALL_TEXT_SIZE).first; + } + positionsInitialized = true; + } + static u32 positions[10] = {24-1, 310-labelWidths[1], 24-1, 192-labelWidths[3], 332-labelWidths[4], 24-1, 192 - labelWidths[6], 332-labelWidths[7], 192 - labelWidths[8], 332-labelWidths[9]}; + + static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word + + u32 y = 91; + + // === TOP SECTION === + // renderer->drawRoundedRect(14, 70-1, 420, 30+2, 10.0f, renderer->aWithOpacity(tsl::tableBGColor)); + + // App ID - use pre-formatted string + renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(displayStrings[0], false, positions[0] + labelWidths[0] + 9, y, SMALL_TEXT_SIZE, tsl::infoTextColor); + + // Profile - use pre-formatted string + renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor); + + y = y + 38; // Direct assignment instead of += 38 + + // === MAIN DATA SECTION === + // renderer->drawRoundedRect(14, 106, 420, 116, 10.0f, renderer->aWithOpacity(tsl::tableBGColor)); + + // === FREQUENCY SECTION === + // Labels first (better cache locality) + renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + + // Current frequencies - use pre-formatted strings + renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU + renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU + renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM + + y = y + 20; // Direct assignment (129 + 20) + + // === REAL FREQUENCIES === + renderer->drawString(displayStrings[5], false, positions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real + renderer->drawString(displayStrings[6], false, positions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real + renderer->drawString(displayStrings[7], false, positions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real + + y = y + 20; // Direct assignment (149 + 20) + + // === VOLTAGES === + renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage + renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage + + // Memory voltage - check if VDD is present + if (emcVoltageUv && vddVoltageUv) { + renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor); + } else if (vddVoltageUv) { + renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); + } else if (emcVoltageUv) { + renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); + } + + // y = y + 20; // Direct assignment (169 + 22) + + + // renderer->drawString(displayStrings[17], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[3]); // CPU + // renderer->drawString(displayStrings[18], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[4]); // GPU + // renderer->drawString(displayStrings[19], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[5]); // PLL + + y = y + 22; // Direct assignment (149 + 20) + + // === TEMPERATURE SECTION === + // Labels + renderer->drawString(labels[5], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[6], false, positions[6]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[7], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + + // Temperatures with color - use pre-computed colors + renderer->drawString(displayStrings[11], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[0]); // SOC + renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[1]); // PCB + renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[2]); // Skin + + y = y + 20; // Direct assignment (191 + 20) + + // === SOC VOLTAGE & POWER === + // SOC voltage (if available) + if (socVoltageUv) [[likely]] { + renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); + } + + // Power labels and values + renderer->drawString(labels[8], false, positions[8]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + renderer->drawString(labels[9], false, positions[9], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); + + renderer->drawString(displayStrings[15], false, dataPositions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power now + renderer->drawString(displayStrings[16], false, dataPositions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power avg + + y = y + 20; // Direct assignment (191 + 20) + renderer->drawString(displayStrings[20], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[4]); // BAT + renderer->drawString(displayStrings[21], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[5]); // PMIC -#include "base_menu_gui.h" -#include "fatal_gui.h" + y = y + 20; // Direct assignment (191 + 20) -// Cache hardware model to avoid repeated syscalls - -BaseMenuGui::BaseMenuGui() : tempColors{tsl::Color(0), tsl::Color(0), tsl::Color(0)} -{ - tsl::initializeThemeVars(); - this->context = nullptr; - this->lastContextUpdate = 0; - this->listElement = nullptr; - - // Initialize all voltages to zero once - memset(&cpuVoltageUv, 0, sizeof(u32) * 5); // Zero all 5 voltage values at once - - // Pre-cache hardware model during initialization - IsMariko(); - - // Initialize display strings - memset(displayStrings, 0, sizeof(displayStrings)); -} - -BaseMenuGui::~BaseMenuGui() { - delete this->context; // delete handles nullptr automatically -} - -// Fast preDraw - just renders pre-computed strings -void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer) { - BaseGui::preDraw(renderer); - if(!this->context) [[unlikely]] return; - - // All constants pre-calculated and cached - static constexpr const char* const labels[10] = { - "App ID", "Profile", "CPU", "GPU", "MEM", "SoC", "Board", "Skin", "Now", "Avg" - }; - - static constexpr u32 dataPositions[6] = {63-3+3, 200-1, 344-1-3, 200-1, 342-1, 321-1}; - - static u32 labelWidths[10]; - static bool positionsInitialized = false; - - if (!positionsInitialized) { - for (int i = 0; i < 10; i++) { - labelWidths[i] = renderer->getTextDimensions(labels[i], false, SMALL_TEXT_SIZE).first; - } - positionsInitialized = true; - } - static u32 positions[10] = {24-1, 310-labelWidths[1], 24-1, 192-labelWidths[3], 332-labelWidths[4], 24-1, 192 - labelWidths[6], 332-labelWidths[7], 192 - labelWidths[8], 332-labelWidths[9]}; - - static u32 maxProfileValueWidth = renderer->getTextDimensions("PD Charger", false, SMALL_TEXT_SIZE).first; // longest word - - u32 y = 91; - - // === TOP SECTION === - renderer->drawRoundedRect(14, 70-1, 420, 30+2, 10.0f, renderer->aWithOpacity(tsl::tableBGColor)); - - // App ID - use pre-formatted string - renderer->drawString(labels[0], false, positions[0], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(displayStrings[0], false, positions[0] + labelWidths[0] + 9, y, SMALL_TEXT_SIZE, tsl::infoTextColor); - - // Profile - use pre-formatted string - renderer->drawString(labels[1], false, 423 - maxProfileValueWidth - labelWidths[1] - 9, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(displayStrings[1], false, 423 - maxProfileValueWidth, y, SMALL_TEXT_SIZE, tsl::infoTextColor); - - y = 129; // Direct assignment instead of += 38 - - // === MAIN DATA SECTION === - renderer->drawRoundedRect(14, 106, 420, 116, 10.0f, renderer->aWithOpacity(tsl::tableBGColor)); - - // === FREQUENCY SECTION === - // Labels first (better cache locality) - renderer->drawString(labels[2], false, positions[2], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(labels[3], false, positions[3], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(labels[4], false, positions[4], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - - // Current frequencies - use pre-formatted strings - renderer->drawString(displayStrings[2], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU - renderer->drawString(displayStrings[3], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU - renderer->drawString(displayStrings[4], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM - - y = 149; // Direct assignment (129 + 20) - - // === REAL FREQUENCIES === - renderer->drawString(displayStrings[5], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU real - renderer->drawString(displayStrings[6], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU real - renderer->drawString(displayStrings[7], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // MEM real - - y = 169; // Direct assignment (149 + 20) - - // === VOLTAGES === - renderer->drawString(displayStrings[8], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // CPU voltage - renderer->drawString(displayStrings[9], false, dataPositions[1], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // GPU voltage - - // Memory voltage - check if VDD is present - if (emcVoltageUv && vddVoltageUv) { - renderer->drawStringWithColoredSections(displayStrings[10], false, {""}, dataPositions[5]-16, y, SMALL_TEXT_SIZE, tsl::infoTextColor, tsl::separatorColor); - } else if (vddVoltageUv) { - renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); - } else if (emcVoltageUv) { - renderer->drawString(displayStrings[10], false, dataPositions[2], y, SMALL_TEXT_SIZE, tsl::infoTextColor); - } - - y = 191; // Direct assignment (169 + 22) - - // === TEMPERATURE SECTION === - // Labels - renderer->drawString(labels[5], false, positions[5], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(labels[6], false, positions[6]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(labels[7], false, positions[7], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - - // Temperatures with color - use pre-computed colors - renderer->drawString(displayStrings[11], false, dataPositions[0], y, SMALL_TEXT_SIZE, tempColors[0]); // SOC - renderer->drawString(displayStrings[12], false, dataPositions[1], y, SMALL_TEXT_SIZE, tempColors[1]); // PCB - renderer->drawString(displayStrings[13], false, dataPositions[2], y, SMALL_TEXT_SIZE, tempColors[2]); // Skin - - y = 211; // Direct assignment (191 + 20) - - // === SOC VOLTAGE & POWER === - // SOC voltage (if available) - if (socVoltageUv) [[likely]] { - renderer->drawString(displayStrings[14], false, dataPositions[0], y, SMALL_TEXT_SIZE, tsl::infoTextColor); - } - - // Power labels and values - renderer->drawString(labels[8], false, positions[8]-1, y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - renderer->drawString(labels[9], false, positions[9], y, SMALL_TEXT_SIZE, tsl::sectionTextColor); - - renderer->drawString(displayStrings[15], false, dataPositions[3], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power now - renderer->drawString(displayStrings[16], false, dataPositions[4], y, SMALL_TEXT_SIZE, tsl::infoTextColor); // Power avg -} - -// Optimized refresh - now does all the string formatting once per second -void BaseMenuGui::refresh() -{ - const u64 ticks = armGetSystemTick(); - // Use cached comparison - 1 billion nanoseconds - if (armTicksToNs(ticks - this->lastContextUpdate) <= 1000000000UL) [[likely]] { - return; // Early exit for most calls - } - - this->lastContextUpdate = ticks; - - // Lazy context allocation - if (!this->context) [[unlikely]] { - this->context = new SysClkContext; - } - - // === ULTRA-FAST VOLTAGE READING === - // Pre-computed domain configuration based on hardware - static const PowerDomainId domains[] = { - PcvPowerDomainId_Max77621_Cpu, // [0] CPU - PcvPowerDomainId_Max77621_Gpu, // [1] GPU - PcvPowerDomainId_Max77812_Dram, // [2] EMC/DRAM - Mariko only - PcvPowerDomainId_Max77620_Sd0, // [3] SOC - EOS only - PcvPowerDomainId_Max77620_Sd1 // [4] VDD2 - EOS only - }; - - // Voltage array for direct indexing - u32* voltages[] = {&cpuVoltageUv, &gpuVoltageUv, &emcVoltageUv, &socVoltageUv, &vddVoltageUv}; - - // Single regulator init/exit cycle - if (R_SUCCEEDED(rgltrInitialize())) [[likely]] { - if (IsMariko()) { - // Mariko with EOS: all 5 domains - for (int i = 0; i < 5; ++i) { - RgltrSession session; - if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] { - if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) { - *voltages[i] = 0; - } - rgltrCloseSession(&session); - } else { - *voltages[i] = 0; - } - } - } else { - // Erista - // Erista with EOS: CPU, GPU, SOC, VDD (no DRAM) - for (int i = 0; i < 5; ++i) { - if (i == 2) continue; // Skip DRAM domain - - RgltrSession session; - if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] { - if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) { - *voltages[i] = 0; - } - rgltrCloseSession(&session); - } else { - *voltages[i] = 0; - } - emcVoltageUv = 0; // Erista never supports DRAM - } - } - - rgltrExit(); - } else { - // Zero all voltages on regulator failure - memset(&cpuVoltageUv, 0, sizeof(u32) * 5); - } - - // === SYSCLK CONTEXT UPDATE === - const Result rc = sysclkIpcGetCurrentContext(this->context); - if (R_FAILED(rc)) [[unlikely]] { - FatalGui::openWithResultCode("sysclkIpcGetCurrentContext", rc); - return; - } - - // === FORMAT ALL DISPLAY STRINGS (once per second) === - // App ID (hex conversion) - sprintf(displayStrings[0], "%016lX", context->applicationId); - - // Profile - strcpy(displayStrings[1], sysclkFormatProfile(context->profile, true)); - - // Current frequencies - u32 hz = context->freqs[0]; // CPU - sprintf(displayStrings[2], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - hz = context->freqs[1]; // GPU - sprintf(displayStrings[3], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - hz = context->freqs[2]; // MEM - sprintf(displayStrings[4], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - // Real frequencies - hz = context->realFreqs[0]; // CPU - sprintf(displayStrings[5], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - hz = context->realFreqs[1]; // GPU - sprintf(displayStrings[6], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - hz = context->realFreqs[2]; // MEM - sprintf(displayStrings[7], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); - - // Voltages - sprintf(displayStrings[8], "%.1f mV", cpuVoltageUv / 1000.0); - sprintf(displayStrings[9], "%.1f mV", gpuVoltageUv / 1000.0); - - // Memory voltage (handle VDD case) - if (emcVoltageUv && vddVoltageUv) { - //sprintf(displayStrings[10], "%u%u mV", vddVoltageUv / 1000U, emcVoltageUv / 1000U); - //sprintf(displayStrings[10], "%u%.1f mV", vddVoltageUv / 1000U, emcVoltageUv / 1000.0f); - sprintf(displayStrings[10], "%u.%u%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U, emcVoltageUv / 1000U); - } else if (vddVoltageUv) { - //sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U); - sprintf(displayStrings[10], "%u.%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U); - } else if (emcVoltageUv) { - sprintf(displayStrings[10], "%u mV", emcVoltageUv / 1000U); - } - - // Temperatures and pre-compute colors - u32 millis = context->temps[0]; // SOC - sprintf(displayStrings[11], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); - tempColors[0] = tsl::GradientColor(millis * 0.001f); - - millis = context->temps[1]; // PCB - sprintf(displayStrings[12], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); - tempColors[1] = tsl::GradientColor(millis * 0.001f); - - millis = context->temps[2]; // Skin - sprintf(displayStrings[13], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); - tempColors[2] = tsl::GradientColor(millis * 0.001f); - - // SOC voltage (if available) - if (socVoltageUv) { - sprintf(displayStrings[14], "%u mV", socVoltageUv / 1000U); - } - - // Power - sprintf(displayStrings[15], "%d mW", context->power[0]); // Now - sprintf(displayStrings[16], "%d mW", context->power[1]); // Avg -} - -tsl::elm::Element* BaseMenuGui::baseUI() -{ - auto* list = new tsl::elm::List(); - this->listElement = list; - this->listUI(); - - return list; -} \ No newline at end of file + + } + + // Optimized refresh - now does all the string formatting once per second + void BaseMenuGui::refresh() + { + + const u64 ticks = armGetSystemTick(); + // Use cached comparison - 1 billion nanoseconds + if (armTicksToNs(ticks - this->lastContextUpdate) <= 1000000000UL) [[likely]] { + return; // Early exit for most calls + } + + this->lastContextUpdate = ticks; + + // Lazy context allocation + if (!this->context) [[unlikely]] { + this->context = new SysClkContext; + } + + // === ULTRA-FAST VOLTAGE READING === + // Pre-computed domain configuration based on hardware + static const PowerDomainId domains[] = { + PcvPowerDomainId_Max77621_Cpu, // [0] CPU + PcvPowerDomainId_Max77621_Gpu, // [1] GPU + PcvPowerDomainId_Max77812_Dram, // [2] EMC/DRAM - Mariko only + PcvPowerDomainId_Max77620_Sd0, // [3] SOC + PcvPowerDomainId_Max77620_Sd1 // [4] VDD2 + }; + + // Voltage array for direct indexing + u32* voltages[] = {&cpuVoltageUv, &gpuVoltageUv, &emcVoltageUv, &socVoltageUv, &vddVoltageUv}; + + // Single regulator init/exit cycle + if (R_SUCCEEDED(rgltrInitialize())) [[likely]] { + if (IsMariko()) { + // Mariko with EOS: all 5 domains + for (int i = 0; i < 5; ++i) { + RgltrSession session; + if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] { + if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) { + *voltages[i] = 0; + } + rgltrCloseSession(&session); + } else { + *voltages[i] = 0; + } + } + } else { + // Erista + // Erista with EOS: CPU, GPU, SOC, VDD (no DRAM) + for (int i = 0; i < 5; ++i) { + if (i == 2) continue; // Skip DRAM domain + + RgltrSession session; + if (R_SUCCEEDED(rgltrOpenSession(&session, domains[i]))) [[likely]] { + if (R_FAILED(rgltrGetVoltage(&session, voltages[i]))) { + *voltages[i] = 0; + } + rgltrCloseSession(&session); + } else { + *voltages[i] = 0; + } + emcVoltageUv = 0; // Erista never supports DRAM + } + } + + rgltrExit(); + } else { + // Zero all voltages on regulator failure + memset(&cpuVoltageUv, 0, sizeof(u32) * 5); + } + + // === SYSCLK CONTEXT UPDATE === + const Result rc = sysclkIpcGetCurrentContext(this->context); + if (R_FAILED(rc)) [[unlikely]] { + FatalGui::openWithResultCode("sysclkIpcGetCurrentContext", rc); + return; + } + + // === FORMAT ALL DISPLAY STRINGS (once per second) === + // App ID (hex conversion) + sprintf(displayStrings[0], "%016lX", context->applicationId); + + // Profile + strcpy(displayStrings[1], sysclkFormatProfile(context->profile, true)); + + // Current frequencies + u32 hz = context->freqs[0]; // CPU + + sprintf(displayStrings[2], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + hz = context->freqs[1]; // GPU + sprintf(displayStrings[3], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + hz = context->freqs[2]; // MEM + sprintf(displayStrings[4], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + // Real frequencies + hz = context->realFreqs[0]; // CPU + sprintf(displayStrings[5], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + hz = context->realFreqs[1]; // GPU + sprintf(displayStrings[6], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + hz = context->realFreqs[2]; // MEM + sprintf(displayStrings[7], "%u.%u MHz", hz / 1000000U, (hz / 100000U) % 10U); + + // Voltages + sprintf(displayStrings[8], "%.1f mV", cpuVoltageUv / 1000.0); + sprintf(displayStrings[9], "%.1f mV", gpuVoltageUv / 1000.0); + + // Memory voltage (handle VDD case) + if (emcVoltageUv && vddVoltageUv) { + //sprintf(displayStrings[10], "%u%u mV", vddVoltageUv / 1000U, emcVoltageUv / 1000U); + //sprintf(displayStrings[10], "%u%.1f mV", vddVoltageUv / 1000U, emcVoltageUv / 1000.0f); + sprintf(displayStrings[10], "%u.%u%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U, emcVoltageUv / 1000U); + } else if (vddVoltageUv) { + //sprintf(displayStrings[10], "%u mV", vddVoltageUv / 1000U); + sprintf(displayStrings[10], "%u.%u mV", vddVoltageUv / 1000U, (vddVoltageUv % 1000U) / 100U); + } else if (emcVoltageUv) { + sprintf(displayStrings[10], "%u mV", emcVoltageUv / 1000U); + } + + + u32 millis = context->temps[SysClkThermalSensor_SOC]; // SOC + sprintf(displayStrings[11], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[0] = tsl::GradientColor(millis * 0.001f); + + millis = context->temps[SysClkThermalSensor_PCB]; // PCB + sprintf(displayStrings[12], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[1] = tsl::GradientColor(millis * 0.001f); + + millis = context->temps[SysClkThermalSensor_Skin]; // Skin + sprintf(displayStrings[13], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[2] = tsl::GradientColor(millis * 0.001f); + + millis = context->temps[HocClkThermalSensor_Battery]; // + sprintf(displayStrings[20], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[3] = tsl::GradientColor(millis * 0.001f); + + millis = context->temps[HocClkThermalSensor_PMIC]; // + sprintf(displayStrings[21], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + tempColors[4] = tsl::GradientColor(millis * 0.001f); + + // millis = context->temps[HocClkThermalSensor_GPU]; // Skin + // sprintf(displayStrings[18], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + // tempColors[4] = tsl::GradientColor(millis * 0.001f); + + // millis = context->temps[HocClkThermalSensor_PLL]; // Skin + // sprintf(displayStrings[19], "%u.%u °C", millis / 1000U, (millis % 1000U) / 100U); + // tempColors[5] = tsl::GradientColor(millis * 0.001f); + + // SOC voltage (if available) + if (socVoltageUv) { + sprintf(displayStrings[14], "%u mV", socVoltageUv / 1000U); + } + + // Power + sprintf(displayStrings[15], "%d mW", context->power[0]); // Now + sprintf(displayStrings[16], "%d mW", context->power[1]); // Avg + + + } + + tsl::elm::Element* BaseMenuGui::baseUI() + { + auto* list = new tsl::elm::List(); + this->listElement = list; + this->listUI(); + + return list; + } \ No newline at end of file diff --git a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.h b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.h index 22a76c2a..3ec312fd 100644 --- a/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/base_menu_gui.h @@ -1,4 +1,15 @@ /* + * -------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * , , + * wrote this file. As long as you retain this notice you can do whatever you + * want with this stuff. If you meet any of us some day, and you think this + * stuff is worth it, you can buy us a beer in return. - The sys-clk authors + * -------------------------------------------------------------------------- + */ + +/* + * * Copyright (c) Souldbminer and Horizon OC Contributors * * This program is free software; you can redistribute it and/or modify it @@ -12,65 +23,69 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * */ + + #pragma once + + #include "../../rgltr_services.h" + #include "../../ipc.h" + #include "base_gui.h" -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ + + class BaseMenuGui : public BaseGui + { + protected: + SysClkContext* context; + std::uint64_t lastContextUpdate; + std::uint32_t cpuVoltageUv; + std::uint32_t gpuVoltageUv; + std::uint32_t emcVoltageUv; + std::uint32_t socVoltageUv; //add soc voltage + std::uint32_t vddVoltageUv;//add vdd2 voltage + + public: + uint64_t systemtickfrequency = 19200000; + bool g_hardwareModelCached = false; + bool g_isMariko = false; + bool g_isAula = false; + bool IsMariko() { + if (!g_hardwareModelCached) { + SetSysProductModel model = SetSysProductModel_Invalid; + setsysGetProductModel(&model); + g_isMariko = (model == SetSysProductModel_Iowa || + model == SetSysProductModel_Hoag || + model == SetSysProductModel_Calcio || + model == SetSysProductModel_Aula); + g_hardwareModelCached = true; + } + return g_isMariko; + } -#pragma once - -#include "../../rgltr_services.h" -#include "../../ipc.h" -#include "base_gui.h" - -class BaseMenuGui : public BaseGui -{ - protected: - SysClkContext* context; - std::uint64_t lastContextUpdate; - std::uint32_t cpuVoltageUv; - std::uint32_t gpuVoltageUv; - std::uint32_t emcVoltageUv; - std::uint32_t socVoltageUv; //add soc voltage - std::uint32_t vddVoltageUv;//add vdd2 voltage - - public: - bool g_hardwareModelCached = false; - bool g_isMariko = false; - - bool IsMariko() { + bool IsAula() { if (!g_hardwareModelCached) { SetSysProductModel model = SetSysProductModel_Invalid; setsysGetProductModel(&model); - g_isMariko = (model == SetSysProductModel_Iowa || - model == SetSysProductModel_Hoag || - model == SetSysProductModel_Calcio || - model == SetSysProductModel_Aula); - g_hardwareModelCached = true; + g_isMariko = (model == SetSysProductModel_Aula); } - return g_isMariko; + return g_isAula; } - - bool IsErista() { - return !IsMariko(); - } - BaseMenuGui(); - ~BaseMenuGui(); - void preDraw(tsl::gfx::Renderer* renderer) override; - tsl::elm::List* listElement; - tsl::elm::Element* baseUI() override; - void refresh() override; - virtual void listUI() = 0; - - private: - char displayStrings[17][32]; // Pre-formatted display strings - tsl::Color tempColors[3]; // Pre-computed temperature colors -}; + + bool IsErista() { + return !IsMariko(); + } + BaseMenuGui(); + ~BaseMenuGui(); + void preDraw(tsl::gfx::Renderer* renderer) override; + tsl::elm::List* listElement; + tsl::elm::Element* baseUI() override; + void refresh() override; + virtual void listUI() = 0; + + private: + char displayStrings[32][32]; // Pre-formatted display strings + tsl::Color tempColors[6] = { + tsl::Color(0), tsl::Color(0), tsl::Color(0), + tsl::Color(0), tsl::Color(0), tsl::Color(0) + }; + }; \ No newline at end of file diff --git a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp index 4b997b07..59e49424 100644 --- a/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/misc_gui.cpp @@ -205,14 +205,18 @@ void MiscGui::listUI() addConfigToggle(HocClkConfigValue_OverwriteBoostMode, nullptr); this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental")); + addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr); addConfigToggle(HocClkConfigValue_ThermalThrottle, nullptr); addConfigToggle(HocClkConfigValue_HandheldTDP, nullptr); - + addConfigToggle(HocClkConfigValue_EnforceBoardLimit, nullptr); + if(IsAula()) { + addConfigToggle(HocClkConfigValue_PWMDimming, "PWM Dimming"); + } ValueThresholds tdpThresholds(8600, 9500); addConfigButton( HocClkConfigValue_HandheldTDPLimit, "TDP Threshold", - ValueRange(5000, 10000, 100, "mW", 1), + ValueRange(5000, 10000, 200, "mW", 1, 0), "Power", &tdpThresholds ); @@ -221,7 +225,7 @@ void MiscGui::listUI() addConfigButton( HocClkConfigValue_LiteTDPLimit, "Lite TDP Threshold", - ValueRange(4000, 8000, 100, "mW", 1), + ValueRange(4000, 8000, 200, "mW", 1, 0), "Power", &tdpThresholdsLite ); @@ -230,11 +234,11 @@ void MiscGui::listUI() addConfigButton( HocClkConfigValue_ThermalThrottleThreshold, "Thermal Throttle Limit", - ValueRange(50, 85, 1, "°C", 1), + ValueRange(50, 85, 5, "°C", 1, 0), "Temp", &throttleThresholds ); - this->listElement->addItem(new tsl::elm::CategoryHeader("Max Clocks")); + this->listElement->addItem(new tsl::elm::CategoryHeader("Clocks")); if(IsMariko()) { addFreqButton(HocClkConfigValue_MarikoMaxCpuClock, nullptr, SysClkModule_CPU); addFreqButton(HocClkConfigValue_MarikoMaxGpuClock, nullptr, SysClkModule_GPU); @@ -244,6 +248,62 @@ void MiscGui::listUI() addFreqButton(HocClkConfigValue_EristaMaxGpuClock, nullptr, SysClkModule_GPU); addFreqButton(HocClkConfigValue_EristaMaxMemClock, nullptr, SysClkModule_MEM); } + + // addFreqButton(HocClkConfigValue_CustomBoostClock, nullptr, S); + if(IsMariko()) { + ValueThresholds BoostThresholds(1963, 2397); + addConfigButton( + HocClkConfigValue_MarikoBoostClock, + "CPU Boost Clock", + ValueRange(1785, 2805, 102, "MHz", 1, 0), + "CPU Boost Clock", + &BoostThresholds + ); + } else { + ValueThresholds BoostThresholds(1785, 2091); + addConfigButton( + HocClkConfigValue_EristaBoostClock, + "CPU Boost Clock", + ValueRange(1785, 2295, 102, "MHz", 1, 0), + "CPU Boost Clock", + &BoostThresholds + ); + } + + this->listElement->addItem(new tsl::elm::CategoryHeader("EMC and MTC")); + + addConfigToggle(HocClkConfigValue_EMCEnableUnsafeVoltages, nullptr); + + if(this->configList->values[HocClkConfigValue_EMCEnableUnsafeVoltages]) { + ValueThresholds emcUvThresholds(1212500, 1250000); + addConfigButton( + HocClkConfigValue_EMCVdd2VoltageuV, + "EMC VDD2 Voltage", + ValueRange(918500, 1350000, 12500, "µV", 1, 1), + "EMC VDD2 Voltage", + &emcUvThresholds + ); + } else { + if(IsMariko()) { + ValueThresholds emcUvThresholds(1212500, 1250000); + addConfigButton( + HocClkConfigValue_EMCVdd2VoltageuV, + "EMC VDD2 Voltage", + ValueRange(1100000, 1212500, 12500, "µV", 1, 1), + "EMC VDD2 Voltage", + &emcUvThresholds + ); + } else { + ValueThresholds emcUvThresholds(1237500, 1300000); + addConfigButton( + HocClkConfigValue_EMCVdd2VoltageuV, + "EMC VDD2 Voltage", + ValueRange(1125000, 1237500, 12500, "mV", 1000, 1), + "EMC VDD2 Voltage", + &emcUvThresholds + ); + } + } tsl::elm::ListItem* applyBtn = new tsl::elm::ListItem("Apply EMC Regs"); applyBtn->setClickListener([](u64 keys) { if (keys & HidNpadButton_A) { diff --git a/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.cpp b/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.cpp index ed5108df..0ff3d3f1 100644 --- a/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.cpp +++ b/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.cpp @@ -1,145 +1,118 @@ -/* - * Copyright (c) Souldbminer and Horizon OC Contributors - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ +#include "value_choice_gui.h" +#include "../format.h" +#include "fatal_gui.h" +#include +#include +ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue, + const ValueRange& range, + const std::string& categoryName, + ValueChoiceListener listener, + const ValueThresholds& thresholds, + bool enableThresholds) + : selectedValue(selectedValue), + range(range), + categoryName(categoryName), + listener(listener), + thresholds(thresholds), + enableThresholds(enableThresholds) +{ +} - #include "value_choice_gui.h" - #include "../format.h" - #include "fatal_gui.h" - #include - #include +ValueChoiceGui::~ValueChoiceGui() +{ +} - ValueChoiceGui::ValueChoiceGui(std::uint32_t selectedValue, - const ValueRange& range, - const std::string& categoryName, - ValueChoiceListener listener, - const ValueThresholds& thresholds, - bool enableThresholds) - : selectedValue(selectedValue), - range(range), - categoryName(categoryName), - listener(listener), - thresholds(thresholds), - enableThresholds(enableThresholds) - { - } +std::string ValueChoiceGui::formatValue(std::uint32_t value) +{ + std::ostringstream oss; - ValueChoiceGui::~ValueChoiceGui() - { - } + if (value == 0) { + return VALUE_DEFAULT_TEXT; + } - std::string ValueChoiceGui::formatValue(std::uint32_t value) - { - std::ostringstream oss; + // Convert to floating point for division + double displayValue = static_cast(value) / static_cast(range.divisor); - if (value == 0) { + // Set precision and formatting + oss << std::fixed << std::setprecision(range.decimalPlaces) << displayValue; + + if (!range.suffix.empty()) { + oss << " " << range.suffix; + } + return oss.str(); +} - return VALUE_DEFAULT_TEXT; - } +int ValueChoiceGui::getSafetyLevel(std::uint32_t value) +{ + if (!enableThresholds) { + return 0; + } - std::uint32_t displayValue = value / range.divisor; + std::uint32_t scaledValue = value / range.divisor; - oss << displayValue; - if (!range.suffix.empty()) { - oss << " " << range.suffix; - } - return oss.str(); - } + if (scaledValue > thresholds.danger) { + return 2; + } + if (scaledValue > thresholds.warning) { + return 1; + } + return 0; +} - int ValueChoiceGui::getSafetyLevel(std::uint32_t value) - { - if (!enableThresholds) { - return 0; - } +tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, bool selected, int safety) +{ + std::string text = formatValue(value); + if (selected) { + text += " \uE14B"; + } - std::uint32_t scaledValue = value / range.divisor; + tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false); - if (scaledValue > thresholds.danger) { - return 2; - } - if (scaledValue > thresholds.warning) { - return 1; - } - return 0; - } + switch (safety) + { + case 0: + listItem->setTextColor(tsl::Color(255, 255, 255, 255)); + listItem->setValueColor(tsl::Color(255, 255, 255, 255)); + break; + case 1: + listItem->setTextColor(tsl::Color(255, 165, 0, 255)); + listItem->setValueColor(tsl::Color(255, 165, 0, 255)); + break; + case 2: + listItem->setTextColor(tsl::Color(255, 0, 0, 255)); + listItem->setValueColor(tsl::Color(255, 0, 0, 255)); + break; + } - tsl::elm::ListItem* ValueChoiceGui::createValueListItem(std::uint32_t value, bool selected, int safety) - { - std::string text = formatValue(value); - if (selected) { - text += " \uE14B"; - } + listItem->setClickListener([this, value](u64 keys) + { + if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) { + if (this->listener(value)) { + tsl::goBack(); + } + return true; + } + return false; + }); - tsl::elm::ListItem* listItem = new tsl::elm::ListItem(text, "", false); + return listItem; +} - switch (safety) - { - case 0: - listItem->setTextColor(tsl::Color(255, 255, 255, 255)); - listItem->setValueColor(tsl::Color(255, 255, 255, 255)); - break; - case 1: - listItem->setTextColor(tsl::Color(255, 165, 0, 255)); - listItem->setValueColor(tsl::Color(255, 165, 0, 255)); - break; - case 2: - listItem->setTextColor(tsl::Color(255, 0, 0, 255)); - listItem->setValueColor(tsl::Color(255, 0, 0, 255)); - break; - } +void ValueChoiceGui::listUI() +{ + if (!categoryName.empty()) { + this->listElement->addItem(new tsl::elm::CategoryHeader(categoryName)); + } - listItem->setClickListener([this, value](u64 keys) - { - if ((keys & HidNpadButton_A) == HidNpadButton_A && this->listener) { + this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0)); - if (this->listener(value)) { - tsl::goBack(); - } - return true; - } - return false; - }); + for (std::uint32_t value = range.min; value <= range.max; value += range.step) + { + int safety = getSafetyLevel(value); + bool selected = (value == this->selectedValue); + this->listElement->addItem(this->createValueListItem(value, selected, safety)); + } - return listItem; - } - - void ValueChoiceGui::listUI() - { - - if (!categoryName.empty()) { - this->listElement->addItem(new tsl::elm::CategoryHeader(categoryName)); - } - - this->listElement->addItem(this->createValueListItem(0, this->selectedValue == 0, 0)); - - for (std::uint32_t value = range.min; value <= range.max; value += range.step) - { - int safety = getSafetyLevel(value); - bool selected = (value == this->selectedValue); - this->listElement->addItem(this->createValueListItem(value, selected, safety)); - } - - this->listElement->jumpToItem("", "\uE14B"); - } \ No newline at end of file + this->listElement->jumpToItem("", "\uE14B"); +} \ No newline at end of file diff --git a/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.h b/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.h index 160de655..2c9b122e 100644 --- a/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.h +++ b/Source/sys-clk/overlay/src/ui/gui/value_choice_gui.h @@ -37,20 +37,20 @@ #define VALUE_DEFAULT_TEXT "Default" struct ValueRange { - std::uint32_t min; - std::uint32_t max; - std::uint32_t step; - std::string suffix; - std::uint32_t divisor; // Divide input values by this for display - - // Default constructor - ValueRange() : min(0), max(0), step(1), suffix(""), divisor(1) {} - - ValueRange(std::uint32_t min, std::uint32_t max, std::uint32_t step, - const std::string& suffix = "", std::uint32_t divisor = 1) - : min(min), max(max), step(step), suffix(suffix), divisor(divisor) {} - }; - + std::uint32_t min; + std::uint32_t max; + std::uint32_t step; + std::string suffix; + std::uint32_t divisor; // Divide input values by this for display + int decimalPlaces; // Number of decimal places to display (0-6) + + ValueRange() : min(0), max(0), step(1), suffix(""), divisor(1), decimalPlaces(0) {} + + ValueRange(std::uint32_t min, std::uint32_t max, std::uint32_t step, + const std::string& suffix = "", std::uint32_t divisor = 1, int decimalPlaces = 0) + : min(min), max(max), step(step), suffix(suffix), divisor(divisor), decimalPlaces(decimalPlaces) {} +}; + struct ValueThresholds { std::uint32_t warning; // Values >= this show orange std::uint32_t danger; // Values >= this show red diff --git a/Source/sys-clk/sysmodule/src/board.cpp b/Source/sys-clk/sysmodule/src/board.cpp index f7b92991..2b5552c7 100644 --- a/Source/sys-clk/sysmodule/src/board.cpp +++ b/Source/sys-clk/sysmodule/src/board.cpp @@ -12,9 +12,9 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ - + /* -------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * , , @@ -24,35 +24,39 @@ * -------------------------------------------------------------------------- */ - #include +#include + #include "board.h" #include "errors.h" +#include "maxXXXXX.h" -#define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0)) -#define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0)) +#define HOSSVC_HAS_CLKRST (hosversionAtLeast(8, 0, 0)) +#define HOSSVC_HAS_TC (hosversionAtLeast(5, 0, 0)) +#define BQ24193_I2C_ADDR 0x6B +#define BQ24193_FaultReg 0x09 static SysClkSocType g_socType = SysClkSocType_Erista; -const char* Board::GetModuleName(SysClkModule module, bool pretty) +const char *Board::GetModuleName(SysClkModule module, bool pretty) { ASSERT_ENUM_VALID(SysClkModule, module); return sysclkFormatModule(module, pretty); } -const char* Board::GetProfileName(SysClkProfile profile, bool pretty) +const char *Board::GetProfileName(SysClkProfile profile, bool pretty) { ASSERT_ENUM_VALID(SysClkProfile, profile); return sysclkFormatProfile(profile, pretty); } -const char* Board::GetThermalSensorName(SysClkThermalSensor sensor, bool pretty) +const char *Board::GetThermalSensorName(SysClkThermalSensor sensor, bool pretty) { ASSERT_ENUM_VALID(SysClkThermalSensor, sensor); return sysclkFormatThermalSensor(sensor, pretty); } -const char* Board::GetPowerSensorName(SysClkPowerSensor sensor, bool pretty) +const char *Board::GetPowerSensorName(SysClkPowerSensor sensor, bool pretty) { ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); return sysclkFormatPowerSensor(sensor, pretty); @@ -60,19 +64,18 @@ const char* Board::GetPowerSensorName(SysClkPowerSensor sensor, bool pretty) PcvModule Board::GetPcvModule(SysClkModule sysclkModule) { - switch(sysclkModule) - { - case SysClkModule_CPU: - return PcvModule_CpuBus; - case SysClkModule_GPU: - return PcvModule_GPU; - case SysClkModule_MEM: - return PcvModule_EMC; - default: - ASSERT_ENUM_VALID(SysClkModule, sysclkModule); + switch (sysclkModule) { + case SysClkModule_CPU: + return PcvModule_CpuBus; + case SysClkModule_GPU: + return PcvModule_GPU; + case SysClkModule_MEM: + return PcvModule_EMC; + default: + ASSERT_ENUM_VALID(SysClkModule, sysclkModule); } - return (PcvModule)0; + return (PcvModule) 0; } PcvModuleId Board::GetPcvModuleId(SysClkModule sysclkModule) @@ -88,13 +91,10 @@ void Board::Initialize() { Result rc = 0; - if(HOSSVC_HAS_CLKRST) - { + if (HOSSVC_HAS_CLKRST) { rc = clkrstInitialize(); ASSERT_RESULT_OK(rc, "clkrstInitialize"); - } - else - { + } else { rc = pcvInitialize(); ASSERT_RESULT_OK(rc, "pcvInitialize"); } @@ -105,8 +105,7 @@ void Board::Initialize() rc = psmInitialize(); ASSERT_RESULT_OK(rc, "psmInitialize"); - if(HOSSVC_HAS_TC) - { + if (HOSSVC_HAS_TC) { rc = tcInitialize(); ASSERT_RESULT_OK(rc, "tcInitialize"); } @@ -122,20 +121,16 @@ void Board::Initialize() void Board::Exit() { - if(HOSSVC_HAS_CLKRST) - { + if (HOSSVC_HAS_CLKRST) { clkrstExit(); - } - else - { + } else { pcvExit(); } apmExtExit(); psmExit(); - if(HOSSVC_HAS_TC) - { + if (HOSSVC_HAS_TC) { tcExit(); } @@ -149,8 +144,7 @@ SysClkProfile Board::GetProfile() Result rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); - if(mode) - { + if (mode) { return SysClkProfile_Docked; } @@ -159,12 +153,9 @@ SysClkProfile Board::GetProfile() rc = psmGetChargerType(&chargerType); ASSERT_RESULT_OK(rc, "psmGetChargerType"); - if(chargerType == PsmChargerType_EnoughPower) - { + if (chargerType == PsmChargerType_EnoughPower) { return SysClkProfile_HandheldChargingOfficial; - } - else if(chargerType == PsmChargerType_LowPower) - { + } else if (chargerType == PsmChargerType_LowPower) { return SysClkProfile_HandheldChargingUSB; } @@ -175,9 +166,8 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz) { Result rc = 0; - if(HOSSVC_HAS_CLKRST) - { - ClkrstSession session = {0}; + if (HOSSVC_HAS_CLKRST) { + ClkrstSession session = { 0 }; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); @@ -186,9 +176,7 @@ void Board::SetHz(SysClkModule module, std::uint32_t hz) ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); clkrstCloseSession(&session); - } - else - { + } else { rc = pcvSetClockRate(Board::GetPcvModule(module), hz); ASSERT_RESULT_OK(rc, "pcvSetClockRate"); } @@ -199,9 +187,8 @@ std::uint32_t Board::GetHz(SysClkModule module) Result rc = 0; std::uint32_t hz = 0; - if(HOSSVC_HAS_CLKRST) - { - ClkrstSession session = {0}; + if (HOSSVC_HAS_CLKRST) { + ClkrstSession session = { 0 }; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); @@ -210,9 +197,7 @@ std::uint32_t Board::GetHz(SysClkModule module) ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); clkrstCloseSession(&session); - } - else - { + } else { rc = pcvGetClockRate(Board::GetPcvModule(module), &hz); ASSERT_RESULT_OK(rc, "pcvGetClockRate"); } @@ -222,49 +207,48 @@ std::uint32_t Board::GetHz(SysClkModule module) std::uint32_t Board::GetRealHz(SysClkModule module) { - switch(module) - { - case SysClkModule_CPU: - return t210ClkCpuFreq(); - case SysClkModule_GPU: - return t210ClkGpuFreq(); - case SysClkModule_MEM: - return t210ClkMemFreq(); - default: - ASSERT_ENUM_VALID(SysClkModule, module); + switch (module) { + case SysClkModule_CPU: + return t210ClkCpuFreq(); + case SysClkModule_GPU: + return t210ClkGpuFreq(); + case SysClkModule_MEM: + return t210ClkMemFreq(); + default: + ASSERT_ENUM_VALID(SysClkModule, module); } return 0; } -void Board::GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32_t maxCount, std::uint32_t* outCount) +void Board::GetFreqList(SysClkModule module, std::uint32_t *outList, +std::uint32_t maxCount, std::uint32_t *outCount) { Result rc = 0; PcvClockRatesListType type; s32 tmpInMaxCount = maxCount; s32 tmpOutCount = 0; - if(HOSSVC_HAS_CLKRST) - { - ClkrstSession session = {0}; + if (HOSSVC_HAS_CLKRST) { + ClkrstSession session = { 0 }; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); - rc = clkrstGetPossibleClockRates(&session, outList, tmpInMaxCount, &type, &tmpOutCount); + rc = clkrstGetPossibleClockRates( + &session, outList, tmpInMaxCount, &type, &tmpOutCount); ASSERT_RESULT_OK(rc, "clkrstGetPossibleClockRates"); clkrstCloseSession(&session); - } - else - { - rc = pcvGetPossibleClockRates(Board::GetPcvModule(module), outList, tmpInMaxCount, &type, &tmpOutCount); + } else { + rc = pcvGetPossibleClockRates(Board::GetPcvModule(module), outList, + tmpInMaxCount, &type, &tmpOutCount); ASSERT_RESULT_OK(rc, "pcvGetPossibleClockRates"); } - if(type != PcvClockRatesListType_Discrete) - { - ERROR_THROW("Unexpected PcvClockRatesListType: %u (module = %s)", type, Board::GetModuleName(module, false)); + if (type != PcvClockRatesListType_Discrete) { + ERROR_THROW("Unexpected PcvClockRatesListType: %u (module = %s)", type, + Board::GetModuleName(module, false)); } *outCount = tmpOutCount; @@ -273,33 +257,27 @@ void Board::GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32 void Board::ResetToStock() { Result rc = 0; - if(hosversionAtLeast(9,0,0)) - { + if (hosversionAtLeast(9, 0, 0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); - SysClkApmConfiguration* apmConfiguration = NULL; - for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) - { - if(sysclk_g_apm_configurations[i].id == confId) - { + SysClkApmConfiguration *apmConfiguration = NULL; + for (size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { + if (sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } - if(!apmConfiguration) - { + if (!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz); Board::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz); Board::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz); - } - else - { + } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); @@ -312,31 +290,25 @@ void Board::ResetToStock() void Board::ResetToStockCpu() { Result rc = 0; - if(hosversionAtLeast(9,0,0)) - { + if (hosversionAtLeast(9, 0, 0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); - SysClkApmConfiguration* apmConfiguration = NULL; - for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) - { - if(sysclk_g_apm_configurations[i].id == confId) - { + SysClkApmConfiguration *apmConfiguration = NULL; + for (size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { + if (sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } - if(!apmConfiguration) - { + if (!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz); - } - else - { + } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); @@ -349,31 +321,25 @@ void Board::ResetToStockCpu() void Board::ResetToStockMem() { Result rc = 0; - if(hosversionAtLeast(9,0,0)) - { + if (hosversionAtLeast(9, 0, 0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); - SysClkApmConfiguration* apmConfiguration = NULL; - for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) - { - if(sysclk_g_apm_configurations[i].id == confId) - { + SysClkApmConfiguration *apmConfiguration = NULL; + for (size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { + if (sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } - if(!apmConfiguration) - { + if (!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz); - } - else - { + } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); @@ -386,31 +352,25 @@ void Board::ResetToStockMem() void Board::ResetToStockGpu() { Result rc = 0; - if(hosversionAtLeast(9,0,0)) - { + if (hosversionAtLeast(9, 0, 0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); - SysClkApmConfiguration* apmConfiguration = NULL; - for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) - { - if(sysclk_g_apm_configurations[i].id == confId) - { + SysClkApmConfiguration *apmConfiguration = NULL; + for (size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { + if (sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } - if(!apmConfiguration) - { + if (!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz); - } - else - { + } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); @@ -419,29 +379,56 @@ void Board::ResetToStockGpu() ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } + std::uint32_t Board::GetTemperatureMilli(SysClkThermalSensor sensor) { std::int32_t millis = 0; + Result res; + u16 data; + u8 reg = MAX17050_TEMP; - if(sensor == SysClkThermalSensor_SOC) - { + switch (sensor) { + case SysClkThermalSensor_SOC: millis = tmp451TempSoc(); - } - else if(sensor == SysClkThermalSensor_PCB) - { + break; + case SysClkThermalSensor_PCB: millis = tmp451TempPcb(); - } - else if(sensor == SysClkThermalSensor_Skin) - { - if(HOSSVC_HAS_TC) - { + break; + case SysClkThermalSensor_Skin: + + if (HOSSVC_HAS_TC) { Result rc; rc = tcGetSkinTemperatureMilliC(&millis); ASSERT_RESULT_OK(rc, "tcGetSkinTemperatureMilliC"); } - } - else - { + break; + case HocClkThermalSensor_Battery: + I2cSession session; + res = i2cOpenSession(&session, I2cDevice_Max17050); + if (R_FAILED(res)) { + millis = -1; + break; + } + + data = 0; + + res = i2csessionSendAuto(&session, ®, 1, I2cTransactionOption_Start); + if (R_FAILED(res)) { + i2csessionClose(&session); + millis = -1; + break; + } + + res = i2csessionReceiveAuto(&session, (u8 *) &data, 2, I2cTransactionOption_Stop); + + i2csessionClose(&session); + + millis = (std::int32_t) data * 10 / 256; + break; + case HocClkThermalSensor_PMIC: + millis = 50000; // Literally the only reasonable value the PMIC can return + break; + default: ASSERT_ENUM_VALID(SysClkThermalSensor, sensor); } @@ -450,14 +437,13 @@ std::uint32_t Board::GetTemperatureMilli(SysClkThermalSensor sensor) std::int32_t Board::GetPowerMw(SysClkPowerSensor sensor) { - switch(sensor) - { - case SysClkPowerSensor_Now: - return max17050PowerNow(); - case SysClkPowerSensor_Avg: - return max17050PowerAvg(); - default: - ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); + switch (sensor) { + case SysClkPowerSensor_Now: + return max17050PowerNow(); + case SysClkPowerSensor_Avg: + return max17050PowerAvg(); + default: + ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); } return 0; @@ -465,24 +451,23 @@ std::int32_t Board::GetPowerMw(SysClkPowerSensor sensor) std::uint32_t Board::GetRamLoad(SysClkRamLoad loadSource) { - switch(loadSource) - { - case SysClkRamLoad_All: - return t210EmcLoadAll(); - case SysClkRamLoad_Cpu: - return t210EmcLoadCpu(); - default: - ASSERT_ENUM_VALID(SysClkRamLoad, loadSource); + switch (loadSource) { + case SysClkRamLoad_All: + return t210EmcLoadAll(); + case SysClkRamLoad_Cpu: + return t210EmcLoadCpu(); + default: + ASSERT_ENUM_VALID(SysClkRamLoad, loadSource); } return 0; } -SysClkSocType Board::GetSocType() { +SysClkSocType Board::GetSocType() +{ return g_socType; } - void Board::FetchHardwareInfos() { u64 sku = 0; @@ -494,17 +479,16 @@ void Board::FetchHardwareInfos() splExit(); - switch(sku) - { - case 2: - case 3: - case 5: - g_socType = SysClkSocType_Mariko; - break; - case 4: - g_socType = SysClkSocType_MarikoLite; - break; - default: - g_socType = SysClkSocType_Erista; + switch (sku) { + case 2: + case 3: + case 5: + g_socType = SysClkSocType_Mariko; + break; + case 4: + g_socType = SysClkSocType_MarikoLite; + break; + default: + g_socType = SysClkSocType_Erista; } } \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/board.h b/Source/sys-clk/sysmodule/src/board.h index 21b9c227..3162c371 100644 --- a/Source/sys-clk/sysmodule/src/board.h +++ b/Source/sys-clk/sysmodule/src/board.h @@ -33,6 +33,7 @@ class Board { public: + u16 max17050_get_reg(u8 reg); static const char* GetProfileName(SysClkProfile profile, bool pretty); static const char* GetModuleName(SysClkModule module, bool pretty); static const char* GetThermalSensorName(SysClkThermalSensor sensor, bool pretty); diff --git a/Source/sys-clk/sysmodule/src/clock_manager.cpp b/Source/sys-clk/sysmodule/src/clock_manager.cpp index b82dd89d..5cf68469 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.cpp +++ b/Source/sys-clk/sysmodule/src/clock_manager.cpp @@ -12,9 +12,9 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * + * */ - + /* -------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * , , @@ -32,6 +32,7 @@ #include "process_management.h" #include "errors.h" #include "ipc_service.h" +#include "emc_patcher.h" #define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0)) @@ -235,27 +236,41 @@ void ClockManager::Tick() std::uint32_t maxHz = 0; std::uint32_t nearestHz = 0; std::uint32_t mode = 0; - - AppletOperationMode opMode = appletGetOperationMode(); + + #define EMC_MAX_VOLTAGE_SAFETY_CHECK 1400000 + + if(this->config->GetConfigValue(HocClkConfigValue_EMCVdd2VoltageuV) < EMC_MAX_VOLTAGE_SAFETY_CHECK) { + EMCpatcher::set_sd1_voltage((u32)this->config->GetConfigValue(HocClkConfigValue_EMCVdd2VoltageuV)); + } else { + ResetToStockClocks(); // Clean up after boost mode + } + + + AppletOperationMode opMode = appletGetOperationMode(); // Used to get if docked or handheld Result rc = apmExtGetCurrentPerformanceConfiguration(&mode); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) { if(Board::GetSocType() == SysClkSocType_MarikoLite) { - if(Board::GetPowerMw(SysClkPowerSensor_Now) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) { + if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) { ResetToStockClocks(); return; } } else { - if(Board::GetPowerMw(SysClkPowerSensor_Now) < -(int)this->config->GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) { + if(Board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)this->config->GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) { ResetToStockClocks(); return; } } } - if(apmExtIsBoostMode(mode) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) { - ResetToStockClocks(); + if(apmExtIsBoostMode(mode) && !this->config->GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) { // Stock boost mode + // ResetToStockClocks(); + if(Board::GetSocType() == SysClkSocType_MarikoLite || Board::GetSocType() == SysClkSocType_Mariko) { + Board::SetHz((SysClkModule)SysClkModule_CPU, (u32)this->config->GetConfigValue(HocClkConfigValue_MarikoBoostClock) * 1000000); + } else { + Board::SetHz((SysClkModule)SysClkModule_CPU, (u32)this->config->GetConfigValue(HocClkConfigValue_EristaBoostClock) * 1000000); + } return; } @@ -442,4 +457,52 @@ bool ClockManager::RefreshContext() void ClockManager::SetRNXRTMode(ReverseNXMode mode) { this->rnxSync->SetRTMode(mode); -} \ No newline at end of file +} + +// void ClockManager::set_sd1_voltage(uint32_t voltage_uv) +// { +// // SD1 parameters +// const u32 uv_step = 12500; +// const u32 uv_min = 600000; +// const u32 uv_max = 1237500; +// const u8 volt_addr = 0x17; // MAX77620_REG_SD1 +// const u8 volt_mask = 0x7F; // MAX77620_SD1_VOLT_MASK + +// // Validate input voltage +// if (voltage_uv < uv_min || voltage_uv > uv_max) +// return; + +// // Calculate voltage multiplier +// u32 mult = (voltage_uv + uv_step - 1 - uv_min) / uv_step; +// mult = mult & volt_mask; + +// // Open I2C session to MAX77620 PMIC +// I2cSession session; +// Result res = i2cOpenSession(&session, I2cDevice_Max77620Pmic); +// if (R_FAILED(res)) { +// return; +// } + +// // Read current register value +// u8 current_val = 0; +// res = i2csessionSendAuto(&session, &volt_addr, 1, I2cTransactionOption_Start); +// if (R_FAILED(res)) { +// i2csessionClose(&session); +// return; +// } + +// res = i2csessionReceiveAuto(&session, ¤t_val, 1, I2cTransactionOption_Stop); +// if (R_FAILED(res)) { +// i2csessionClose(&session); +// return; +// } + +// // Mask in the new voltage bits, preserving other bits +// u8 new_val = (current_val & ~volt_mask) | mult; + +// // Write back register with START and STOP conditions +// u8 write_buf[2] = {volt_addr, new_val}; +// res = i2csessionSendAuto(&session, write_buf, sizeof(write_buf), I2cTransactionOption_All); + +// i2csessionClose(&session); +// } \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/clock_manager.h b/Source/sys-clk/sysmodule/src/clock_manager.h index c29681d8..543c9ea5 100644 --- a/Source/sys-clk/sysmodule/src/clock_manager.h +++ b/Source/sys-clk/sysmodule/src/clock_manager.h @@ -62,7 +62,7 @@ class ClockManager std::uint32_t count; std::uint32_t list[SYSCLK_FREQ_LIST_MAX]; } freqTable[SysClkModule_EnumMax]; - + // void set_sd1_voltage(uint32_t uv); protected: bool IsAssignableHz(SysClkModule module, std::uint32_t hz); std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile); diff --git a/Source/sys-clk/sysmodule/src/emc.cpp b/Source/sys-clk/sysmodule/src/emc.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/Source/sys-clk/sysmodule/src/emc.h b/Source/sys-clk/sysmodule/src/emc.h deleted file mode 100644 index e69de29b..00000000 diff --git a/Source/sys-clk/sysmodule/src/emc_patcher.cpp b/Source/sys-clk/sysmodule/src/emc_patcher.cpp index 6b5c7135..738d62dd 100644 --- a/Source/sys-clk/sysmodule/src/emc_patcher.cpp +++ b/Source/sys-clk/sysmodule/src/emc_patcher.cpp @@ -1,7 +1,26 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include #include "emc_patcher.h" #include "file_utils.h" #include "board.h" - +#include "i2c.h" +#include "maxXXXXX.h" #define MC_BASE 0x70019000 #define EMC_BASE 0x7001B000 @@ -60,18 +79,19 @@ void EMCpatcher::Run() { std::scoped_lock lock{this->patcherMutex}; this->config->Refresh(); - this->ApplyEMCPatch(); + // this->ApplyEMCPatch(); + this->I2CApplyVoltage(); } void EMCpatcher::ApplyEMCPatch() { if(HOSSVC_HAS_MM) { // only for 10.0.0+, older versions need rewrites - u64 mc_virt_addr = 0; - u64 mc_out_size = 0; - u64 emc_virt_addr = 0; - u64 emc_out_size = 0; - Result rc; + // u64 mc_virt_addr = 0; + // u64 mc_out_size = 0; + // u64 emc_virt_addr = 0; + // u64 emc_out_size = 0; + // Result rc; // rc = svcQueryMemoryMapping(&mc_virt_addr, &mc_out_size, MC_BASE, MC_EMC_BASE_SIZE); // map mc // ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping"); @@ -79,9 +99,9 @@ void EMCpatcher::ApplyEMCPatch() // rc = svcQueryMemoryMapping(&emc_virt_addr, &emc_out_size, EMC_BASE, MC_EMC_BASE_SIZE); // map emc // ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping"); - write_reg64(EMC_BASE, EMC_RAS_0, 1); + // write_reg64(EMC_BASE, EMC_RAS_0, 1); - write_reg64(EMC_BASE, EMC_TIMING_CONTROL_0, 0x1); // apply shadow regs + // write_reg64(EMC_BASE, EMC_TIMING_CONTROL_0, 0x1); // apply shadow regs // svcUnmapMemory((void *)mc_virt_addr, (void *)MC_BASE, MC_EMC_BASE_SIZE); // clean up @@ -89,3 +109,68 @@ void EMCpatcher::ApplyEMCPatch() } } + +#define EMC_MAX_VOLTAGE_SAFETY_CHECK 1350000 +#define SD3_UV_MIN 600000 +#define SD3_UV_STEP 12500 +#define I2C_DEVICE(bus, addr) ((I2cDevice)(((bus) << 8) | (addr))) + +#define I2C_5 5 +#define MAX77620_I2C_ADDR 0x3C + +#define I2cDevice_MAX77620 I2C_DEVICE(I2C_5, MAX77620_I2C_ADDR) + +void EMCpatcher::I2CApplyVoltage() +{ + if(this->config->GetConfigValue(HocClkConfigValue_EMCVdd2VoltageuV) < EMC_MAX_VOLTAGE_SAFETY_CHECK) { + set_sd1_voltage((u32)this->config->GetConfigValue(HocClkConfigValue_EMCVdd2VoltageuV)); + } +} + +void EMCpatcher::set_sd1_voltage(uint32_t voltage_uv) +{ + // SD1 parameters + const u32 uv_step = 12500; + const u32 uv_min = 600000; + const u32 uv_max = 1237500; + const u8 volt_addr = 0x17; // MAX77620_REG_SD1 + const u8 volt_mask = 0x7F; // MAX77620_SD1_VOLT_MASK + + // Validate input voltage + if (voltage_uv < uv_min || voltage_uv > uv_max) + return; + + // Calculate voltage multiplier + u32 mult = (voltage_uv + uv_step - 1 - uv_min) / uv_step; + mult = mult & volt_mask; + + // Open I2C session to MAX77620 PMIC + I2cSession session; + Result res = i2cOpenSession(&session, I2cDevice_Max77620Pmic); + if (R_FAILED(res)) { + return; + } + + // Read current register value + u8 current_val = 0; + res = i2csessionSendAuto(&session, &volt_addr, 1, I2cTransactionOption_Start); + if (R_FAILED(res)) { + i2csessionClose(&session); + return; + } + + res = i2csessionReceiveAuto(&session, ¤t_val, 1, I2cTransactionOption_Stop); + if (R_FAILED(res)) { + i2csessionClose(&session); + return; + } + + // Mask in the new voltage bits, preserving other bits + u8 new_val = (current_val & ~volt_mask) | mult; + + // Write back register with START and STOP conditions + u8 write_buf[2] = {volt_addr, new_val}; + res = i2csessionSendAuto(&session, write_buf, sizeof(write_buf), I2cTransactionOption_All); + + i2csessionClose(&session); +} \ No newline at end of file diff --git a/Source/sys-clk/sysmodule/src/emc_patcher.h b/Source/sys-clk/sysmodule/src/emc_patcher.h index 6c288333..ef1e026c 100644 --- a/Source/sys-clk/sysmodule/src/emc_patcher.h +++ b/Source/sys-clk/sysmodule/src/emc_patcher.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #pragma once #include @@ -67,4 +84,6 @@ public: void Run(); void ApplyEMCPatch(); + void I2CApplyVoltage(); + static void set_sd1_voltage(uint32_t uv); }; diff --git a/Source/sys-clk/sysmodule/src/fancontrol.c b/Source/sys-clk/sysmodule/src/fancontrol.c index 11e1be1d..98d59bdd 100644 --- a/Source/sys-clk/sysmodule/src/fancontrol.c +++ b/Source/sys-clk/sysmodule/src/fancontrol.c @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #include "fancontrol.h" #include "tmp451.h" diff --git a/Source/sys-clk/sysmodule/src/fancontrol.h b/Source/sys-clk/sysmodule/src/fancontrol.h index d7d16030..d9fd471f 100644 --- a/Source/sys-clk/sysmodule/src/fancontrol.h +++ b/Source/sys-clk/sysmodule/src/fancontrol.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #pragma once #ifdef __cplusplus diff --git a/Source/sys-clk/sysmodule/src/i2c.h b/Source/sys-clk/sysmodule/src/i2c.h index 653e7e1e..047cd14d 100644 --- a/Source/sys-clk/sysmodule/src/i2c.h +++ b/Source/sys-clk/sysmodule/src/i2c.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #ifndef I2C_H #define I2C_H diff --git a/Source/sys-clk/sysmodule/src/integrations.cpp b/Source/sys-clk/sysmodule/src/integrations.cpp index 7ac0b04e..d6f91e7a 100644 --- a/Source/sys-clk/sysmodule/src/integrations.cpp +++ b/Source/sys-clk/sysmodule/src/integrations.cpp @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #include "integrations.h" ReverseNXSync::ReverseNXSync() diff --git a/Source/sys-clk/sysmodule/src/integrations.h b/Source/sys-clk/sysmodule/src/integrations.h index 19678641..893f925d 100644 --- a/Source/sys-clk/sysmodule/src/integrations.h +++ b/Source/sys-clk/sysmodule/src/integrations.h @@ -1,3 +1,20 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #pragma once #include #include diff --git a/Source/sys-clk/sysmodule/src/ipc_service.cpp b/Source/sys-clk/sysmodule/src/ipc_service.cpp index 3d3dfcb7..9e936792 100644 --- a/Source/sys-clk/sysmodule/src/ipc_service.cpp +++ b/Source/sys-clk/sysmodule/src/ipc_service.cpp @@ -191,7 +191,7 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8* return ipcSrv->SetReverseNXRTMode(mode); } break; - case HocClkIpcCmd_UpdateEMCRegs: // Trigger, not data + case HocClkIpcCmd_UpdateEMC: // Trigger, not data return ipcSrv->PatchEmcRegs(); break; } @@ -354,6 +354,6 @@ Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) { Result IpcService::PatchEmcRegs() { - EMCpatcher::GetInstance()->Run(); +// EMCpatcher::GetInstance()->Run(); return 0; } diff --git a/Source/sys-clk/sysmodule/src/main.cpp b/Source/sys-clk/sysmodule/src/main.cpp index 5c10a49f..9820cdfb 100644 --- a/Source/sys-clk/sysmodule/src/main.cpp +++ b/Source/sys-clk/sysmodule/src/main.cpp @@ -38,6 +38,9 @@ #include "clock_manager.h" #include "ipc_service.h" #include "fancontrol.h" +#include "emc_patcher.h" +#include "pwm_dimming.h" + #define INNER_HEAP_SIZE 0x30000 extern "C" @@ -113,17 +116,25 @@ int main(int argc, char** argv) { Board::Initialize(); ProcessManagement::Initialize(); - + PWMDimmer::Initialize(); ProcessManagement::WaitForQLaunch(); ClockManager* clockMgr = new ClockManager(); IpcService* ipcSrv = new IpcService(clockMgr); + EMCpatcher* emcPatcher = new EMCpatcher(); + PWMDimmer* pwmDimmer = PWMDimmer::GetInstance(); FileUtils::LogLine("Ready"); clockMgr->SetRunning(true); clockMgr->GetConfig()->SetEnabled(true); ipcSrv->SetRunning(true); + pwmDimmer->Initialize(); + + emcPatcher->GetConfig()->SetEnabled(true); + emcPatcher->Run(); + pwmDimmer->Start(); + TemperaturePoint *table; ReadConfigFile(&table); InitFanController(table); diff --git a/Source/sys-clk/sysmodule/src/maxXXXXX.h b/Source/sys-clk/sysmodule/src/maxXXXXX.h new file mode 100644 index 00000000..2da06670 --- /dev/null +++ b/Source/sys-clk/sysmodule/src/maxXXXXX.h @@ -0,0 +1,691 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +/* + * Defining registers address and its bit definitions of MAX77620 and MAX20024 + * + * Copyright (c) 2019-2020 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, + * version 2, as published by the Free Software Foundation. + */ + +#include + +#ifndef MAX77XXX_H +#define MAX77XXX_H + + +#define MAX17050_BOARD_CGAIN 2 /* Actual: 1.99993 */ +#define MAX17050_BOARD_SNS_RESISTOR_UOHM 5000 /* 0.005 Ohm */ + +#define MAX17050_STATUS_BattAbsent BIT(3) + +/* Consider RepCap which is less then 10 units below FullCAP full */ +#define MAX17050_FULL_THRESHOLD 10 + +#define MAX17050_CHARACTERIZATION_DATA_SIZE 48 + +#define MAXIM17050_I2C_ADDR 0x36 + +enum MAX17050_reg { + MAX17050_STATUS = 0x00, + MAX17050_VALRT_Th = 0x01, + MAX17050_TALRT_Th = 0x02, + MAX17050_SALRT_Th = 0x03, + MAX17050_AtRate = 0x04, + MAX17050_RepCap = 0x05, + MAX17050_RepSOC = 0x06, + MAX17050_Age = 0x07, + MAX17050_TEMP = 0x08, + MAX17050_VCELL = 0x09, + MAX17050_Current = 0x0A, + MAX17050_AvgCurrent = 0x0B, + + MAX17050_SOC = 0x0D, + MAX17050_AvSOC = 0x0E, + MAX17050_RemCap = 0x0F, + MAX17050_FullCAP = 0x10, + MAX17050_TTE = 0x11, + MAX17050_QRTbl00 = 0x12, + MAX17050_FullSOCThr = 0x13, + MAX17050_RSLOW = 0x14, + + MAX17050_AvgTA = 0x16, + MAX17050_Cycles = 0x17, + MAX17050_DesignCap = 0x18, + MAX17050_AvgVCELL = 0x19, + MAX17050_MinMaxTemp = 0x1A, + MAX17050_MinMaxVolt = 0x1B, + MAX17050_MinMaxCurr = 0x1C, + MAX17050_CONFIG = 0x1D, + MAX17050_ICHGTerm = 0x1E, + MAX17050_AvCap = 0x1F, + MAX17050_ManName = 0x20, + MAX17050_DevName = 0x21, + MAX17050_QRTbl10 = 0x22, + MAX17050_FullCAPNom = 0x23, + MAX17050_TempNom = 0x24, + MAX17050_TempLim = 0x25, + MAX17050_TempHot = 0x26, + MAX17050_AIN = 0x27, + MAX17050_LearnCFG = 0x28, + MAX17050_FilterCFG = 0x29, + MAX17050_RelaxCFG = 0x2A, + MAX17050_MiscCFG = 0x2B, + MAX17050_TGAIN = 0x2C, + MAX17050_TOFF = 0x2D, + MAX17050_CGAIN = 0x2E, + MAX17050_COFF = 0x2F, + + MAX17050_QRTbl20 = 0x32, + MAX17050_SOC_empty = 0x33, + MAX17050_T_empty = 0x34, + MAX17050_FullCAP0 = 0x35, + MAX17050_LAvg_empty = 0x36, + MAX17050_FCTC = 0x37, + MAX17050_RCOMP0 = 0x38, + MAX17050_TempCo = 0x39, + MAX17050_V_empty = 0x3A, + MAX17050_K_empty0 = 0x3B, + MAX17050_TaskPeriod = 0x3C, + MAX17050_FSTAT = 0x3D, + MAX17050_TIMER = 0x3E, + MAX17050_SHDNTIMER = 0x3F, + + MAX17050_QRTbl30 = 0x42, + + MAX17050_dQacc = 0x45, + MAX17050_dPacc = 0x46, + + MAX17050_VFSOC0 = 0x48, + + Max17050_QH0 = 0x4C, + MAX17050_QH = 0x4D, + MAX17050_QL = 0x4E, + + MAX17050_MinVolt = 0x50, // Custom ID. Not to be sent to i2c. + MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. + + MAX17050_VFSOC0Enable = 0x60, + MAX17050_MODELEnable1 = 0x62, + MAX17050_MODELEnable2 = 0x63, + + MAX17050_MODELChrTbl = 0x80, + + MAX17050_OCV = 0xEE, + + MAX17050_OCVInternal = 0xFB, + + MAX17050_VFSOC = 0xFF, +}; + +#define MAX77620_I2C_ADDR 0x3C + +/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ +#define MAX77620_REG_CNFGGLBL1 0x00 +#define MAX77620_CNFGGLBL1_LBRSTEN BIT(0) +#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E +#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_MPPLD BIT(6) +#define MAX77620_CNFGGLBL1_LBDAC_EN BIT(7) + +#define MAX77620_REG_CNFGGLBL2 0x01 +#define MAX77620_TWD_MASK 0x3 +#define MAX77620_TWD_2s 0x0 +#define MAX77620_TWD_16s 0x1 +#define MAX77620_TWD_64s 0x2 +#define MAX77620_TWD_128s 0x3 +#define MAX77620_WDTEN BIT(2) +#define MAX77620_WDTSLPC BIT(3) +#define MAX77620_WDTOFFC BIT(4) +#define MAX77620_GLBL_LPM BIT(5) +#define MAX77620_I2CTWD_MASK 0xC0 +#define MAX77620_I2CTWD_DISABLED 0x00 +#define MAX77620_I2CTWD_1_33ms 0x40 +#define MAX77620_I2CTWD_35_7ms 0x80 +#define MAX77620_I2CTWD_41_7ms 0xC0 + +#define MAX77620_REG_CNFGGLBL3 0x02 +#define MAX77620_WDTC_MASK 0x3 + +#define MAX77620_REG_CNFG1_32K 0x03 +#define MAX77620_CNFG1_PWR_MD_32K_MASK 0x3 +#define MAX77620_CNFG1_32K_OUT0_EN BIT(2) +#define MAX77620_CNFG1_32KLOAD_MASK 0x30 +#define MAX77620_CNFG1_32K_OK BIT(7) + +#define MAX77620_REG_CNFGBBC 0x04 +#define MAX77620_CNFGBBC_ENABLE BIT(0) +#define MAX77620_CNFGBBC_CURRENT_MASK 0x06 +#define MAX77620_CNFGBBC_CURRENT_SHIFT 1 +#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 +#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 +#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE BIT(5) +#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 +#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 +#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) +#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) + +#define MAX77620_REG_IRQTOP 0x05 +#define MAX77620_REG_IRQTOPM 0x0D +#define MAX77620_IRQ_TOP_ONOFF_MASK BIT(1) +#define MAX77620_IRQ_TOP_32K_MASK BIT(2) +#define MAX77620_IRQ_TOP_RTC_MASK BIT(3) +#define MAX77620_IRQ_TOP_GPIO_MASK BIT(4) +#define MAX77620_IRQ_TOP_LDO_MASK BIT(5) +#define MAX77620_IRQ_TOP_SD_MASK BIT(6) +#define MAX77620_IRQ_TOP_GLBL_MASK BIT(7) + +#define MAX77620_REG_INTLBT 0x06 +#define MAX77620_REG_INTENLBT 0x0E +#define MAX77620_IRQ_GLBLM_MASK BIT(0) +#define MAX77620_IRQ_TJALRM2_MASK BIT(1) +#define MAX77620_IRQ_TJALRM1_MASK BIT(2) +#define MAX77620_IRQ_LBM_MASK BIT(3) + +#define MAX77620_REG_IRQSD 0x07 +#define MAX77620_REG_IRQMASKSD 0x0F +#define MAX77620_IRQSD_PFI_SD3 BIT(4) +#define MAX77620_IRQSD_PFI_SD2 BIT(5) +#define MAX77620_IRQSD_PFI_SD1 BIT(6) +#define MAX77620_IRQSD_PFI_SD0 BIT(7) + +#define MAX77620_REG_IRQ_LVL2_L0_7 0x08 // LDO number that irq occurred. +#define MAX77620_REG_IRQ_MSK_L0_7 0x10 +#define MAX77620_REG_IRQ_LVL2_L8 \ + 0x09 // LDO number that irq occurred. Only bit0: LDO8 is valid. +#define MAX77620_REG_IRQ_MSK_L8 0x11 +#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A // Edge detection interrupt. + +#define MAX77620_REG_ONOFFIRQ 0x0B +#define MAX77620_REG_ONOFFIRQM 0x12 +#define MAX77620_ONOFFIRQ_MRWRN BIT(0) +#define MAX77620_ONOFFIRQ_EN0_1SEC BIT(1) +#define MAX77620_ONOFFIRQ_EN0_F BIT(2) +#define MAX77620_ONOFFIRQ_EN0_R BIT(3) +#define MAX77620_ONOFFIRQ_LID_F BIT(4) +#define MAX77620_ONOFFIRQ_LID_R BIT(5) +#define MAX77620_ONOFFIRQ_ACOK_F BIT(6) +#define MAX77620_ONOFFIRQ_ACOK_R BIT(7) + +#define MAX77620_REG_NVERC 0x0C // Shutdown reason (non-volatile). +#define MAX77620_NVERC_SHDN BIT(0) +#define MAX77620_NVERC_WTCHDG BIT(1) +#define MAX77620_NVERC_HDRST BIT(2) +#define MAX77620_NVERC_TOVLD BIT(3) +#define MAX77620_NVERC_MBLSD BIT(4) +#define MAX77620_NVERC_MBO BIT(5) +#define MAX77620_NVERC_MBU BIT(6) +#define MAX77620_NVERC_RSTIN BIT(7) + +#define MAX77620_REG_STATLBT 0x13 +#define MAX77620_REG_STATSD 0x14 + +#define MAX77620_REG_ONOFFSTAT 0x15 +#define MAX77620_ONOFFSTAT_LID BIT(0) +#define MAX77620_ONOFFSTAT_ACOK BIT(1) +#define MAX77620_ONOFFSTAT_EN0 BIT(2) + +/* SD and LDO Registers */ +#define MAX77620_REG_SD0 0x16 +#define MAX77620_REG_SD1 0x17 +#define MAX77620_REG_SD2 0x18 +#define MAX77620_REG_SD3 0x19 +#define MAX77620_REG_SD4 0x1A +#define MAX77620_REG_DVSSD0 0x1B +#define MAX77620_REG_DVSSD1 0x1C +#define MAX77620_SDX_VOLT_MASK 0xFF +#define MAX77620_SD0_VOLT_MASK 0x7F // Max is 0x40. +#define MAX77620_SD1_VOLT_MASK 0x7F // Max is 0x4C. +#define MAX77620_LDO_VOLT_MASK 0x3F + +#define MAX77620_REG_SD0_CFG 0x1D +#define MAX77620_REG_SD1_CFG 0x1E +#define MAX77620_REG_SD2_CFG 0x1F +#define MAX77620_REG_SD3_CFG 0x20 +#define MAX77620_REG_SD4_CFG 0x21 +#define MAX77620_SD_SR_MASK 0xC0 +#define MAX77620_SD_SR_SHIFT 6 +#define MAX77620_SD_POWER_MODE_MASK 0x30 +#define MAX77620_SD_POWER_MODE_SHIFT 4 +#define MAX77620_SD_CFG1_ADE_MASK BIT(3) +#define MAX77620_SD_CFG1_ADE_DISABLE 0 +#define MAX77620_SD_CFG1_ADE_ENABLE BIT(3) +#define MAX77620_SD_FPWM_MASK 0x04 +#define MAX77620_SD_FPWM_SHIFT 2 +#define MAX77620_SD_FSRADE_MASK 0x01 +#define MAX77620_SD_FSRADE_SHIFT 0 +#define MAX77620_SD_CFG1_FPWM_SD_MASK BIT(2) +#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 +#define MAX77620_SD_CFG1_FPWM_SD_FPWM BIT(2) +#define MAX77620_SD_CFG1_MPOK_MASK BIT(1) +#define MAX77620_SD_CFG1_FSRADE_SD_MASK BIT(0) +#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 +#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE BIT(0) + +#define MAX77620_REG_SD_CFG2 0x22 +#define MAX77620_SD_CNF2_RSVD BIT(0) +#define MAX77620_SD_CNF2_ROVS_EN_SD1 BIT(1) +#define MAX77620_SD_CNF2_ROVS_EN_SD0 BIT(2) + +#define MAX77620_REG_LDO0_CFG 0x23 +#define MAX77620_REG_LDO0_CFG2 0x24 +#define MAX77620_REG_LDO1_CFG 0x25 +#define MAX77620_REG_LDO1_CFG2 0x26 +#define MAX77620_REG_LDO2_CFG 0x27 +#define MAX77620_REG_LDO2_CFG2 0x28 +#define MAX77620_REG_LDO3_CFG 0x29 +#define MAX77620_REG_LDO3_CFG2 0x2A +#define MAX77620_REG_LDO4_CFG 0x2B +#define MAX77620_REG_LDO4_CFG2 0x2C +#define MAX77620_REG_LDO5_CFG 0x2D +#define MAX77620_REG_LDO5_CFG2 0x2E +#define MAX77620_REG_LDO6_CFG 0x2F +#define MAX77620_REG_LDO6_CFG2 0x30 +#define MAX77620_REG_LDO7_CFG 0x31 +#define MAX77620_REG_LDO7_CFG2 0x32 +#define MAX77620_REG_LDO8_CFG 0x33 +#define MAX77620_REG_LDO8_CFG2 0x34 +/*! LDO CFG */ +#define MAX77620_LDO_POWER_MODE_SHIFT 6 +#define MAX77620_LDO_POWER_MODE_MASK (3 << MAX77620_LDO_POWER_MODE_SHIFT) +#define MAX77620_POWER_MODE_NORMAL 3 +#define MAX77620_POWER_MODE_LPM 2 +#define MAX77620_POWER_MODE_GLPM 1 +#define MAX77620_POWER_MODE_DISABLE 0 +/*! LDO CFG2 */ +#define MAX77620_LDO_CFG2_SS_MASK (1 << 0) +#define MAX77620_LDO_CFG2_SS_FAST (0 << 0) +#define MAX77620_LDO_CFG2_SS_SLOW (1 << 0) +#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) +#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) +#define MAX77620_LDO_CFG2_MPOK_MASK BIT(2) +#define MAX77620_LDO_CFG2_POK_MASK BIT(3) +#define MAX77620_LDO_CFG2_COMP_SHIFT 4 +#define MAX77620_LDO_CFG2_COMP_MASK (3 << MAX77620_LDO_COMP_SHIFT) +#define MAX77620_LDO_CFG2_COMP_SLOW 3 +#define MAX77620_LDO_CFG2_COMP_MID_SLOW 2 +#define MAX77620_LDO_CFG2_COMP_MID_FAST 1 +#define MAX77620_LDO_CFG2_COMP_FAST 0 +#define MAX77620_LDO_CFG2_ALPM_EN_MASK BIT(6) +#define MAX77620_LDO_CFG2_OVCLMP_MASK BIT(7) + +#define MAX77620_REG_LDO_CFG3 0x35 +#define MAX77620_LDO_BIAS_EN BIT(0) +#define MAX77620_TRACK4_SHIFT 5 +#define MAX77620_TRACK4_MASK (1 << MAX77620_TRACK4_SHIFT) + +#define MAX77620_REG_GPIO0 0x36 +#define MAX77620_REG_GPIO1 0x37 +#define MAX77620_REG_GPIO2 0x38 +#define MAX77620_REG_GPIO3 0x39 +#define MAX77620_REG_GPIO4 0x3A +#define MAX77620_REG_GPIO5 0x3B +#define MAX77620_REG_GPIO6 0x3C +#define MAX77620_REG_GPIO7 0x3D +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) +#define MAX77620_GPIO_OUTPUT_DISABLE 0 +#define MAX77620_GPIO_OUTPUT_ENABLE 1 + +#define MAX77620_REG_PUE_GPIO 0x3E // Gpio Pullup resistor enable. +#define MAX77620_REG_PDE_GPIO 0x3F // Gpio Pulldown resistor enable. + +#define MAX77620_REG_AME_GPIO \ + 0x40 // Gpio pinmuxing. Clear bits are Standard GPIO. + +#define MAX77620_REG_ONOFFCNFG1 0x41 +#define MAX20024_ONOFFCNFG1_CLRSE 0x18 +#define MAX77620_ONOFFCNFG1_PWR_OFF BIT(1) +#define MAX77620_ONOFFCNFG1_SLPEN BIT(2) +#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 +#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 +#define MAX77620_ONOFFCNFG1_RSVD BIT(6) +#define MAX77620_ONOFFCNFG1_SFT_RST BIT(7) + +#define MAX77620_REG_ONOFFCNFG2 0x42 +#define MAX77620_ONOFFCNFG2_WK_EN0 BIT(0) +#define MAX77620_ONOFFCNFG2_WK_ALARM2 BIT(1) +#define MAX77620_ONOFFCNFG2_WK_ALARM1 BIT(2) +#define MAX77620_ONOFFCNFG2_WK_MBATT \ + BIT(3) // MBATT event generates a wakeup signal. use it in android/l4t? +#define MAX77620_ONOFFCNFG2_WK_ACOK BIT(4) +#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK BIT(5) +#define MAX77620_ONOFFCNFG2_WD_RST_WK BIT(6) +#define MAX77620_ONOFFCNFG2_SFT_RST_WK BIT(7) + +/* FPS Registers */ +#define MAX77620_REG_FPS_CFG0 0x43 // FPS0. +#define MAX77620_REG_FPS_CFG1 0x44 // FPS1. +#define MAX77620_REG_FPS_CFG2 0x45 // FPS2. +#define MAX77620_FPS_ENFPS_SW_MASK 0x01 +#define MAX77620_FPS_ENFPS_SW 0x01 +#define MAX77620_FPS_EN_SRC_SHIFT 1 +#define MAX77620_FPS_EN_SRC_MASK 0x06 +#define MAX77620_FPS_TIME_PERIOD_SHIFT 3 +#define MAX77620_FPS_TIME_PERIOD_MASK 0x38 + +#define MAX77620_REG_FPS_LDO0 0x46 +#define MAX77620_REG_FPS_LDO1 0x47 +#define MAX77620_REG_FPS_LDO2 0x48 +#define MAX77620_REG_FPS_LDO3 0x49 +#define MAX77620_REG_FPS_LDO4 0x4A +#define MAX77620_REG_FPS_LDO5 0x4B +#define MAX77620_REG_FPS_LDO6 0x4C +#define MAX77620_REG_FPS_LDO7 0x4D +#define MAX77620_REG_FPS_LDO8 0x4E +#define MAX77620_REG_FPS_SD0 0x4F +#define MAX77620_REG_FPS_SD1 0x50 +#define MAX77620_REG_FPS_SD2 0x51 +#define MAX77620_REG_FPS_SD3 0x52 +#define MAX77620_REG_FPS_SD4 0x53 +#define MAX77620_REG_FPS_GPIO1 0x54 +#define MAX77620_REG_FPS_GPIO2 0x55 +#define MAX77620_REG_FPS_GPIO3 0x56 +#define MAX77620_REG_FPS_RSO 0x57 +#define MAX77620_FPS_PD_PERIOD_SHIFT 0 +#define MAX77620_FPS_PD_PERIOD_MASK 0x07 +#define MAX77620_FPS_PU_PERIOD_SHIFT 3 +#define MAX77620_FPS_PU_PERIOD_MASK 0x38 +#define MAX77620_FPS_SRC_SHIFT 6 +#define MAX77620_FPS_SRC_MASK 0xC0 + +#define MAX77620_FPS_COUNT 3 +#define MAX77620_FPS_PERIOD_MIN_US 40 +#define MAX77620_FPS_PERIOD_MAX_US 2560 + +#define MAX77620_REG_CID0 0x58 +#define MAX77620_REG_CID1 0x59 +#define MAX77620_REG_CID2 0x5A +#define MAX77620_REG_CID3 0x5B +#define MAX77620_REG_CID4 0x5C // OTP version. +#define MAX77620_REG_CID5 0x5D // ES version. +#define MAX77620_CID_DIDO_MASK 0xF +#define MAX77620_CID_DIDO_SHIFT 0 +#define MAX77620_CID_DIDM_MASK 0xF0 +#define MAX77620_CID_DIDM_SHIFT 4 + +/* Device Identification Metal */ +#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) +/* Device Indentification OTP */ +#define MAX77620_CID5_DIDO(n) ((n) & 0xF) + +#define MAX77620_REG_DVSSD4 0x5E +#define MAX20024_REG_MAX_ADD 0x70 + +#define MAX77620_IRQ_LVL2_GPIO_EDGE0 BIT(0) +#define MAX77620_IRQ_LVL2_GPIO_EDGE1 BIT(1) +#define MAX77620_IRQ_LVL2_GPIO_EDGE2 BIT(2) +#define MAX77620_IRQ_LVL2_GPIO_EDGE3 BIT(3) +#define MAX77620_IRQ_LVL2_GPIO_EDGE4 BIT(4) +#define MAX77620_IRQ_LVL2_GPIO_EDGE5 BIT(5) +#define MAX77620_IRQ_LVL2_GPIO_EDGE6 BIT(6) +#define MAX77620_IRQ_LVL2_GPIO_EDGE7 BIT(7) + +/* Interrupts */ +enum { + MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ + MAX77620_IRQ_TOP_SD, /* SD power fail */ + MAX77620_IRQ_TOP_LDO, /* LDO power fail */ + MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ + MAX77620_IRQ_TOP_RTC, /* RTC */ + MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ + MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ + MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ + MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ +}; + +/* GPIOs */ +enum { + MAX77620_GPIO0, + MAX77620_GPIO1, + MAX77620_GPIO2, + MAX77620_GPIO3, + MAX77620_GPIO4, + MAX77620_GPIO5, + MAX77620_GPIO6, + MAX77620_GPIO7, + MAX77620_GPIO_NR, +}; + +/* FPS Source */ +enum max77620_fps_src { + MAX77620_FPS_SRC_0, + MAX77620_FPS_SRC_1, + MAX77620_FPS_SRC_2, + MAX77620_FPS_SRC_NONE, + MAX77620_FPS_SRC_DEF, +}; + +#define MAX77812_PHASE31_CPU_I2C_ADDR \ + 0x31 // High power GPU. 2 Outputs: 3-phase M1 + 1-phase M4. +#define MAX77812_PHASE211_CPU_I2C_ADDR \ + 0x33 // Low power GPU. 3 Outputs: 2-phase M1 + 1-phase M3 + 1-phase M4. + +#define MAX77812_REG_RSET 0x00 +#define MAX77812_REG_INT_SRC 0x01 +#define MAX77812_REG_INT_SRC_M 0x02 +#define MAX77812_REG_TOPSYS_INT 0x03 +#define MAX77812_REG_TOPSYS_INT_M 0x04 +#define MAX77812_REG_TOPSYS_STAT 0x05 +#define MAX77812_REG_EN_CTRL 0x06 +#define MAX77812_EN_CTRL_ENABLE 1 +#define MAX77812_EN_CTRL_EN_M1_SHIFT 0 +#define MAX77812_EN_CTRL_EN_M1_MASK (1 << MAX77812_EN_CTRL_EN_M1_SHIFT) +#define MAX77812_EN_CTRL_EN_M2_SHIFT 2 +#define MAX77812_EN_CTRL_EN_M2_MASK (1 << MAX77812_EN_CTRL_EN_M2_SHIFT) +#define MAX77812_EN_CTRL_EN_M3_SHIFT 4 +#define MAX77812_EN_CTRL_EN_M3_MASK (1 << MAX77812_EN_CTRL_EN_M3_SHIFT) +#define MAX77812_EN_CTRL_EN_M4_SHIFT 6 +#define MAX77812_EN_CTRL_EN_M4_MASK (1 << MAX77812_EN_CTRL_EN_M4_SHIFT) +#define MAX77812_REG_STUP_DLY2 0x07 +#define MAX77812_REG_STUP_DLY3 0x08 +#define MAX77812_REG_STUP_DLY4 0x09 +#define MAX77812_REG_SHDN_DLY1 0x0A +#define MAX77812_REG_SHDN_DLY2 0x0B +#define MAX77812_REG_SHDN_DLY3 0x0C +#define MAX77812_REG_SHDN_DLY4 0x0D +#define MAX77812_REG_WDTRSTB_DEB 0x0E +#define MAX77812_REG_GPI_FUNC 0x0F +#define MAX77812_REG_GPI_DEB1 0x10 +#define MAX77812_REG_GPI_DEB2 0x11 +#define MAX77812_REG_GPI_PD_CTRL 0x12 +#define MAX77812_REG_PROT_CFG 0x13 +#define MAX77812_REG_VERSION 0x14 +#define MAX77812_REG_I2C_CFG 0x15 +#define MAX77812_REG_BUCK_INT 0x20 +#define MAX77812_REG_BUCK_INT_M 0x21 +#define MAX77812_REG_BUCK_STAT 0x22 +#define MAX77812_REG_M1_VOUT 0x23 // GPU. +#define MAX77812_REG_M2_VOUT 0x24 +#define MAX77812_REG_M3_VOUT 0x25 // DRAM on PHASE211. +#define MAX77812_REG_M4_VOUT 0x26 // CPU. +#define MAX77812_REG_M1_VOUT_D 0x27 +#define MAX77812_REG_M2_VOUT_D 0x28 +#define MAX77812_REG_M3_VOUT_D 0x29 +#define MAX77812_REG_M4_VOUT_D 0x2A +#define MAX77812_REG_M1_VOUT_S 0x2B +#define MAX77812_REG_M2_VOUT_S 0x2C +#define MAX77812_REG_M3_VOUT_S 0x2D +#define MAX77812_REG_M4_VOUT_S 0x2E +#define MAX77812_REG_M1_CFG 0x2F // HOS: M1_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M2_CFG 0x30 // HOS: M2_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M3_CFG 0x31 // HOS: M3_ILIM - 7.2A/4.8A. +#define MAX77812_REG_M4_CFG 0x32 // HOS: M4_ILIM - 7.2A/4.8A. +#define MAX77812_REG_GLB_CFG1 0x33 // HOS: B_SD_SR/B_SS_SR - 5mV/us. +#define MAX77812_REG_GLB_CFG2 0x34 // HOS: B_RD_SR/B_RU_SR - 5mV/us +#define MAX77812_REG_GLB_CFG3 0x35 + +/*! Protected area and settings only for MAX77812_ES2_VERSION */ +#define MAX77812_REG_GLB_CFG4 0x36 // QS: 0xBB. +#define MAX77812_REG_GLB_CFG5 0x37 // QS: 0x39. ES2: Set to 0x3E. +#define MAX77812_REG_GLB_CFG6 0x38 // QS: 0x88. ES2: Set to 0x90. +#define MAX77812_REG_GLB_CFG7 0x39 // QS: 0x04. +#define MAX77812_REG_GLB_CFG8 0x3A // QS: 0x3A. ES2: Set to 0x3A. + +#define MAX77812_REG_PROT_ACCESS 0xFD // 0x00: Lock, 0x5A: Unlock. +#define MAX77812_REG_UNKNOWN 0xFE + +#define MAX77812_REG_EN_CTRL_MASK(n) BIT(n) +#define MAX77812_START_SLEW_RATE_MASK 0x07 +#define MAX77812_SHDN_SLEW_RATE_MASK 0x70 +#define MAX77812_RAMPUP_SLEW_RATE_MASK 0x07 +#define MAX77812_RAMPDOWN_SLEW_RATE_MASK 0x70 +#define MAX77812_SLEW_RATE_SHIFT 4 + +#define MAX77812_OP_ACTIVE_DISCHARGE_MASK BIT(7) +#define MAX77812_PEAK_CURRENT_LMT_MASK 0x70 +#define MAX77812_SWITCH_FREQ_MASK 0x0C +#define MAX77812_FORCED_PWM_MASK BIT(1) +#define MAX77812_SLEW_RATE_CNTRL_MASK BIT(0) +#define MAX77812_START_SHD_DELAY_MASK 0x1F +#define MAX77812_VERSION_MASK 0x07 +#define MAX77812_ES2_VERSION 0x04 +#define MAX77812_QS_VERSION 0x05 + +#define MAX77812_BUCK_VOLT_MASK 0xFF + +#define BQ24193_I2C_ADDR 0x6B + +// REG 0 masks. +#define BQ24193_INCONFIG_INLIMIT_MASK (7 << 0) +#define BQ24193_INCONFIG_VINDPM_MASK 0x78 +#define BQ24193_INCONFIG_HIZ_EN_MASK (1 << 7) + +// REG 1 masks. +#define BQ24193_PORCONFIG_BOOST_MASK (1 << 0) +#define BQ24193_PORCONFIG_SYSMIN_MASK (7 << 1) // 3000uV HOS default. +#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3 << 4) +#define BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN (1 << 4) +#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1 << 6) +#define BQ24193_PORCONFIG_RESET_MASK (1 << 7) + +// REG 2 masks. +#define BQ24193_CHRGCURR_20PCT_MASK (1 << 0) +#define BQ24193_CHRGCURR_ICHG_MASK 0xFC + +// REG 3 masks. +#define BQ24193_PRECHRG_ITERM 0x0F +#define BQ24193_PRECHRG_IPRECHG 0xF0 + +// REG 4 masks. +#define BQ24193_CHRGVOLT_VTHRES (1 << 0) +#define BQ24193_CHRGVOLT_BATTLOW (1 << 1) +#define BQ24193_CHRGVOLT_VREG 0xFC + +// REG 5 masks. +#define BQ24193_CHRGTERM_ISET_MASK (1 << 0) +#define BQ24193_CHRGTERM_CHGTIMER_MASK (3 << 1) +#define BQ24193_CHRGTERM_ENTIMER_MASK (1 << 3) +#define BQ24193_CHRGTERM_WATCHDOG_MASK (3 << 4) +#define BQ24193_CHRGTERM_TERM_ST_MASK (1 << 6) +#define BQ24193_CHRGTERM_TERM_EN_MASK (1 << 7) + +// REG 6 masks. +#define BQ24193_IRTHERMAL_THERM_MASK (3 << 0) +#define BQ24193_IRTHERMAL_VCLAMP_MASK (7 << 2) +#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7 << 5) + +// REG 7 masks. +#define BQ24193_MISC_INT_MASK (3 << 0) +#define BQ24193_MISC_VSET_MASK (1 << 4) +#define BQ24193_MISC_BATFET_DI_MASK (1 << 5) +#define BQ24193_MISC_TMR2X_EN_MASK (1 << 6) +#define BQ24193_MISC_DPDM_EN_MASK (1 << 7) + +// REG 8 masks. +#define BQ24193_STATUS_VSYS_MASK (1 << 0) +#define BQ24193_STATUS_THERM_MASK (1 << 1) +#define BQ24193_STATUS_PG_MASK (1 << 2) +#define BQ24193_STATUS_DPM_MASK (1 << 3) +#define BQ24193_STATUS_CHRG_MASK (3 << 4) +#define BQ24193_STATUS_VBUS_MASK (3 << 6) + +// REG 9 masks. +#define BQ24193_FAULT_THERM_MASK (7 << 0) +#define BQ24193_FAULT_BATT_OVP_MASK (1 << 3) +#define BQ24193_FAULT_CHARGE_MASK (3 << 4) +#define BQ24193_FAULT_BOOST_MASK (1 << 6) +#define BQ24193_FAULT_WATCHDOG_MASK (1 << 7) + +// REG A masks. +#define BQ24193_VENDORPART_DEV_MASK (3 << 0) +#define BQ24193_VENDORPART_PN_MASK (7 << 3) + +enum BQ24193_reg { + BQ24193_InputSource = 0x00, + BQ24193_PORConfig = 0x01, + BQ24193_ChrgCurr = 0x02, + BQ24193_PreChrgTerm = 0x03, + BQ24193_ChrgVolt = 0x04, + BQ24193_ChrgTermTimer = 0x05, + BQ24193_IRCompThermal = 0x06, + BQ24193_Misc = 0x07, + BQ24193_Status = 0x08, + BQ24193_FaultReg = 0x09, + BQ24193_VendorPart = 0x0A, +}; + +enum BQ24193_reg_prop { + BQ24193_InputVoltageLimit, // REG 0. + BQ24193_InputCurrentLimit, // REG 0. + BQ24193_SystemMinimumVoltage, // REG 1. + BQ24193_FastChargeCurrentLimit, // REG 2. + BQ24193_ChargeVoltageLimit, // REG 4. + BQ24193_RechargeThreshold, // REG 4. + BQ24193_ThermalRegulation, // REG 6. + BQ24193_ChargeStatus, // REG 8. + BQ24193_TempStatus, // REG 9. + BQ24193_DevID, // REG A. + BQ24193_ProductNumber, // REG A. +}; + +#endif /* MAX77XXX_H */ diff --git a/Source/sys-clk/sysmodule/src/pwm_dimming.cpp b/Source/sys-clk/sysmodule/src/pwm_dimming.cpp new file mode 100644 index 00000000..9755b94a --- /dev/null +++ b/Source/sys-clk/sysmodule/src/pwm_dimming.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include "config.h" +#include "errors.h" +#include "file_utils.h" +#include "pwm_dimming.h" +#define PWM_DIMMING_HZ_RATE 5e3 // 5KHz PWM dimming, should be decent for most people +#define DUTY_CYCLE_LEGNTH_NS (1e9 / (double)(PWM_DIMMING_HZ_RATE)) + +float initial_brightness = 1.0f; +float current_brightness = 1.0f; +Thread pwmThread; + +PWMDimmer *PWMDimmer::instance = nullptr; + +PWMDimmer *PWMDimmer::GetInstance() +{ + return instance; +} + +void PWMDimmer::Initialize() +{ + if (!instance) { + instance = new PWMDimmer(); + FileUtils::LogLine("[pwmDim] Initialized PWMDimmer"); + } +} + +Config *PWMDimmer::GetConfig() +{ + return this->config; +} + +void PWMDimmer::Exit() +{ + if (instance) { + FileUtils::LogLine("[pwmDim] Exiting PWMDimmer"); + delete instance; + instance = nullptr; + } +} + +PWMDimmer::PWMDimmer() +{ + this->config = Config::CreateDefault(); +} + +PWMDimmer::~PWMDimmer() +{ + delete this->config; +} + +void PWMDimmer::Start() +{ + std::scoped_lock lock{ this->patcherMutex }; + this->config->Refresh(); + this->StartPWMDimming(); + + u64 sku = 0; + Result rc = splInitialize(); + ASSERT_RESULT_OK(rc, "splInitialize"); + + rc = splGetConfig(SplConfigItem_HardwareType, &sku); + ASSERT_RESULT_OK(rc, "splGetConfig"); + + splExit(); + if (sku == HocClkConsoleType_OLED && this->config->GetConfigValue(HocClkConfigValue_PWMDimming)) { + lblGetCurrentBrightnessSetting(&initial_brightness); + Result rc = + threadCreate(&pwmThread, ThreadEntry, this, NULL, 0x4000, 0x2B, -2); + if (R_FAILED(rc)) { + return; + } + + rc = threadStart(&pwmThread); + if (R_FAILED(rc)) { + threadClose(&pwmThread); + return; + } + } +} + +void PWMDimmer::ThreadEntry(void *arg) +{ + auto *self = static_cast(arg); + self->StartPWMDimming(); +} + +void PWMDimmer::StartPWMDimming() +{ + Result rc = lblInitialize(); + if (R_FAILED(rc)) { + return; + } + for (;;) { + lblGetCurrentBrightnessSetting(¤t_brightness); + lblSetCurrentBrightnessSetting(current_brightness); + svcSleepThread(DUTY_CYCLE_LEGNTH_NS / 2); + lblSetCurrentBrightnessSetting(0.0f); + svcSleepThread(DUTY_CYCLE_LEGNTH_NS / 2); + } +} diff --git a/Source/sys-clk/sysmodule/src/pwm_dimming.h b/Source/sys-clk/sysmodule/src/pwm_dimming.h new file mode 100644 index 00000000..555552a3 --- /dev/null +++ b/Source/sys-clk/sysmodule/src/pwm_dimming.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) Souldbminer and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +#include +#include +#include "config.h" +#include "errors.h" + +class PWMDimmer +{ + public: + static PWMDimmer* GetInstance(); + static void Initialize(); + Config *GetConfig(); + static void Exit(); + + PWMDimmer(); + ~PWMDimmer(); + static void ThreadEntry(void* arg); + + void Start(); + void StartPWMDimming(); + + private: + static PWMDimmer* instance; + Config* config; + std::mutex patcherMutex; + +};