rewrite everything
This commit is contained in:
66
Source/sys-clk/sysmodule/lib/nxExt/src/apm_ext.c
Normal file
66
Source/sys-clk/sysmodule/lib/nxExt/src/apm_ext.c
Normal 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);
|
||||
}
|
||||
28
Source/sys-clk/sysmodule/lib/nxExt/src/i2c.c
Normal file
28
Source/sys-clk/sysmodule/lib/nxExt/src/i2c.c
Normal 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/i2c.h"
|
||||
|
||||
#define I2C_CMD_SND 0
|
||||
#define I2C_CMD_RCV 1
|
||||
|
||||
Result i2csessionExtRegReceive(I2cSession* s, u8 in, void* out, u8 out_size)
|
||||
{
|
||||
u8 cmdlist[5] = {
|
||||
I2C_CMD_SND | (I2cTransactionOption_Start << 6),
|
||||
sizeof(in),
|
||||
in,
|
||||
|
||||
I2C_CMD_RCV | (I2cTransactionOption_All << 6),
|
||||
out_size
|
||||
};
|
||||
|
||||
return i2csessionExecuteCommandList(s, out, out_size, cmdlist, sizeof(cmdlist));
|
||||
}
|
||||
204
Source/sys-clk/sysmodule/lib/nxExt/src/ipc_server.c
Normal file
204
Source/sys-clk/sysmodule/lib/nxExt/src/ipc_server.c
Normal 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;
|
||||
}
|
||||
|
||||
124
Source/sys-clk/sysmodule/lib/nxExt/src/max17050.c
Normal file
124
Source/sys-clk/sysmodule/lib/nxExt/src/max17050.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "nxExt/i2c.h"
|
||||
|
||||
#define MAX17050_WAIT_NS 1000000000UL
|
||||
|
||||
#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_power(s32 *out_mw_now, s32 *out_mw_avg)
|
||||
{
|
||||
s64 ma, mv;
|
||||
u16 values[3] = {0};
|
||||
|
||||
Result rc = i2csessionExtRegReceive(&g_i2c_session, MAX17050_VCELL, values, sizeof(values));
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
ma = (s16)values[1];
|
||||
ma = ma * 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN);
|
||||
|
||||
mv = (int)(values[0] >> 3) * 625 / 1000;
|
||||
|
||||
*out_mw_now = ma * mv / 1000000;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = i2csessionExtRegReceive(&g_i2c_session, MAX17050_AvgVCELL, values, sizeof(u16));
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
ma = (s16)values[2];
|
||||
ma = ma * 1562500 / (MAX17050_BOARD_SNS_RESISTOR_UOHM * MAX17050_BOARD_CGAIN);
|
||||
|
||||
mv = (int)(values[0] >> 3) * 625 / 1000;
|
||||
|
||||
*out_mw_avg = 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(&g_power_now, &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;
|
||||
}
|
||||
289
Source/sys-clk/sysmodule/lib/nxExt/src/t210.c
Normal file
289
Source/sys-clk/sysmodule/lib/nxExt/src/t210.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2023 CTCaer
|
||||
* Copyright (c) 2023 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.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)))
|
||||
|
||||
/* Actmon Global registers */
|
||||
#define ACTMON_GLB_STATUS 0x0
|
||||
#define ACTMON_MCCPU_MON_ACT BIT(8)
|
||||
#define ACTMON_MCALL_MON_ACT BIT(9)
|
||||
#define ACTMON_CPU_FREQ_MON_ACT BIT(10)
|
||||
#define ACTMON_BPMP_MON_ACT BIT(14)
|
||||
#define ACTMON_CPU_MON_ACT BIT(15)
|
||||
|
||||
#define ACTMON_GLB_PERIOD_CTRL 0x4
|
||||
#define ACTMON_GLB_PERIOD_USEC BIT(8)
|
||||
#define ACTMON_GLB_PERIOD_SAMPLE(n) (((n) - 1) & 0xFF)
|
||||
|
||||
/* Actmon Device Registers */
|
||||
#define ACTMON_DEV_SIZE 0x40
|
||||
/* Actmon CTRL */
|
||||
#define ACTMON_DEV_CTRL_K_VAL(k) (((k) & 7) << 10)
|
||||
#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18)
|
||||
#define ACTMON_DEV_CTRL_ENB BIT(31)
|
||||
|
||||
#define ACTMON_PERIOD_MS 20
|
||||
#define DEV_COUNT_WEIGHT 1024
|
||||
|
||||
#define ACTMON_BASE (g_act_base + 0x800)
|
||||
#define ACTMON_DEV_BASE (ACTMON_BASE + 0x80)
|
||||
#define ACTMON(x) (*(volatile u32 *)(ACTMON_BASE + (x)))
|
||||
|
||||
typedef enum _actmon_dev_t
|
||||
{
|
||||
ACTMON_DEV_CPU,
|
||||
ACTMON_DEV_BPMP,
|
||||
ACTMON_DEV_AHB,
|
||||
ACTMON_DEV_APB,
|
||||
ACTMON_DEV_CPU_FREQ,
|
||||
ACTMON_DEV_MC_ALL,
|
||||
ACTMON_DEV_MC_CPU,
|
||||
|
||||
ACTMON_DEV_NUM,
|
||||
} actmon_dev_t;
|
||||
|
||||
typedef struct _actmon_dev_reg_t
|
||||
{
|
||||
vu32 ctrl;
|
||||
vu32 upper_wnark;
|
||||
vu32 lower_wmark;
|
||||
vu32 init_avg;
|
||||
vu32 avg_upper_wmark;
|
||||
vu32 avg_lower_wmark;
|
||||
vu32 count_weight;
|
||||
vu32 count;
|
||||
vu32 avg_count;
|
||||
vu32 intr_status;
|
||||
vu32 ctrl2;
|
||||
vu32 rsvd[5];
|
||||
} actmon_dev_reg_t;
|
||||
|
||||
static uintptr_t g_clk_base = 0;
|
||||
static uintptr_t g_gpu_base = 0;
|
||||
static uintptr_t g_act_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 g_emc_lall = 0;
|
||||
static u32 g_emc_lcpu = 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 void _actmon_dev_enable(actmon_dev_t dev, u32 freq, u32 weight)
|
||||
{
|
||||
actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));
|
||||
|
||||
regs->init_avg = (u32)freq * ACTMON_PERIOD_MS / 2;
|
||||
regs->count_weight = weight;
|
||||
|
||||
regs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC | ACTMON_DEV_CTRL_K_VAL(3); // 8 samples average.
|
||||
}
|
||||
|
||||
static u32 _actmon_dev_get_count_avg(actmon_dev_t dev)
|
||||
{
|
||||
actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));
|
||||
|
||||
return regs->avg_count;
|
||||
}
|
||||
|
||||
static inline Result _svcQueryMemoryMappingFallback(u64* virtaddr, u64 physaddr, u64 size)
|
||||
{
|
||||
if(hosversionAtLeast(10,0,0))
|
||||
{
|
||||
u64 out_size;
|
||||
return svcQueryMemoryMapping(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)
|
||||
{
|
||||
_svcQueryMemoryMappingFallback(&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)
|
||||
{
|
||||
_svcQueryMemoryMappingFallback(&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;
|
||||
}
|
||||
|
||||
if (!g_act_base)
|
||||
{
|
||||
_svcQueryMemoryMappingFallback(&g_act_base, 0x6000C000ul, 0x1000);
|
||||
}
|
||||
|
||||
if(!g_act_base)
|
||||
{
|
||||
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 emc_freq = g_mem_freq / 1000;
|
||||
|
||||
// Check if actmon is disabled
|
||||
if (!(ACTMON(ACTMON_GLB_STATUS) & ACTMON_MCALL_MON_ACT))
|
||||
{
|
||||
ACTMON(ACTMON_GLB_PERIOD_CTRL) = ACTMON_GLB_PERIOD_SAMPLE(ACTMON_PERIOD_MS);
|
||||
_actmon_dev_enable(ACTMON_DEV_MC_ALL, emc_freq, 256 * 4);
|
||||
}
|
||||
|
||||
// Check if actmon is disabled
|
||||
if (!(ACTMON(ACTMON_GLB_STATUS) & ACTMON_MCCPU_MON_ACT))
|
||||
_actmon_dev_enable(ACTMON_DEV_MC_CPU, emc_freq, 256 * 4);
|
||||
|
||||
// Get 1000 -> 100.0.
|
||||
g_emc_lall = (u64)_actmon_dev_get_count_avg(ACTMON_DEV_MC_ALL) * 10 * 100 / (emc_freq * ACTMON_PERIOD_MS);
|
||||
g_emc_lcpu = (u64)_actmon_dev_get_count_avg(ACTMON_DEV_MC_CPU) * 10 * 100 / (emc_freq * ACTMON_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
u32 t210EmcLoadAll()
|
||||
{
|
||||
_clock_update_freqs();
|
||||
return g_emc_lall;
|
||||
}
|
||||
|
||||
u32 t210EmcLoadCpu()
|
||||
{
|
||||
_clock_update_freqs();
|
||||
return g_emc_lcpu;
|
||||
}
|
||||
102
Source/sys-clk/sysmodule/lib/nxExt/src/tmp451.c
Normal file
102
Source/sys-clk/sysmodule/lib/nxExt/src/tmp451.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SOC/PCB Temperature driver for Nintendo Switch's TI TMP451
|
||||
*
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2024 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/tmp451.h"
|
||||
#include "nxExt/i2c.h"
|
||||
|
||||
#define TMP451_WAIT_NS 1000000000UL
|
||||
|
||||
#define TMP451_PCB_TEMP_REG 0x00
|
||||
#define TMP451_SOC_TEMP_REG 0x01
|
||||
|
||||
#define TMP451_SOC_TMP_DEC_REG 0x10
|
||||
#define TMP451_PCB_TMP_DEC_REG 0x15
|
||||
|
||||
static I2cSession g_i2c_session;
|
||||
static u64 g_update_ticks = 0;
|
||||
static s32 g_temp_pcb = 0;
|
||||
static s32 g_temp_soc = 0;
|
||||
|
||||
static Result _tmp451_get_temp(u8 reg, u8 dec_reg, s32* out)
|
||||
{
|
||||
u8 val = 0;
|
||||
Result rc = i2csessionExtRegReceive(&g_i2c_session, reg, &val, sizeof(val));
|
||||
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
*out = (s32)val * 1000;
|
||||
rc = i2csessionExtRegReceive(&g_i2c_session, dec_reg, &val, sizeof(val));
|
||||
}
|
||||
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
*out += ((s32)(val >> 4) * 625) / 10;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _tmp451_update()
|
||||
{
|
||||
u64 ticks = armGetSystemTick();
|
||||
if(armTicksToNs(ticks - g_update_ticks) <= TMP451_WAIT_NS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_update_ticks = ticks;
|
||||
|
||||
if(!serviceIsActive(&g_i2c_session.s))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tmp451_get_temp(TMP451_PCB_TEMP_REG, TMP451_PCB_TMP_DEC_REG, &g_temp_pcb);
|
||||
_tmp451_get_temp(TMP451_SOC_TEMP_REG, TMP451_SOC_TMP_DEC_REG, &g_temp_soc);
|
||||
}
|
||||
|
||||
Result tmp451Initialize(void)
|
||||
{
|
||||
Result rc = i2cInitialize();
|
||||
|
||||
if(R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = i2cOpenSession(&g_i2c_session, I2cDevice_Tmp451);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void tmp451Exit(void)
|
||||
{
|
||||
i2csessionClose(&g_i2c_session);
|
||||
i2cExit();
|
||||
}
|
||||
|
||||
s32 tmp451TempPcb(void)
|
||||
{
|
||||
_tmp451_update();
|
||||
return g_temp_pcb;
|
||||
}
|
||||
|
||||
s32 tmp451TempSoc(void)
|
||||
{
|
||||
_tmp451_update();
|
||||
return g_temp_soc;
|
||||
}
|
||||
Reference in New Issue
Block a user