Merge sys-clk-oc and add upto 2903 clocks (please don't use)

I do have to come up with a better name too...
This commit is contained in:
souldbminersmwc
2025-08-22 18:31:38 -04:00
parent 822556e6e4
commit 4738eea080
289 changed files with 50229 additions and 4772 deletions

View File

@@ -0,0 +1,66 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* 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 "nxExt/apm_ext.h"
#include <stdatomic.h>
static Service g_apmSrv;
static Service g_apmSysSrv;
static atomic_size_t g_refCnt;
Result apmExtInitialize(void)
{
g_refCnt++;
if (serviceIsActive(&g_apmSrv))
{
return 0;
}
Result rc = 0;
rc = smGetService(&g_apmSrv, "apm");
if(R_SUCCEEDED(rc))
{
rc = smGetService(&g_apmSysSrv, "apm:sys");
}
if (R_FAILED(rc))
{
apmExtExit();
}
return rc;
}
void apmExtExit(void)
{
if (--g_refCnt == 0)
{
serviceClose(&g_apmSrv);
serviceClose(&g_apmSysSrv);
}
}
Result apmExtGetPerformanceMode(u32* out_mode)
{
return serviceDispatchOut(&g_apmSrv, 1, *out_mode);
}
Result apmExtSysRequestPerformanceMode(u32 mode)
{
return serviceDispatchIn(&g_apmSysSrv, 0, mode);
}
Result apmExtGetCurrentPerformanceConfiguration(u32* out_conf)
{
return serviceDispatchOut(&g_apmSysSrv, 7, *out_conf);
}

View File

@@ -0,0 +1,204 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* 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 "nxExt/ipc_server.h"
#include <string.h>
Result ipcServerInit(IpcServer* server, const char* name, u32 max_sessions)
{
if(max_sessions < 1 || max_sessions > (MAX_WAIT_OBJECTS - 1))
{
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
}
server->srvName = smEncodeName(name);
server->max = max_sessions + 1;
server->count = 0;
Result rc = smRegisterService(&server->handles[0], server->srvName, false, max_sessions);
if(R_SUCCEEDED(rc))
{
server->count = 1;
}
return rc;
}
Result ipcServerExit(IpcServer* server)
{
for(u32 i = 0; i < server->count; i++)
{
svcCloseHandle(server->handles[i]);
}
server->count = 0;
return smUnregisterService(server->srvName);
}
static Result _ipcServerAddSession(IpcServer* server, Handle session)
{
if(server->count >= server->max)
{
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
server->handles[server->count] = session;
server->count++;
return 0;
}
static Result _ipcServerDeleteSession(IpcServer* server, u32 index)
{
if(!index || index >= server->count)
{
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
}
svcCloseHandle(server->handles[index]);
for(u32 j = index; j < (server->count - 1); j++)
{
server->handles[j] = server->handles[j + 1];
}
server->count--;
return 0;
}
static Result _ipcServerParseRequest(IpcServerRequest* r)
{
u8* base = armGetTls();
r->hipc = hipcParseRequest(base);
r->data.cmdId = 0;
r->data.size = 0;
r->data.ptr = NULL;
if(r->hipc.meta.type == CmifCommandType_Request)
{
IpcServerRawHeader* header = cmifGetAlignedDataStart(r->hipc.data.data_words, base);
size_t dataSize = r->hipc.meta.num_data_words * 4;
if(!header || dataSize < sizeof(IpcServerRawHeader) || header->magic != CMIF_IN_HEADER_MAGIC)
{
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
}
r->data.cmdId = header->cmdId;
if(dataSize > sizeof(IpcServerRawHeader))
{
r->data.size = dataSize - sizeof(IpcServerRawHeader);
r->data.ptr = ((u8*)header) + sizeof(IpcServerRawHeader);
}
}
return 0;
}
static void _ipcServerPrepareResponse(Result rc, void* data, size_t dataSize)
{
u8* base = armGetTls();
HipcRequest hipc = hipcMakeRequestInline(base,
.type = CmifCommandType_Request,
.num_data_words = (sizeof(IpcServerRawHeader) + dataSize + 0x10) / 4,
);
IpcServerRawHeader* rawHeader = cmifGetAlignedDataStart(hipc.data_words, base);
rawHeader->magic = CMIF_OUT_HEADER_MAGIC;
rawHeader->result = rc;
if(R_SUCCEEDED(rc))
{
memcpy(((u8*)rawHeader) + sizeof(IpcServerRawHeader), data, dataSize);
}
}
static Result _ipcServerProcessNewSession(IpcServer* server)
{
Handle session;
Result rc = svcAcceptSession(&session, server->handles[0]);
if(R_SUCCEEDED(rc) && R_FAILED(rc = _ipcServerAddSession(server, session)))
{
svcCloseHandle(session);
}
return rc;
}
static Result _ipcServerProcessSession(IpcServer* server, IpcServerRequestHandler handler, void* userdata, u32 handleIndex)
{
s32 unusedIndex;
IpcServerRequest r;
size_t dataSize = 0;
u8 data[IPC_SERVER_EXT_RESPONSE_MAX_DATA_SIZE];
bool close = false;
Result rc = svcReplyAndReceive(&unusedIndex, &server->handles[handleIndex], 1, 0, UINT64_MAX);
if(R_SUCCEEDED(rc))
{
rc = _ipcServerParseRequest(&r);
}
if(R_SUCCEEDED(rc))
{
switch(r.hipc.meta.type)
{
case CmifCommandType_Request:
_ipcServerPrepareResponse(
handler(userdata, &r, data, &dataSize),
data,
dataSize
);
break;
case CmifCommandType_Close:
_ipcServerPrepareResponse(0, NULL, 0);
close = true;
break;
default:
_ipcServerPrepareResponse(MAKERESULT(11, 403), NULL, 0);
break;
}
rc = svcReplyAndReceive(&unusedIndex, &server->handles[handleIndex], 0, server->handles[handleIndex], 0);
if(rc == KERNELRESULT(TimedOut))
{
rc = 0;
}
}
if(R_FAILED(rc) || close)
{
_ipcServerDeleteSession(server, handleIndex);
}
return rc;
}
Result ipcServerProcess(IpcServer* server, IpcServerRequestHandler handler, void* userdata)
{
s32 handleIndex = -1;
Result rc = svcWaitSynchronization(&handleIndex, server->handles, server->count, UINT64_MAX);
if(R_SUCCEEDED(rc) && (handleIndex < 0 || handleIndex >= server->count))
{
rc = MAKERESULT(Module_Libnx, LibnxError_NotFound);
}
if(R_SUCCEEDED(rc))
{
if(handleIndex)
{
rc = _ipcServerProcessSession(server, handler, userdata, handleIndex);
}
else
{
rc = _ipcServerProcessNewSession(server);
}
}
return rc;
}

View File

@@ -0,0 +1,125 @@
/*
* Fuel gauge driver for Nintendo Switch's Maxim 17050
*
* Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (c) 2018 CTCaer
* Copyright (c) 2022 p-sam
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "nxExt/max17050.h"
#define MAX17050_WAIT_NS 1175800000UL
#define MAX17050_VCELL 0x09
#define MAX17050_Current 0x0A
#define MAX17050_AvgCurrent 0x0B
#define MAX17050_AvgVCELL 0x19
#define MAX17050_BOARD_CGAIN 2
#define MAX17050_BOARD_SNS_RESISTOR_UOHM 5000
static I2cSession g_i2c_session;
static u64 g_update_ticks = 0;
static s32 g_power_now = 0;
static s32 g_power_avg = 0;
static Result _max17050_get_reg(u8 reg, u16* out)
{
Result rc = i2csessionSendAuto(&g_i2c_session, &reg, sizeof(reg), I2cTransactionOption_All);
if(R_SUCCEEDED(rc))
{
rc = i2csessionReceiveAuto(&g_i2c_session, out, sizeof(*out), I2cTransactionOption_All);
}
return rc;
}
static Result _max17050_get_power(u8 creg, u8 vreg, s32 *out_mw)
{
u16 current = 0;
u16 voltage = 0;
Result rc = _max17050_get_reg(creg, &current);
if(R_SUCCEEDED(rc))
{
rc = _max17050_get_reg(vreg, &voltage);
}
if(R_SUCCEEDED(rc))
{
s64 ma = (s16)current;
ma *= 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN);
s64 mv = (int)(voltage >> 3) * 625 / 1000;
*out_mw = ma * mv / 1000000;
}
return rc;
}
static void _max17050_update()
{
u64 ticks = armGetSystemTick();
if(armTicksToNs(ticks - g_update_ticks) <= MAX17050_WAIT_NS)
{
return;
}
g_update_ticks = ticks;
if(!serviceIsActive(&g_i2c_session.s))
{
return;
}
_max17050_get_power(MAX17050_Current, MAX17050_VCELL, &g_power_now);
_max17050_get_power(MAX17050_AvgCurrent, MAX17050_AvgVCELL, &g_power_avg);
}
Result max17050Initialize(void)
{
Result rc = i2cInitialize();
if(R_SUCCEEDED(rc))
{
rc = i2cOpenSession(&g_i2c_session, I2cDevice_Max17050);
}
return rc;
}
void max17050Exit(void)
{
i2csessionClose(&g_i2c_session);
i2cExit();
}
s32 max17050PowerNow(void)
{
_max17050_update();
return g_power_now;
}
s32 max17050PowerAvg(void)
{
_max17050_update();
return g_power_avg;
}

View File

@@ -0,0 +1,54 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* 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 "nxExt/pcv_ext.h"
Result pcvExtGetPossibleClockRates(PcvModule module, u32 *rates, s32 max_count, PcvExtClockRatesListType *out_type, s32 *out_count)
{
if(hosversionAtLeast(8,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
const struct {
PcvModule module;
s32 max_count;
} in = { module, max_count };
struct {
s32 type;
s32 count;
} out;
Result rc = serviceDispatchInOut(pcvGetServiceSession(), 5, in, out,
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcPointer, },
.buffers = { { rates, max_count * sizeof(u32) }, }
);
if (R_SUCCEEDED(rc) && out_type) *out_type = out.type;
if (R_SUCCEEDED(rc) && out_count) *out_count = out.count;
return rc;
}
Result clkrstExtGetPossibleClockRates(ClkrstSession *session, u32 *rates, s32 max_count, PcvExtClockRatesListType *out_type, s32 *out_count) {
struct {
s32 type;
s32 count;
} out;
Result rc = serviceDispatchInOut(&session->s, 10, max_count, out,
.buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcAutoSelect, },
.buffers = { { rates, max_count * sizeof(u32) }, }
);
if (R_SUCCEEDED(rc) && out_type) *out_type = out.type;
if (R_SUCCEEDED(rc) && out_count) *out_count = out.count;
return rc;
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2022 CTCaer
* Copyright (c) 2022 p-sam
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "nxExt/t210_clk.h"
#define WAIT_NS 1000000000UL
#define usleep(x) svcSleepThread(1000UL * x)
#define GPU_TRIM_SYS_GPCPLL_COEFF 0x4
#define GPU_TRIM_SYS_GPCPLL(x) (*(volatile u32 *)(g_gpu_base + 0x137000ul + (x)))
#define CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL 0x60
#define CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS 0x64
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C
/*! PTO_CLK_CNT */
#define PTO_REF_CLK_WIN_CFG_MASK 0xF
#define PTO_REF_CLK_WIN_CFG_16P 0xF
#define PTO_CNT_EN BIT(9)
#define PTO_CNT_RST BIT(10)
#define PTO_CLK_ENABLE BIT(13)
#define PTO_SRC_SEL_SHIFT 14
#define PTO_SRC_SEL_MASK 0x1FF
#define PTO_DIV_SEL_MASK (3 << 23)
#define PTO_DIV_SEL_GATED (0 << 23)
#define PTO_DIV_SEL_DIV1 (1 << 23)
#define PTO_DIV_SEL_DIV2_RISING (2 << 23)
#define PTO_DIV_SEL_DIV2_FALLING (3 << 23)
#define PTO_DIV_SEL_CPU_EARLY (0 << 23)
#define PTO_DIV_SEL_CPU_LATE (1 << 23)
#define PTO_CLK_CNT_BUSY BIT(31)
#define PTO_CLK_CNT 0xFFFFFF
#define CLK_PTO_CCLK_G 0x12
#define CLK_PTO_EMC 0x24
#define CLOCK(x) (*(volatile u32 *)(g_clk_base + (x)))
static uintptr_t g_clk_base = 0;
static uintptr_t g_gpu_base = 0;
static u64 g_update_ticks = 0;
static u32 g_cpu_freq = 0;
static u32 g_gpu_freq = 0;
static u32 g_mem_freq = 0;
static u32 _clock_get_dev_freq(u32 id)
{
const u32 pto_win = 16;
const u32 pto_osc = 32768;
u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (pto_win - 1);
CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val;
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST;
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val;
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN;
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep((1000000ULL * pto_win / pto_osc) + 12 + 2); // 502 us.
while (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY)
;
u32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT;
CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0;
(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);
usleep(2);
u32 freq_khz = (u64)cnt * pto_osc / pto_win / 1000;
return freq_khz;
}
static inline Result _svcQueryIoMappingFallback(u64* virtaddr, u64 physaddr, u64 size)
{
if(hosversionAtLeast(10,0,0))
{
u64 out_size;
return svcQueryIoMapping(virtaddr, &out_size, physaddr, size);
}
else
{
return svcLegacyQueryIoMapping(virtaddr, physaddr, size);
}
}
static void _clock_update_freqs(void)
{
u64 ticks = armGetSystemTick();
if(armTicksToNs(ticks - g_update_ticks) <= WAIT_NS)
{
return;
}
g_update_ticks = ticks;
if (!g_clk_base)
{
_svcQueryIoMappingFallback(&g_clk_base, 0x60006000ul, 0x1000);
}
if(!g_clk_base)
{
return;
}
g_mem_freq = _clock_get_dev_freq(CLK_PTO_EMC) * 1000;
g_cpu_freq = _clock_get_dev_freq(CLK_PTO_CCLK_G) * 1000;
if (!g_gpu_base)
{
_svcQueryIoMappingFallback(&g_gpu_base, 0x57000000ul, 0x1000000);
}
if (!g_gpu_base)
{
return;
}
bool gpu_enabled = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) & BIT(24)) && !(CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_X) & BIT(24));
if(!gpu_enabled)
{
return;
}
const u32 osc = 38400000;
u32 coeff = GPU_TRIM_SYS_GPCPLL(GPU_TRIM_SYS_GPCPLL_COEFF);
u32 divm = coeff & 0xFF;
u32 divn = (coeff >> 8) & 0xFF;
u32 divp = (coeff >> 16) & 0x3F;
g_gpu_freq = osc * divn / (divm * divp) / 2;
}
u32 t210ClkCpuFreq(void)
{
_clock_update_freqs();
return g_cpu_freq;
}
u32 t210ClkMemFreq(void)
{
_clock_update_freqs();
return g_mem_freq;
}
u32 t210ClkGpuFreq(void)
{
_clock_update_freqs();
return g_gpu_freq;
}

View File

@@ -0,0 +1,28 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* 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 "nxExt/ts_ext.h"
Result tsExtOpenSession(TsExtSession *out, TsLocation dev) {
const u32 in = ((u32)dev + 1) | 0x41000000;
return serviceDispatchIn(tsGetServiceSession(), 4, in,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
void tsExtCloseSession(TsExtSession *session) {
serviceClose(&session->s);
}
Result tsExtSessionGetTemperature(TsExtSession *session, float *temperature) {
return serviceDispatchOut(&session->s, 4, *temperature);
}