sysclk: remove old hocclk, bump version
This commit is contained in:
2
Source/hoc-clk/sysmodule/.gitignore
vendored
Normal file
2
Source/hoc-clk/sysmodule/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/out
|
||||
/build
|
||||
164
Source/hoc-clk/sysmodule/Makefile
Normal file
164
Source/hoc-clk/sysmodule/Makefile
Normal file
@@ -0,0 +1,164 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := horizon-oc
|
||||
BUILD := build
|
||||
OUTDIR := out
|
||||
RESOURCES := res
|
||||
SOURCES := src src/nx/ipc ../common/src src/board
|
||||
DATA := data
|
||||
INCLUDES := ../common/include
|
||||
EXEFS_SRC := exefs_src
|
||||
LIBNAMES := minIni nxExt
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
DEFINES := -DDISABLE_IPC -DTARGET="\"$(TARGET)\"" -DTARGET_VERSION="\"$(TARGET_VERSION)\""
|
||||
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -Os -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := $(foreach lib,$(LIBNAMES),-l$(lib)) -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX) $(foreach lib,$(LIBNAMES),$(TOPDIR)/lib/$(lib))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(OUTDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||
|
||||
export APP_JSON := $(TOPDIR)/perms.json
|
||||
|
||||
.PHONY: $(BUILD) clean clean-libs clean-build all libs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
libs:
|
||||
@$(foreach lib,$(LIBNAMES),$(MAKE) --no-print-directory -C $(TOPDIR)/lib/$(lib) && ) true
|
||||
|
||||
$(LIBNAMES):
|
||||
@echo $@
|
||||
|
||||
$(BUILD): libs
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean-libs:
|
||||
@echo clean libs $(LIBNAMES) ...
|
||||
@$(foreach lib,$(LIBNAMES),$(MAKE) -C $(TOPDIR)/lib/$(lib) clean && ) true
|
||||
|
||||
clean-build:
|
||||
@echo clean build ...
|
||||
@rm -fr $(BUILD) $(TARGET).kip $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf $(OUTDIR)
|
||||
|
||||
clean: clean-libs clean-build
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all $(LIBFILES)
|
||||
|
||||
LIBFILES := $(foreach lib,$(LIBNAMES),$(TOPDIR)/lib/$(lib)/lib/lib$(lib).a)
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
all: $(OUTPUT).nsp
|
||||
|
||||
$(OUTPUT).nsp: $(OUTPUT).nso $(OUTPUT).npdm
|
||||
|
||||
$(OUTPUT).elf: $(OFILES) $(LIBFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
13
Source/hoc-clk/sysmodule/lib/minIni/.gitignore
vendored
Normal file
13
Source/hoc-clk/sysmodule/lib/minIni/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Editor files
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Objects
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Lib
|
||||
lib
|
||||
release
|
||||
debug
|
||||
12
Source/hoc-clk/sysmodule/lib/minIni/.gitrepo
Normal file
12
Source/hoc-clk/sysmodule/lib/minIni/.gitrepo
Normal file
@@ -0,0 +1,12 @@
|
||||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/compuphase/minIni
|
||||
branch = master
|
||||
commit = 8ce144c3c287fa4e59f8ed4c405cd8b7e29f189b
|
||||
parent = f32c0b1bca87a6d7e55fb341f8db9ef33b13819f
|
||||
method = merge
|
||||
cmdver = 0.4.0
|
||||
189
Source/hoc-clk/sysmodule/lib/minIni/LICENSE
Normal file
189
Source/hoc-clk/sysmodule/lib/minIni/LICENSE
Normal file
@@ -0,0 +1,189 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
|
||||
EXCEPTION TO THE APACHE 2.0 LICENSE
|
||||
|
||||
As a special exception to the Apache License 2.0 (and referring to the
|
||||
definitions in Section 1 of this license), you may link, statically or
|
||||
dynamically, the "Work" to other modules to produce an executable file
|
||||
containing portions of the "Work", and distribute that executable file
|
||||
in "Object" form under the terms of your choice, without any of the
|
||||
additional requirements listed in Section 4 of the Apache License 2.0.
|
||||
This exception applies only to redistributions in "Object" form (not
|
||||
"Source" form) and only if no modifications have been made to the "Work".
|
||||
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
133
Source/hoc-clk/sysmodule/lib/minIni/Makefile
Normal file
133
Source/hoc-clk/sysmodule/lib/minIni/Makefile
Normal file
@@ -0,0 +1,133 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
SOURCES := dev
|
||||
DATA := data
|
||||
INCLUDES := dev
|
||||
SRC_H_FILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec
|
||||
|
||||
CFLAGS := -g -Wall -Werror \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
$(ARCH) \
|
||||
$(BUILD_CFLAGS)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
CFILES := minIni.c
|
||||
CPPFILES :=
|
||||
SFILES :=
|
||||
BINFILES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
.PHONY: clean all lib/lib$(TARGET).a
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: lib/lib$(TARGET).a
|
||||
|
||||
lib:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
release:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
debug:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
lib/lib$(TARGET).a : lib release $(SOURCES) $(INCLUDES)
|
||||
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
|
||||
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
|
||||
DEPSDIR=$(CURDIR)/release \
|
||||
--no-print-directory -C release \
|
||||
-f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr release debug lib
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT) : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%_bin.h %.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
12
Source/hoc-clk/sysmodule/lib/minIni/NOTICE
Normal file
12
Source/hoc-clk/sysmodule/lib/minIni/NOTICE
Normal file
@@ -0,0 +1,12 @@
|
||||
minIni is a programmer's library to read and write "INI" files in embedded
|
||||
systems. The library takes little resources and can be configured for various
|
||||
kinds of file I/O libraries.
|
||||
|
||||
The method for portable INI file management in minIni is, in part based, on the
|
||||
article "Multiplatform .INI Files" by Joseph J. Graf in the March 1994 issue of
|
||||
Dr. Dobb's Journal.
|
||||
|
||||
The C++ class in minIni.h was contributed by Steven Van Ingelgem.
|
||||
|
||||
The option to compile minIni as a read-only library was contributed by Luca
|
||||
Bassanello.
|
||||
170
Source/hoc-clk/sysmodule/lib/minIni/README.md
Normal file
170
Source/hoc-clk/sysmodule/lib/minIni/README.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# minIni
|
||||
minIni is a portable and configurable library for reading and writing ".INI" files. At 830 lines of commented source
|
||||
code
|
||||
(version 1.2), minIni truly is a "mini" INI file parser, especially considering its features.
|
||||
|
||||
The library does not require the file I/O functions from the standard C/C++ library, but instead lets you configure
|
||||
the file I/O interface to use via macros. minIni uses limited stack space and does not use dynamic memory (malloc and
|
||||
friends) at all.
|
||||
|
||||
Some minor variations on standard INI files are supported too, notably minIni supports INI files that lack sections.
|
||||
|
||||
|
||||
# Acknowledgement
|
||||
|
||||
minIni is derived from an earlier INI file parser (which I wrote) for desktop systems.
|
||||
|
||||
In turn, that earlier parser was a re-write of the code from the article "Multiplatform .INI Files" by Joseph J. Graf
|
||||
in the March 1994 issue of Dr. Dobb's Journal. In other words, minIni has its roots in the work of Joseph Graf (even
|
||||
though the code has been almost completely re-written).
|
||||
|
||||
|
||||
# Features
|
||||
|
||||
minIni is a programmer's library to read and write "INI" files in embedded systems. minIni takes little resources,
|
||||
can be configured for various kinds of file I/O libraries and provides functionality for reading, writing and
|
||||
deleting keys from an INI file.
|
||||
|
||||
Although the main feature of minIni is that it is small and minimal, it has a few other features:
|
||||
|
||||
* minIni supports reading keys that are outside a section, and it thereby supports configuration files that do not use sections (but that are otherwise compatible with INI files).
|
||||
* You may use a colon to separate key and value; the colon is equivalent to the equal sign. That is, the strings "Name: Value" and "Name=Value" have the same meaning.
|
||||
* The hash character ("#") is an alternative for the semicolon to start a comment. Trailing comments (i.e. behind a key/value pair on a line) are allowed.
|
||||
* Leading and trailing white space around key names and values is ignored.
|
||||
* When writing a value that contains a comment character (";" or "#"), that value will automatically be put between double quotes; when reading the value, these quotes are removed. When a double-quote itself appears in the setting, these characters are escaped.
|
||||
* Section and key enumeration are supported.
|
||||
* You can optionally set the line termination (for text files) that minIni will use. (This is a compile-time setting, not a run-time setting.)
|
||||
* Since writing speed is much lower than reading speed in Flash memory (SD/MMC cards, USB memory sticks), minIni minimizes "file writes" at the expense of double "file reads".
|
||||
* The memory footprint is deterministic. There is no dynamic memory allocation.
|
||||
|
||||
## INI file reading paradigms
|
||||
|
||||
There are two approaches to reading settings from an INI file. One way is to call a function, such as
|
||||
GetProfileString() for every section and key that you need. This is especially convenient if there is a large
|
||||
INI file, but you only need a few settings from that file at any time —especially if the INI file can also
|
||||
change while your program runs. This is the approach that the Microsoft Windows API uses.
|
||||
|
||||
The above procedure is quite inefficient, however, when you need to retrieve quite a few settings in a row from
|
||||
the INI file —especially if the INI file is not cached in memory (which it isn't, in minIni). A different approach
|
||||
to getting settings from an INI file is to call a "parsing" function and let that function call the application
|
||||
back with the section and key names plus the associated data. XML parsing libraries often use this approach; see
|
||||
for example the Expat library.
|
||||
|
||||
minIni supports both approaches. For reading a single setting, use functions like ini_gets(). For the callback
|
||||
approach, implement a callback and call ini_browse(). See the minIni manual for details.
|
||||
|
||||
|
||||
# INI file syntax
|
||||
|
||||
INI files are best known from Microsoft Windows, but they are also used with applications that run on other
|
||||
platforms (although their file extension is sometimes ".cfg" instead of ".ini").
|
||||
|
||||
INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section)
|
||||
and the value must fit on a single line. INI files are commonly separated into sections —in minIni, this is
|
||||
optional. A section is a name between square brackets, like "[Network]" in the example below.
|
||||
|
||||
```
|
||||
[Network]
|
||||
hostname=My Computer
|
||||
address=dhcp
|
||||
dns = 192.168.1.1
|
||||
```
|
||||
|
||||
In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key
|
||||
and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the
|
||||
equal sign for the key/value delimiter.
|
||||
|
||||
Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing
|
||||
spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the
|
||||
minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if
|
||||
the value to write contains trailing white space (or special characters).
|
||||
|
||||
minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a
|
||||
section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing
|
||||
bracket "]" of a section name.
|
||||
|
||||
Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line.
|
||||
A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments
|
||||
are extensions of minIni).
|
||||
|
||||
For more details on the format, please see http://en.wikipedia.org/wiki/INI_file.
|
||||
|
||||
|
||||
# Adapting minIni to a file system
|
||||
|
||||
The minIni library must be configured for a platform with the help of a so- called "glue file". This glue file
|
||||
contains macros (and possibly functions) that map file reading and writing functions used by the minIni library
|
||||
to those provided by the operating system. The glue file must be called "minGlue.h".
|
||||
|
||||
To get you started, the minIni distribution comes with the following example glue files:
|
||||
|
||||
* a glue file that maps to the standard C/C++ library (specifically the file I/O functions from the "stdio" package),
|
||||
* a glue file for Microchip's "Memory Disk Drive File System Library" (see http://www.microchip.com/),
|
||||
* a glue file for the FAT library provided with the CCS PIC compiler (see http://www.ccsinfo.com/)
|
||||
* a glue file for the EFS Library (EFSL, http://www.efsl.be/),
|
||||
* and a glue file for the FatFs and Petit-FatFs libraries (http://elm-chan.org/fsw/ff/00index_e.html).
|
||||
|
||||
The minIni library does not rely on the availability of a standard C library, because embedded operating systems
|
||||
may have limited support for file I/O. Even on full operating systems, separating the file I/O from the INI format
|
||||
parsing carries advantages, because it allows you to cache the INI file and thereby enhance performance.
|
||||
|
||||
The glue file must specify the type that identifies a file, whether it is a handle or a pointer. For the standard
|
||||
C/C++ file I/O library, this would be:
|
||||
|
||||
```C
|
||||
#define INI_FILETYPE FILE*
|
||||
```
|
||||
|
||||
If you are not using the standard C/C++ file I/O library, chances are that you need a different handle or
|
||||
"structure" to identify the storage than the ubiquitous "FILE*" type. For example, the glue file for the FatFs
|
||||
library uses the following declaration:
|
||||
|
||||
```C
|
||||
#define INI_FILETYPE FIL
|
||||
```
|
||||
|
||||
The minIni functions declare variables of this INI_FILETYPE type and pass these variables to sub-functions
|
||||
(including the glue interface functions) by reference.
|
||||
|
||||
For "write support", another type that must be defined is for variables that hold the "current position" in a
|
||||
file. For the standard C/C++ I/O library, this is "fpos_t".
|
||||
|
||||
Another item that needs to be configured is the buffer size. The functions in the minIni library allocate this
|
||||
buffer on the stack, so the buffer size is directly related to the stack usage. In addition, the buffer size
|
||||
determines the maximum line length that is supported in the INI file and the maximum path name length for the
|
||||
temporary file. For example, minGlue.h could contain the definition:
|
||||
|
||||
```C
|
||||
#define INI_BUFFERSIZE 512
|
||||
```
|
||||
|
||||
The above macro limits the line length of the INI files supported by minIni to 512 characters.
|
||||
|
||||
The temporary file is only used when writing to INI files. The minIni routines copy/change the INI file to a
|
||||
temporary file and then rename that temporary file to the original file. This approach uses the least amount of
|
||||
memory. The path name of the temporary file is the same as the input file, but with the last character set to a
|
||||
tilde ("~").
|
||||
|
||||
Below is an example of a glue file (this is the one that maps to the C/C++ "stdio" library).
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
|
||||
#define INI_FILETYPE FILE*
|
||||
#define ini_openread(filename,file) ((*(file) = fopen((filename),"r")) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"w")) != NULL)
|
||||
#define ini_close(file) (fclose(*(file)) == 0)
|
||||
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
|
||||
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
|
||||
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
|
||||
#define ini_remove(filename) (remove(filename) == 0)
|
||||
|
||||
#define INI_FILEPOS fpos_t
|
||||
#define ini_tell(file,pos) (fgetpos(*(file), (pos)) == 0)
|
||||
#define ini_seek(file,pos) (fsetpos(*(file), (pos)) == 0)
|
||||
```
|
||||
|
||||
As you can see, a glue file is mostly a set of macros that wraps one function definition around another.
|
||||
|
||||
The glue file may contain more settings, for support of rational numbers, to explicitly set the line termination
|
||||
character(s), or to disable write support (for example). See the manual that comes with the archive for the details.
|
||||
37
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-FatFs.h
Normal file
37
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-FatFs.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Glue functions for the minIni library, based on the FatFs and Petit-FatFs
|
||||
* libraries, see http://elm-chan.org/fsw/ff/00index_e.html
|
||||
*
|
||||
* By CompuPhase, 2008-2012
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*
|
||||
* (The FatFs and Petit-FatFs libraries are copyright by ChaN and licensed at
|
||||
* its own terms.)
|
||||
*/
|
||||
|
||||
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
|
||||
|
||||
/* You must set _USE_STRFUNC to 1 or 2 in the include file ff.h (or tff.h)
|
||||
* to enable the "string functions" fgets() and fputs().
|
||||
*/
|
||||
#include "ff.h" /* include tff.h for Tiny-FatFs */
|
||||
|
||||
#define INI_FILETYPE FIL
|
||||
#define ini_openread(filename,file) (f_open((file), (filename), FA_READ+FA_OPEN_EXISTING) == FR_OK)
|
||||
#define ini_openwrite(filename,file) (f_open((file), (filename), FA_WRITE+FA_CREATE_ALWAYS) == FR_OK)
|
||||
#define ini_close(file) (f_close(file) == FR_OK)
|
||||
#define ini_read(buffer,size,file) f_gets((buffer), (size),(file))
|
||||
#define ini_write(buffer,file) f_puts((buffer), (file))
|
||||
#define ini_remove(filename) (f_unlink(filename) == FR_OK)
|
||||
|
||||
#define INI_FILEPOS DWORD
|
||||
#define ini_tell(file,pos) (*(pos) = f_tell((file)))
|
||||
#define ini_seek(file,pos) (f_lseek((file), *(pos)) == FR_OK)
|
||||
|
||||
static int ini_rename(TCHAR *source, const TCHAR *dest)
|
||||
{
|
||||
/* Function f_rename() does not allow drive letters in the destination file */
|
||||
char *drive = strchr(dest, ':');
|
||||
drive = (drive == NULL) ? dest : drive + 1;
|
||||
return (f_rename(source, drive) == FR_OK);
|
||||
}
|
||||
64
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-ccs.h
Normal file
64
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-ccs.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* minIni glue functions for FAT library by CCS, Inc. (as provided with their
|
||||
* PIC MCU compiler)
|
||||
*
|
||||
* By CompuPhase, 2011-2012
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*
|
||||
* (The FAT library is copyright (c) 2007 Custom Computer Services, and
|
||||
* licensed at its own terms.)
|
||||
*/
|
||||
|
||||
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
|
||||
|
||||
#ifndef FAT_PIC_C
|
||||
#error FAT library must be included before this module
|
||||
#endif
|
||||
#define const /* keyword not supported by CCS */
|
||||
|
||||
#define INI_FILETYPE FILE
|
||||
#define ini_openread(filename,file) (fatopen((filename), "r", (file)) == GOODEC)
|
||||
#define ini_openwrite(filename,file) (fatopen((filename), "w", (file)) == GOODEC)
|
||||
#define ini_close(file) (fatclose((file)) == 0)
|
||||
#define ini_read(buffer,size,file) (fatgets((buffer), (size), (file)) != NULL)
|
||||
#define ini_write(buffer,file) (fatputs((buffer), (file)) == GOODEC)
|
||||
#define ini_remove(filename) (rm_file((filename)) == 0)
|
||||
|
||||
#define INI_FILEPOS fatpos_t
|
||||
#define ini_tell(file,pos) (fatgetpos((file), (pos)) == 0)
|
||||
#define ini_seek(file,pos) (fatsetpos((file), (pos)) == 0)
|
||||
|
||||
#ifndef INI_READONLY
|
||||
/* CCS FAT library lacks a rename function, so instead we copy the file to the
|
||||
* new name and delete the old file
|
||||
*/
|
||||
static int ini_rename(char *source, char *dest)
|
||||
{
|
||||
FILE fr, fw;
|
||||
int n;
|
||||
|
||||
if (fatopen(source, "r", &fr) != GOODEC)
|
||||
return 0;
|
||||
if (rm_file(dest) != 0)
|
||||
return 0;
|
||||
if (fatopen(dest, "w", &fw) != GOODEC)
|
||||
return 0;
|
||||
|
||||
/* With some "insider knowledge", we can save some memory: the "source"
|
||||
* parameter holds a filename that was built from the "dest" parameter. It
|
||||
* was built in a local buffer with the size INI_BUFFERSIZE. We can reuse
|
||||
* this buffer for copying the file.
|
||||
*/
|
||||
while (n=fatread(source, 1, INI_BUFFERSIZE, &fr))
|
||||
fatwrite(source, 1, n, &fw);
|
||||
|
||||
fatclose(&fr);
|
||||
fatclose(&fw);
|
||||
|
||||
/* Now we need to delete the source file. However, we have garbled the buffer
|
||||
* that held the filename of the source. So we need to build it again.
|
||||
*/
|
||||
ini_tempname(source, dest, INI_BUFFERSIZE);
|
||||
return rm_file(source) == 0;
|
||||
}
|
||||
#endif
|
||||
63
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-efsl.h
Normal file
63
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-efsl.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* Glue functions for the minIni library, based on the EFS Library, see
|
||||
* http://www.efsl.be/
|
||||
*
|
||||
* By CompuPhase, 2008-2012
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*
|
||||
* (EFSL is copyright 2005-2006 Lennart Ysboodt and Michael De Nil, and
|
||||
* licensed under the GPL with an exception clause for static linking.)
|
||||
*/
|
||||
|
||||
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
|
||||
#define INI_LINETERM "\r\n" /* set line termination explicitly */
|
||||
|
||||
#include "efs.h"
|
||||
extern EmbeddedFileSystem g_efs;
|
||||
|
||||
#define INI_FILETYPE EmbeddedFile
|
||||
#define ini_openread(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'r') == 0)
|
||||
#define ini_openwrite(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'w') == 0)
|
||||
#define ini_close(file) file_fclose(file)
|
||||
#define ini_read(buffer,size,file) (file_read((file), (size), (buffer)) > 0)
|
||||
#define ini_write(buffer,file) (file_write((file), strlen(buffer), (char*)(buffer)) > 0)
|
||||
#define ini_remove(filename) rmfile(&g_efs.myFs, (char*)(filename))
|
||||
|
||||
#define INI_FILEPOS euint32
|
||||
#define ini_tell(file,pos) (*(pos) = (file)->FilePtr))
|
||||
#define ini_seek(file,pos) file_setpos((file), (*pos))
|
||||
|
||||
#if ! defined INI_READONLY
|
||||
/* EFSL lacks a rename function, so instead we copy the file to the new name
|
||||
* and delete the old file
|
||||
*/
|
||||
static int ini_rename(char *source, const char *dest)
|
||||
{
|
||||
EmbeddedFile fr, fw;
|
||||
int n;
|
||||
|
||||
if (file_fopen(&fr, &g_efs.myFs, source, 'r') != 0)
|
||||
return 0;
|
||||
if (rmfile(&g_efs.myFs, (char*)dest) != 0)
|
||||
return 0;
|
||||
if (file_fopen(&fw, &g_efs.myFs, (char*)dest, 'w') != 0)
|
||||
return 0;
|
||||
|
||||
/* With some "insider knowledge", we can save some memory: the "source"
|
||||
* parameter holds a filename that was built from the "dest" parameter. It
|
||||
* was built in buffer and this buffer has the size INI_BUFFERSIZE. We can
|
||||
* reuse this buffer for copying the file.
|
||||
*/
|
||||
while (n=file_read(&fr, INI_BUFFERSIZE, source))
|
||||
file_write(&fw, n, source);
|
||||
|
||||
file_fclose(&fr);
|
||||
file_fclose(&fw);
|
||||
|
||||
/* Now we need to delete the source file. However, we have garbled the buffer
|
||||
* that held the filename of the source. So we need to build it again.
|
||||
*/
|
||||
ini_tempname(source, dest, INI_BUFFERSIZE);
|
||||
return rmfile(&g_efs.myFs, source) == 0;
|
||||
}
|
||||
#endif
|
||||
26
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-ffs.h
Normal file
26
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-ffs.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Glue functions for the minIni library, based on the "FAT Filing System"
|
||||
* library by embedded-code.com
|
||||
*
|
||||
* By CompuPhase, 2008-2012
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*
|
||||
* (The "FAT Filing System" library itself is copyright embedded-code.com, and
|
||||
* licensed at its own terms.)
|
||||
*/
|
||||
|
||||
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
|
||||
#include <mem-ffs.h>
|
||||
|
||||
#define INI_FILETYPE FFS_FILE*
|
||||
#define ini_openread(filename,file) ((*(file) = ffs_fopen((filename),"r")) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = ffs_fopen((filename),"w")) != NULL)
|
||||
#define ini_close(file) (ffs_fclose(*(file)) == 0)
|
||||
#define ini_read(buffer,size,file) (ffs_fgets((buffer),(size),*(file)) != NULL)
|
||||
#define ini_write(buffer,file) (ffs_fputs((buffer),*(file)) >= 0)
|
||||
#define ini_rename(source,dest) (ffs_rename((source), (dest)) == 0)
|
||||
#define ini_remove(filename) (ffs_remove(filename) == 0)
|
||||
|
||||
#define INI_FILEPOS long
|
||||
#define ini_tell(file,pos) (ffs_fgetpos(*(file), (pos)) == 0)
|
||||
#define ini_seek(file,pos) (ffs_fsetpos(*(file), (pos)) == 0)
|
||||
58
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-mdd.h
Normal file
58
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-mdd.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* minIni glue functions for Microchip's "Memory Disk Drive" file system
|
||||
* library, as presented in Microchip application note AN1045.
|
||||
*
|
||||
* By CompuPhase, 2011-2014
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*
|
||||
* (The "Microchip Memory Disk Drive File System" is copyright (c) Microchip
|
||||
* Technology Incorporated, and licensed at its own terms.)
|
||||
*/
|
||||
|
||||
#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */
|
||||
|
||||
#include "MDD File System\fsio.h"
|
||||
#include <string.h>
|
||||
|
||||
#define INI_FILETYPE FSFILE*
|
||||
#define ini_openread(filename,file) ((*(file) = FSfopen((filename),FS_READ)) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = FSfopen((filename),FS_WRITE)) != NULL)
|
||||
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),FS_READPLUS)) != NULL)
|
||||
#define ini_close(file) (FSfclose(*(file)) == 0)
|
||||
#define ini_write(buffer,file) (FSfwrite((buffer), 1, strlen(buffer), (*file)) > 0)
|
||||
#define ini_remove(filename) (FSremove((filename)) == 0)
|
||||
|
||||
#define INI_FILEPOS long int
|
||||
#define ini_tell(file,pos) (*(pos) = FSftell(*(file)))
|
||||
#define ini_seek(file,pos) (FSfseek(*(file), *(pos), SEEK_SET) == 0)
|
||||
|
||||
/* Since the Memory Disk Drive file system library reads only blocks of files,
|
||||
* the function to read a text line does so by "over-reading" a block of the
|
||||
* of the maximum size and truncating it behind the end-of-line.
|
||||
*/
|
||||
static int ini_read(char *buffer, int size, INI_FILETYPE *file)
|
||||
{
|
||||
size_t numread = size;
|
||||
char *eol;
|
||||
|
||||
if ((numread = FSfread(buffer, 1, size, *file)) == 0)
|
||||
return 0; /* at EOF */
|
||||
if ((eol = strchr(buffer, '\n')) == NULL)
|
||||
eol = strchr(buffer, '\r');
|
||||
if (eol != NULL) {
|
||||
/* terminate the buffer */
|
||||
*++eol = '\0';
|
||||
/* "unread" the data that was read too much */
|
||||
FSfseek(*file, - (int)(numread - (size_t)(eol - buffer)), SEEK_CUR);
|
||||
} /* if */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef INI_READONLY
|
||||
static int ini_rename(const char *source, const char *dest)
|
||||
{
|
||||
FSFILE* ftmp = FSfopen((source), FS_READ);
|
||||
FSrename((dest), ftmp);
|
||||
return FSfclose(ftmp) == 0;
|
||||
}
|
||||
#endif
|
||||
31
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-stdio.h
Normal file
31
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue-stdio.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Glue functions for the minIni library, based on the C/C++ stdio library
|
||||
*
|
||||
* Or better said: this file contains macros that maps the function interface
|
||||
* used by minIni to the standard C/C++ file I/O functions.
|
||||
*
|
||||
* By CompuPhase, 2008-2014
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*/
|
||||
|
||||
/* map required file I/O types and functions to the standard C library */
|
||||
#include <stdio.h>
|
||||
|
||||
#define INI_FILETYPE FILE*
|
||||
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
|
||||
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
|
||||
#define ini_close(file) (fclose(*(file)) == 0)
|
||||
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
|
||||
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
|
||||
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
|
||||
#define ini_remove(filename) (remove(filename) == 0)
|
||||
|
||||
#define INI_FILEPOS long int
|
||||
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
|
||||
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
|
||||
|
||||
/* for floating-point support, define additional types and functions */
|
||||
#define INI_REAL float
|
||||
#define ini_ftoa(string,value) sprintf((string),"%f",(value))
|
||||
#define ini_atof(string) (INI_REAL)strtod((string),NULL)
|
||||
35
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue.h
Normal file
35
Source/hoc-clk/sysmodule/lib/minIni/dev/minGlue.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Glue functions for the minIni library, based on the C/C++ stdio library
|
||||
*
|
||||
* Or better said: this file contains macros that maps the function interface
|
||||
* used by minIni to the standard C/C++ file I/O functions.
|
||||
*
|
||||
* By CompuPhase, 2008-2014
|
||||
* This "glue file" is in the public domain. It is distributed without
|
||||
* warranties or conditions of any kind, either express or implied.
|
||||
*/
|
||||
|
||||
/* map required file I/O types and functions to the standard C library */
|
||||
#include <stdio.h>
|
||||
|
||||
#define INI_FILETYPE FILE*
|
||||
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
|
||||
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
|
||||
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
|
||||
#define ini_close(file) (fclose(*(file)) == 0)
|
||||
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
|
||||
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
|
||||
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
|
||||
#define ini_remove(filename) (remove(filename) == 0)
|
||||
|
||||
#define INI_FILEPOS long int
|
||||
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
|
||||
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
|
||||
|
||||
/* for floating-point support, define additional types and functions */
|
||||
//#define INI_REAL float
|
||||
//#define ini_ftoa(string,value) sprintf((string),"%f",(value))
|
||||
//#define ini_atof(string) (INI_REAL)strtod((string),NULL)
|
||||
|
||||
#define INI_ANSIONLY
|
||||
#define INI_LINETERM "\n"
|
||||
#define PORTABLE_STRNICMP
|
||||
1009
Source/hoc-clk/sysmodule/lib/minIni/dev/minIni.c
Normal file
1009
Source/hoc-clk/sysmodule/lib/minIni/dev/minIni.c
Normal file
File diff suppressed because it is too large
Load Diff
68
Source/hoc-clk/sysmodule/lib/minIni/dev/minIni.h
Normal file
68
Source/hoc-clk/sysmodule/lib/minIni/dev/minIni.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
|
||||
*
|
||||
* Copyright (c) CompuPhase, 2008-2017
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $
|
||||
*/
|
||||
#ifndef MININI_H
|
||||
#define MININI_H
|
||||
|
||||
#include "minGlue.h"
|
||||
|
||||
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
|
||||
#include <tchar.h>
|
||||
#define mTCHAR TCHAR
|
||||
#else
|
||||
/* force TCHAR to be "char", but only for minIni */
|
||||
#define mTCHAR char
|
||||
#endif
|
||||
|
||||
#if !defined INI_BUFFERSIZE
|
||||
#define INI_BUFFERSIZE 512
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
|
||||
long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
|
||||
int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
|
||||
|
||||
#if defined INI_REAL
|
||||
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
|
||||
#endif
|
||||
|
||||
#if !defined INI_READONLY
|
||||
int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
|
||||
int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
|
||||
int ini_putsection(const mTCHAR *Section, const mTCHAR **Keys, const mTCHAR **Values, const mTCHAR *Filename);
|
||||
#if defined INI_REAL
|
||||
int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
|
||||
#endif
|
||||
#endif /* INI_READONLY */
|
||||
|
||||
#if !defined INI_NOBROWSE
|
||||
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData);
|
||||
int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename);
|
||||
#endif /* INI_NOBROWSE */
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MININI_H */
|
||||
117
Source/hoc-clk/sysmodule/lib/minIni/dev/test.c
Normal file
117
Source/hoc-clk/sysmodule/lib/minIni/dev/test.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* Simple test program
|
||||
*
|
||||
* gcc -o test test.c minIni.c
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minIni.h"
|
||||
|
||||
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
const char inifile[] = "test.ini";
|
||||
const char inifile2[] = "testplain.ini";
|
||||
|
||||
int Callback(const char *section, const char *key, const char *value, void *userdata)
|
||||
{
|
||||
(void)userdata; /* this parameter is not used in this example */
|
||||
printf(" [%s]\t%s=%s\n", section, key, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char str[100];
|
||||
long n;
|
||||
int s, k;
|
||||
char section[50];
|
||||
|
||||
/* string reading */
|
||||
n = ini_gets("first", "string", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==4 && strcmp(str,"noot")==0);
|
||||
n = ini_gets("second", "string", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==4 && strcmp(str,"mies")==0);
|
||||
n = ini_gets("first", "undefined", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==5 && strcmp(str,"dummy")==0);
|
||||
/* ----- */
|
||||
n = ini_gets("", "string", "dummy", str, sizearray(str), inifile2);
|
||||
assert(n==4 && strcmp(str,"noot")==0);
|
||||
n = ini_gets(NULL, "string", "dummy", str, sizearray(str), inifile2);
|
||||
assert(n==4 && strcmp(str,"noot")==0);
|
||||
/* ----- */
|
||||
printf("1. String reading tests passed\n");
|
||||
|
||||
/* value reading */
|
||||
n = ini_getl("first", "val", -1, inifile);
|
||||
assert(n==1);
|
||||
n = ini_getl("second", "val", -1, inifile);
|
||||
assert(n==2);
|
||||
n = ini_getl("first", "undefined", -1, inifile);
|
||||
assert(n==-1);
|
||||
/* ----- */
|
||||
n = ini_getl(NULL, "val", -1, inifile2);
|
||||
assert(n==1);
|
||||
/* ----- */
|
||||
printf("2. Value reading tests passed\n");
|
||||
|
||||
/* string writing */
|
||||
n = ini_puts("first", "alt", "flagged as \"correct\"", inifile);
|
||||
assert(n==1);
|
||||
n = ini_gets("first", "alt", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==20 && strcmp(str,"flagged as \"correct\"")==0);
|
||||
/* ----- */
|
||||
n = ini_puts("second", "alt", "correct", inifile);
|
||||
assert(n==1);
|
||||
n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==7 && strcmp(str,"correct")==0);
|
||||
/* ----- */
|
||||
n = ini_puts("third", "test", "correct", inifile);
|
||||
assert(n==1);
|
||||
n = ini_gets("third", "test", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==7 && strcmp(str,"correct")==0);
|
||||
/* ----- */
|
||||
n = ini_puts("second", "alt", "overwrite", inifile);
|
||||
assert(n==1);
|
||||
n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==9 && strcmp(str,"overwrite")==0);
|
||||
/* ----- */
|
||||
n = ini_puts("second", "alt", "123456789", inifile);
|
||||
assert(n==1);
|
||||
n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile);
|
||||
assert(n==9 && strcmp(str,"123456789")==0);
|
||||
/* ----- */
|
||||
n = ini_puts(NULL, "alt", "correct", inifile2);
|
||||
assert(n==1);
|
||||
n = ini_gets(NULL, "alt", "dummy", str, sizearray(str), inifile2);
|
||||
assert(n==7 && strcmp(str,"correct")==0);
|
||||
/* ----- */
|
||||
printf("3. String writing tests passed\n");
|
||||
|
||||
/* section/key enumeration */
|
||||
printf("4. Section/key enumeration, file structure follows\n");
|
||||
for (s = 0; ini_getsection(s, section, sizearray(section), inifile) > 0; s++) {
|
||||
printf(" [%s]\n", section);
|
||||
for (k = 0; ini_getkey(section, k, str, sizearray(str), inifile) > 0; k++) {
|
||||
printf("\t%s\n", str);
|
||||
} /* for */
|
||||
} /* for */
|
||||
|
||||
/* browsing through the file */
|
||||
printf("5. browse through all settings, file field list follows\n");
|
||||
ini_browse(Callback, NULL, inifile);
|
||||
|
||||
/* string deletion */
|
||||
n = ini_puts("first", "alt", NULL, inifile);
|
||||
assert(n==1);
|
||||
n = ini_puts("second", "alt", NULL, inifile);
|
||||
assert(n==1);
|
||||
n = ini_puts("third", NULL, NULL, inifile);
|
||||
assert(n==1);
|
||||
/* ----- */
|
||||
n = ini_puts(NULL, "alt", NULL, inifile2);
|
||||
assert(n==1);
|
||||
printf("6. String deletion tests passed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
8
Source/hoc-clk/sysmodule/lib/minIni/dev/test.ini
Normal file
8
Source/hoc-clk/sysmodule/lib/minIni/dev/test.ini
Normal file
@@ -0,0 +1,8 @@
|
||||
[First]
|
||||
String=noot # trailing commment
|
||||
Val=1
|
||||
|
||||
[Second]
|
||||
Val = 2
|
||||
#comment=3
|
||||
String = mies
|
||||
80
Source/hoc-clk/sysmodule/lib/minIni/dev/test2.cc
Normal file
80
Source/hoc-clk/sysmodule/lib/minIni/dev/test2.cc
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
gcc -o minIni.o -c minIni.c
|
||||
g++ -o test2.o -c test2.cc
|
||||
g++ -o test2 test2.o minIni.o
|
||||
./test2
|
||||
*/
|
||||
|
||||
|
||||
#include <assert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
using namespace std ;
|
||||
|
||||
#include "minIni.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
minIni ini("test.ini");
|
||||
string s;
|
||||
|
||||
/* string reading */
|
||||
s = ini.gets( "first", "string" , "aap" );
|
||||
assert(s == "noot");
|
||||
s = ini.gets( "second", "string" , "aap" );
|
||||
assert(s == "mies");
|
||||
s = ini.gets( "first", "dummy" , "aap" );
|
||||
assert(s == "aap");
|
||||
cout << "1. String reading tests passed" << endl ;
|
||||
|
||||
|
||||
/* value reading */
|
||||
long n;
|
||||
n = ini.getl("first", "val", -1 );
|
||||
assert(n==1);
|
||||
n = ini.getl("second", "val", -1);
|
||||
assert(n==2);
|
||||
n = ini.getl("first", "dummy", -1);
|
||||
assert(n==-1);
|
||||
cout << "2. Value reading tests passed" << endl ;
|
||||
|
||||
|
||||
/* string writing */
|
||||
bool b;
|
||||
b = ini.put("first", "alt", "flagged as \"correct\"");
|
||||
assert(b);
|
||||
s = ini.gets("first", "alt", "aap");
|
||||
assert(s=="flagged as \"correct\"");
|
||||
|
||||
b = ini.put("second", "alt", "correct");
|
||||
assert(b);
|
||||
s = ini.gets("second", "alt", "aap");
|
||||
assert(s=="correct");
|
||||
|
||||
b = ini.put("third", "alt", "correct");
|
||||
assert(b);
|
||||
s = ini.gets("third", "alt", "aap" );
|
||||
assert(s=="correct");
|
||||
cout << "3. String writing tests passed" << endl;
|
||||
|
||||
/* section/key enumeration */
|
||||
cout << "4. section/key enumeration; file contents follows" << endl;
|
||||
string section;
|
||||
for (int is = 0; section = ini.getsection(is), section.length() > 0; is++) {
|
||||
cout << " [" << section.c_str() << "]" << endl;
|
||||
for (int ik = 0; s = ini.getkey(section, ik), s.length() > 0; ik++) {
|
||||
cout << "\t" << s.c_str() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* string deletion */
|
||||
b = ini.del("first", "alt");
|
||||
assert(b);
|
||||
b = ini.del("second", "alt");
|
||||
assert(b);
|
||||
b = ini.del("third");
|
||||
assert(b);
|
||||
cout << "5. string deletion passed " << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
Source/hoc-clk/sysmodule/lib/minIni/dev/testplain.ini
Normal file
3
Source/hoc-clk/sysmodule/lib/minIni/dev/testplain.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
String=noot # trailing commment
|
||||
#comment=3
|
||||
Val=1
|
||||
101
Source/hoc-clk/sysmodule/lib/minIni/dev/wxMinIni.h
Normal file
101
Source/hoc-clk/sysmodule/lib/minIni/dev/wxMinIni.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* minIni - Multi-Platform INI file parser, wxWidgets interface
|
||||
*
|
||||
* Copyright (c) CompuPhase, 2008-2012
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Version: $Id: wxMinIni.h 44 2012-01-04 15:52:56Z thiadmer.riemersma@gmail.com $
|
||||
*/
|
||||
#ifndef WXMININI_H
|
||||
#define WXMININI_H
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include "minIni.h"
|
||||
|
||||
class minIni
|
||||
{
|
||||
public:
|
||||
minIni(const wxString& filename) : iniFilename(filename)
|
||||
{ }
|
||||
|
||||
bool getbool(const wxString& Section, const wxString& Key, bool DefValue=false) const
|
||||
{ return ini_getbool(Section.utf8_str(), Key.utf8_str(), int(DefValue), iniFilename.utf8_str()) != 0; }
|
||||
|
||||
long getl(const wxString& Section, const wxString& Key, long DefValue=0) const
|
||||
{ return ini_getl(Section.utf8_str(), Key.utf8_str(), DefValue, iniFilename.utf8_str()); }
|
||||
|
||||
int geti(const wxString& Section, const wxString& Key, int DefValue=0) const
|
||||
{ return static_cast<int>(ini_getl(Section.utf8_str(), Key.utf8_str(), (long)DefValue, iniFilename.utf8_str())); }
|
||||
|
||||
wxString gets(const wxString& Section, const wxString& Key, const wxString& DefValue=wxT("")) const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_gets(Section.utf8_str(), Key.utf8_str(), DefValue.utf8_str(), buffer, INI_BUFFERSIZE, iniFilename.utf8_str());
|
||||
wxString result = wxString::FromUTF8(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
wxString getsection(int idx) const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.utf8_str());
|
||||
wxString result = wxString::FromUTF8(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
wxString getkey(const wxString& Section, int idx) const
|
||||
{
|
||||
char buffer[INI_BUFFERSIZE];
|
||||
ini_getkey(Section.utf8_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.utf8_str());
|
||||
wxString result = wxString::FromUTF8(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined INI_REAL
|
||||
INI_REAL getf(const wxString& Section, wxString& Key, INI_REAL DefValue=0) const
|
||||
{ return ini_getf(Section.utf8_str(), Key.utf8_str(), DefValue, iniFilename.utf8_str()); }
|
||||
#endif
|
||||
|
||||
#if ! defined INI_READONLY
|
||||
bool put(const wxString& Section, const wxString& Key, long Value) const
|
||||
{ return ini_putl(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; }
|
||||
|
||||
bool put(const wxString& Section, const wxString& Key, int Value) const
|
||||
{ return ini_putl(Section.utf8_str(), Key.utf8_str(), (long)Value, iniFilename.utf8_str()) != 0; }
|
||||
|
||||
bool put(const wxString& Section, const wxString& Key, bool Value) const
|
||||
{ return ini_putl(Section.utf8_str(), Key.utf8_str(), (long)Value, iniFilename.utf8_str()) != 0; }
|
||||
|
||||
bool put(const wxString& Section, const wxString& Key, const wxString& Value) const
|
||||
{ return ini_puts(Section.utf8_str(), Key.utf8_str(), Value.utf8_str(), iniFilename.utf8_str()) != 0; }
|
||||
|
||||
bool put(const wxString& Section, const wxString& Key, const char* Value) const
|
||||
{ return ini_puts(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; }
|
||||
|
||||
#if defined INI_REAL
|
||||
bool put(const wxString& Section, const wxString& Key, INI_REAL Value) const
|
||||
{ return ini_putf(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; }
|
||||
#endif
|
||||
|
||||
bool del(const wxString& Section, const wxString& Key) const
|
||||
{ return ini_puts(Section.utf8_str(), Key.utf8_str(), 0, iniFilename.utf8_str()) != 0; }
|
||||
|
||||
bool del(const wxString& Section) const
|
||||
{ return ini_puts(Section.utf8_str(), 0, 0, iniFilename.utf8_str()) != 0; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
wxString iniFilename;
|
||||
};
|
||||
|
||||
#endif /* WXMININI_H */
|
||||
BIN
Source/hoc-clk/sysmodule/lib/minIni/doc/minIni.pdf
Normal file
BIN
Source/hoc-clk/sysmodule/lib/minIni/doc/minIni.pdf
Normal file
Binary file not shown.
38
Source/hoc-clk/sysmodule/lib/minIni/include/minIni.h
Normal file
38
Source/hoc-clk/sysmodule/lib/minIni/include/minIni.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "../dev/minIni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
13
Source/hoc-clk/sysmodule/lib/nxExt/.gitignore
vendored
Normal file
13
Source/hoc-clk/sysmodule/lib/nxExt/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Editor files
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Objects
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Lib
|
||||
lib
|
||||
release
|
||||
debug
|
||||
132
Source/hoc-clk/sysmodule/lib/nxExt/Makefile
Normal file
132
Source/hoc-clk/sysmodule/lib/nxExt/Makefile
Normal file
@@ -0,0 +1,132 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
SOURCES := src
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec
|
||||
|
||||
CFLAGS := -g -Wall -Werror \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
$(ARCH) \
|
||||
$(BUILD_CFLAGS)
|
||||
|
||||
CFLAGS += $(INCLUDE) -std=gnu11
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
.PHONY: clean all lib/lib$(TARGET).a lib/lib$(TARGET)d.a
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: lib/lib$(TARGET).a lib/lib$(TARGET)d.a
|
||||
|
||||
lib:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
release:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
debug:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
lib/lib$(TARGET).a : lib release $(SOURCES) $(INCLUDES)
|
||||
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
|
||||
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
|
||||
DEPSDIR=$(CURDIR)/release \
|
||||
--no-print-directory -C release \
|
||||
-f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr release debug lib
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT) : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%_bin.h %.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
36
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt.h
Normal file
36
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nxExt/apm_ext.h"
|
||||
#include "nxExt/i2c.h"
|
||||
#include "nxExt/t210.h"
|
||||
#include "nxExt/max17050.h"
|
||||
#include "nxExt/tmp451.h"
|
||||
#include "nxExt/ipc_server.h"
|
||||
#include "nxExt/cpp/lockable_mutex.h"
|
||||
58
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/apm_ext.h
Normal file
58
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/apm_ext.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result apmExtInitialize(void);
|
||||
void apmExtExit(void);
|
||||
|
||||
Result apmExtGetPerformanceMode(u32* out_mode);
|
||||
Result apmExtSysRequestPerformanceMode(u32 mode);
|
||||
Result apmExtGetCurrentPerformanceConfiguration(u32* out_conf);
|
||||
Result apmExtSysRequestPerformanceMode(u32 mode);
|
||||
Result apmExtSysSetCpuBoostMode(u32 mode);
|
||||
|
||||
Result apmExtGetPerformanceMode(u32 *out_mode);
|
||||
Result apmExtGetCurrentPerformanceConfiguration(u32 *out_conf);
|
||||
|
||||
inline bool apmExtIsCPUBoosted(u32 conf_id) { // CPU boosted to 1785 MHz
|
||||
return (conf_id == 0x92220009 || conf_id == 0x9222000A);
|
||||
};
|
||||
inline bool apmExtIsBoostMode(u32 conf_id) { // GPU throttled to 76.8 MHz
|
||||
return (conf_id >= 0x92220009 && conf_id <= 0x9222000C);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <mutex>
|
||||
#include <switch.h>
|
||||
|
||||
class LockableMutex
|
||||
{
|
||||
public:
|
||||
LockableMutex()
|
||||
{
|
||||
mutexInit(&this->m);
|
||||
}
|
||||
|
||||
virtual ~LockableMutex() {}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
mutexLock(&this->m);
|
||||
}
|
||||
|
||||
bool TryLock()
|
||||
{
|
||||
return mutexTryLock(&this->m);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
mutexUnlock(&this->m);
|
||||
}
|
||||
|
||||
// snake_case aliases in order to implement Lockable
|
||||
|
||||
void lock()
|
||||
{
|
||||
this->Lock();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return this->TryLock();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
this->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex m;
|
||||
};
|
||||
|
||||
#endif
|
||||
41
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/i2c.h
Normal file
41
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/i2c.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result i2csessionExtRegReceive(I2cSession* s, u8 in, void* out, u8 out_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#define IPC_SERVER_EXT_RESPONSE_MAX_DATA_SIZE (0x100 - 0x10 - sizeof(IpcServerRawHeader))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 magic;
|
||||
union
|
||||
{
|
||||
u64 cmdId;
|
||||
u64 result;
|
||||
};
|
||||
} IpcServerRawHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SmServiceName srvName;
|
||||
Handle handles[MAX_WAIT_OBJECTS];
|
||||
u32 max;
|
||||
u32 count;
|
||||
} IpcServer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 cmdId;
|
||||
void* ptr;
|
||||
size_t size;
|
||||
} IpcServerRequestData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HipcParsedRequest hipc;
|
||||
IpcServerRequestData data;
|
||||
} IpcServerRequest;
|
||||
|
||||
typedef Result (*IpcServerRequestHandler)(void* userdata, const IpcServerRequest* r, u8* out_data, size_t* out_dataSize);
|
||||
|
||||
Result ipcServerInit(IpcServer* server, const char* name, u32 max_sessions);
|
||||
Result ipcServerExit(IpcServer* server);
|
||||
Result ipcServerProcess(IpcServer* server, IpcServerRequestHandler handler, void* userdata);
|
||||
Result ipcServerParseCommand(const IpcServerRequest* r, size_t* out_datasize, void** out_data, u64* out_cmd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
44
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/max17050.h
Normal file
44
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/max17050.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result max17050Initialize(void);
|
||||
void max17050Exit(void);
|
||||
s32 max17050PowerNow(void);
|
||||
s32 max17050PowerAvg(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
45
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/t210.h
Normal file
45
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/t210.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
u32 t210ClkCpuFreq(void);
|
||||
u32 t210ClkMemFreq(void);
|
||||
u32 t210ClkGpuFreq(void);
|
||||
u32 t210EmcLoadAll(void);
|
||||
u32 t210EmcLoadCpu(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
44
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/tmp451.h
Normal file
44
Source/hoc-clk/sysmodule/lib/nxExt/include/nxExt/tmp451.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result tmp451Initialize(void);
|
||||
void tmp451Exit(void);
|
||||
s32 tmp451TempPcb(void);
|
||||
s32 tmp451TempSoc(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
83
Source/hoc-clk/sysmodule/lib/nxExt/src/apm_ext.c
Normal file
83
Source/hoc-clk/sysmodule/lib/nxExt/src/apm_ext.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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);
|
||||
}
|
||||
45
Source/hoc-clk/sysmodule/lib/nxExt/src/i2c.c
Normal file
45
Source/hoc-clk/sysmodule/lib/nxExt/src/i2c.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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));
|
||||
}
|
||||
221
Source/hoc-clk/sysmodule/lib/nxExt/src/ipc_server.c
Normal file
221
Source/hoc-clk/sysmodule/lib/nxExt/src/ipc_server.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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/hoc-clk/sysmodule/lib/nxExt/src/max17050.c
Normal file
124
Source/hoc-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;
|
||||
}
|
||||
290
Source/hoc-clk/sysmodule/lib/nxExt/src/t210.c
Normal file
290
Source/hoc-clk/sysmodule/lib/nxExt/src/t210.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2023 CTCaer
|
||||
* Copyright (c) 2023 p-sam
|
||||
* Copyright (c) 2026 Souldbminer
|
||||
*
|
||||
* 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_DIV2 0x13
|
||||
#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, u32 multiplier)
|
||||
{
|
||||
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 * multiplier * pto_osc / pto_win;
|
||||
|
||||
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, 1);
|
||||
g_cpu_freq = _clock_get_dev_freq(CLK_PTO_CCLK_G_DIV2, 2);
|
||||
|
||||
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/hoc-clk/sysmodule/lib/nxExt/src/tmp451.c
Normal file
102
Source/hoc-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;
|
||||
}
|
||||
235
Source/hoc-clk/sysmodule/perms.json
Normal file
235
Source/hoc-clk/sysmodule/perms.json
Normal file
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"name": "hoc:clk",
|
||||
"title_id": "0x00FF0000636C6BFF",
|
||||
"title_id_range_min": "0x00FF0000636C6BFF",
|
||||
"title_id_range_max": "0x00FF0000636C6BFF",
|
||||
"main_thread_stack_size": "0x0000C000",
|
||||
"main_thread_priority": 16,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 1,
|
||||
"is_retail": true,
|
||||
"pool_partition": 2,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 3,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
"service_access": [
|
||||
"*"
|
||||
],
|
||||
"service_host": [
|
||||
"hoc:clk"
|
||||
],
|
||||
"kernel_capabilities": [
|
||||
{
|
||||
"type": "kernel_flags",
|
||||
"value": {
|
||||
"highest_thread_priority": 63,
|
||||
"lowest_thread_priority": 16,
|
||||
"lowest_cpu_id": 0,
|
||||
"highest_cpu_id": 3
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x60006000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x57000000",
|
||||
"is_ro": false,
|
||||
"size": "0x01000000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x6000c000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x7000f000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x700e2000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x70110000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x54300000",
|
||||
"size": "0x40000",
|
||||
"is_ro": false,
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "syscalls",
|
||||
"value": {
|
||||
"svcUnknown": "0x00",
|
||||
"svcSetHeapSize": "0x01",
|
||||
"svcSetMemoryPermission": "0x02",
|
||||
"svcSetMemoryAttribute": "0x03",
|
||||
"svcMapMemory": "0x04",
|
||||
"svcUnmapMemory": "0x05",
|
||||
"svcQueryMemory": "0x06",
|
||||
"svcExitProcess": "0x07",
|
||||
"svcCreateThread": "0x08",
|
||||
"svcStartThread": "0x09",
|
||||
"svcExitThread": "0x0a",
|
||||
"svcSleepThread": "0x0b",
|
||||
"svcGetThreadPriority": "0x0c",
|
||||
"svcSetThreadPriority": "0x0d",
|
||||
"svcGetThreadCoreMask": "0x0e",
|
||||
"svcSetThreadCoreMask": "0x0f",
|
||||
"svcGetCurrentProcessorNumber": "0x10",
|
||||
"svcSignalEvent": "0x11",
|
||||
"svcClearEvent": "0x12",
|
||||
"svcMapSharedMemory": "0x13",
|
||||
"svcUnmapSharedMemory": "0x14",
|
||||
"svcCreateTransferMemory": "0x15",
|
||||
"svcCloseHandle": "0x16",
|
||||
"svcResetSignal": "0x17",
|
||||
"svcWaitSynchronization": "0x18",
|
||||
"svcCancelSynchronization": "0x19",
|
||||
"svcArbitrateLock": "0x1a",
|
||||
"svcArbitrateUnlock": "0x1b",
|
||||
"svcWaitProcessWideKeyAtomic": "0x1c",
|
||||
"svcSignalProcessWideKey": "0x1d",
|
||||
"svcGetSystemTick": "0x1e",
|
||||
"svcConnectToNamedPort": "0x1f",
|
||||
"svcSendSyncRequestLight": "0x20",
|
||||
"svcSendSyncRequest": "0x21",
|
||||
"svcSendSyncRequestWithUserBuffer": "0x22",
|
||||
"svcSendAsyncRequestWithUserBuffer": "0x23",
|
||||
"svcGetProcessId": "0x24",
|
||||
"svcGetThreadId": "0x25",
|
||||
"svcBreak": "0x26",
|
||||
"svcOutputDebugString": "0x27",
|
||||
"svcReturnFromException": "0x28",
|
||||
"svcGetInfo": "0x29",
|
||||
"svcFlushEntireDataCache": "0x2a",
|
||||
"svcFlushDataCache": "0x2b",
|
||||
"svcMapPhysicalMemory": "0x2c",
|
||||
"svcUnmapPhysicalMemory": "0x2d",
|
||||
"svcGetFutureThreadInfo": "0x2e",
|
||||
"svcGetLastThreadInfo": "0x2f",
|
||||
"svcGetResourceLimitLimitValue": "0x30",
|
||||
"svcGetResourceLimitCurrentValue": "0x31",
|
||||
"svcSetThreadActivity": "0x32",
|
||||
"svcGetThreadContext3": "0x33",
|
||||
"svcWaitForAddress": "0x34",
|
||||
"svcSignalToAddress": "0x35",
|
||||
"svcUnknown": "0x36",
|
||||
"svcUnknown": "0x37",
|
||||
"svcUnknown": "0x38",
|
||||
"svcUnknown": "0x39",
|
||||
"svcUnknown": "0x3a",
|
||||
"svcUnknown": "0x3b",
|
||||
"svcDumpInfo": "0x3c",
|
||||
"svcDumpInfoNew": "0x3d",
|
||||
"svcUnknown": "0x3e",
|
||||
"svcUnknown": "0x3f",
|
||||
"svcCreateSession": "0x40",
|
||||
"svcAcceptSession": "0x41",
|
||||
"svcReplyAndReceiveLight": "0x42",
|
||||
"svcReplyAndReceive": "0x43",
|
||||
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
||||
"svcCreateEvent": "0x45",
|
||||
"svcUnknown": "0x46",
|
||||
"svcUnknown": "0x47",
|
||||
"svcMapPhysicalMemoryUnsafe": "0x48",
|
||||
"svcUnmapPhysicalMemoryUnsafe": "0x49",
|
||||
"svcSetUnsafeLimit": "0x4a",
|
||||
"svcCreateCodeMemory": "0x4b",
|
||||
"svcControlCodeMemory": "0x4c",
|
||||
"svcSleepSystem": "0x4d",
|
||||
"svcReadWriteRegister": "0x4e",
|
||||
"svcSetProcessActivity": "0x4f",
|
||||
"svcCreateSharedMemory": "0x50",
|
||||
"svcMapTransferMemory": "0x51",
|
||||
"svcUnmapTransferMemory": "0x52",
|
||||
"svcCreateInterruptEvent": "0x53",
|
||||
"svcQueryPhysicalAddress": "0x54",
|
||||
"svcQueryMemoryMapping": "0x55",
|
||||
"svcCreateDeviceAddressSpace": "0x56",
|
||||
"svcAttachDeviceAddressSpace": "0x57",
|
||||
"svcDetachDeviceAddressSpace": "0x58",
|
||||
"svcMapDeviceAddressSpaceByForce": "0x59",
|
||||
"svcMapDeviceAddressSpaceAligned": "0x5a",
|
||||
"svcMapDeviceAddressSpace": "0x5b",
|
||||
"svcUnmapDeviceAddressSpace": "0x5c",
|
||||
"svcInvalidateProcessDataCache": "0x5d",
|
||||
"svcStoreProcessDataCache": "0x5e",
|
||||
"svcFlushProcessDataCache": "0x5f",
|
||||
"svcDebugActiveProcess": "0x60",
|
||||
"svcBreakDebugProcess": "0x61",
|
||||
"svcTerminateDebugProcess": "0x62",
|
||||
"svcGetDebugEvent": "0x63",
|
||||
"svcContinueDebugEvent": "0x64",
|
||||
"svcGetProcessList": "0x65",
|
||||
"svcGetThreadList": "0x66",
|
||||
"svcGetDebugThreadContext": "0x67",
|
||||
"svcSetDebugThreadContext": "0x68",
|
||||
"svcQueryDebugProcessMemory": "0x69",
|
||||
"svcReadDebugProcessMemory": "0x6a",
|
||||
"svcWriteDebugProcessMemory": "0x6b",
|
||||
"svcSetHardwareBreakPoint": "0x6c",
|
||||
"svcGetDebugThreadParam": "0x6d",
|
||||
"svcUnknown": "0x6e",
|
||||
"svcGetSystemInfo": "0x6f",
|
||||
"svcCreatePort": "0x70",
|
||||
"svcManageNamedPort": "0x71",
|
||||
"svcConnectToPort": "0x72",
|
||||
"svcSetProcessMemoryPermission": "0x73",
|
||||
"svcMapProcessMemory": "0x74",
|
||||
"svcUnmapProcessMemory": "0x75",
|
||||
"svcQueryProcessMemory": "0x76",
|
||||
"svcMapProcessCodeMemory": "0x77",
|
||||
"svcUnmapProcessCodeMemory": "0x78",
|
||||
"svcCreateProcess": "0x79",
|
||||
"svcStartProcess": "0x7a",
|
||||
"svcTerminateProcess": "0x7b",
|
||||
"svcGetProcessInfo": "0x7c",
|
||||
"svcCreateResourceLimit": "0x7d",
|
||||
"svcSetResourceLimitLimitValue": "0x7e",
|
||||
"svcCallSecureMonitor": "0x7f"
|
||||
}
|
||||
}, {
|
||||
"type": "min_kernel_version",
|
||||
"value": "0x0060"
|
||||
}, {
|
||||
"type": "handle_table_size",
|
||||
"value": 1023
|
||||
}, {
|
||||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": false,
|
||||
"force_debug_prod": false,
|
||||
"force_debug": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
237
Source/hoc-clk/sysmodule/src/board/board.cpp
Normal file
237
Source/hoc-clk/sysmodule/src/board/board.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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.h>
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
#include <pwm.h>
|
||||
#include <registers.h>
|
||||
#include <battery.h>
|
||||
#include "display_refresh_rate.hpp"
|
||||
#include <rgltr.h>
|
||||
#include <notification.h>
|
||||
|
||||
#include "board.hpp"
|
||||
#include "board_fuse.hpp"
|
||||
#include "board_load.hpp"
|
||||
#include "board_volt.hpp"
|
||||
#include "board_misc.hpp"
|
||||
#include "../soctherm.hpp"
|
||||
#include "../integrations.hpp"
|
||||
#include "../file_utils.hpp"
|
||||
namespace board {
|
||||
|
||||
SysClkSocType gSocType;
|
||||
u8 gDramID;
|
||||
HorizonOCConsoleType gConsoleType = HorizonOCConsoleType_Iowa;
|
||||
FuseData fuseData;
|
||||
u8 speedoBracket;
|
||||
PwmChannelSession iCon;
|
||||
|
||||
u32 fd = 0, fd2 = 0;
|
||||
|
||||
void FetchHardwareInfos() {
|
||||
ReadFuses(fuseData);
|
||||
SetGpuBracket(fuseData.gpuSpeedo, speedoBracket);
|
||||
|
||||
u64 sku = 0, dramID = 0;
|
||||
Result rc = splInitialize();
|
||||
ASSERT_RESULT_OK(rc, "splInitialize");
|
||||
|
||||
rc = splGetConfig(SplConfigItem_HardwareType, &sku);
|
||||
ASSERT_RESULT_OK(rc, "splGetConfig");
|
||||
|
||||
rc = splGetConfig(SplConfigItem_DramId, &dramID);
|
||||
ASSERT_RESULT_OK(rc, "splGetConfig");
|
||||
gDramID = dramID;
|
||||
splExit();
|
||||
|
||||
switch(sku) {
|
||||
case 2 ... 5:
|
||||
gSocType = SysClkSocType_Mariko;
|
||||
break;
|
||||
default:
|
||||
gSocType = SysClkSocType_Erista;
|
||||
}
|
||||
|
||||
if (gSocType == SysClkSocType_Mariko) {
|
||||
CacheGpuVoltTable();
|
||||
}
|
||||
|
||||
gConsoleType = static_cast<HorizonOCConsoleType>(sku);
|
||||
}
|
||||
|
||||
/* TODO: Check for config */
|
||||
void Initialize() {
|
||||
Result rc = 0;
|
||||
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
rc = clkrstInitialize();
|
||||
ASSERT_RESULT_OK(rc, "clkrstInitialize");
|
||||
} else {
|
||||
rc = pcvInitialize();
|
||||
ASSERT_RESULT_OK(rc, "pcvInitialize");
|
||||
}
|
||||
|
||||
rc = apmExtInitialize();
|
||||
ASSERT_RESULT_OK(rc, "apmExtInitialize");
|
||||
|
||||
rc = psmInitialize();
|
||||
ASSERT_RESULT_OK(rc, "psmInitialize");
|
||||
|
||||
if(HOSSVC_HAS_TC) {
|
||||
rc = tcInitialize();
|
||||
ASSERT_RESULT_OK(rc, "tcInitialize");
|
||||
}
|
||||
|
||||
rc = max17050Initialize();
|
||||
ASSERT_RESULT_OK(rc, "max17050Initialize");
|
||||
|
||||
rc = tmp451Initialize();
|
||||
ASSERT_RESULT_OK(rc, "tmp451Initialize");
|
||||
|
||||
Result nvCheck = 1;
|
||||
if (R_SUCCEEDED(nvInitialize())) {
|
||||
nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu");
|
||||
// Result nvCheck_sched = nvOpen(&fd2, "/dev/nvsched-ctrl");
|
||||
// /* This can be improved. */
|
||||
// NvSchedSucceed(nvCheck_sched);
|
||||
|
||||
// if (R_SUCCEEDED(nvCheck_sched)) {
|
||||
// SchedSetFD2(fd2);
|
||||
// }
|
||||
}
|
||||
|
||||
rc = rgltrInitialize();
|
||||
ASSERT_RESULT_OK(rc, "rgltrInitialize");
|
||||
|
||||
rc = pmdmntInitialize();
|
||||
ASSERT_RESULT_OK(rc, "pmdmntInitialize");
|
||||
|
||||
StartLoad(nvCheck, fd);
|
||||
|
||||
batteryInfoInitialize();
|
||||
FetchHardwareInfos();
|
||||
|
||||
soctherm::Initialize();
|
||||
|
||||
Result pwmCheck = 1;
|
||||
if (hosversionAtLeast(6,0,0) && R_SUCCEEDED(pwmInitialize())) {
|
||||
pwmCheck = pwmOpenSession2(&iCon, 0x3D000001);
|
||||
}
|
||||
|
||||
StartMiscThread(pwmCheck, &iCon);
|
||||
|
||||
u64 clkVirtAddr, dsiVirtAddr, outsize;
|
||||
|
||||
rc = svcQueryMemoryMapping(&clkVirtAddr, &outsize, 0x60006000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (clk)");
|
||||
|
||||
rc = svcQueryMemoryMapping(&dsiVirtAddr, &outsize, 0x54300000, 0x40000);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (dsi)");
|
||||
|
||||
display::DisplayRefreshConfig cfg = {.clkVirtAddr = clkVirtAddr, .dsiVirtAddr = dsiVirtAddr, .isLite = (GetConsoleType() == HorizonOCConsoleType_Hoag), .isRetroSUPER = integrations::GetRETROSuperStatus()};
|
||||
display::Initialize(&cfg);
|
||||
|
||||
CacheDfllData();
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
clkrstExit();
|
||||
} else {
|
||||
pcvExit();
|
||||
}
|
||||
|
||||
apmExtExit();
|
||||
psmExit();
|
||||
|
||||
if (HOSSVC_HAS_TC) {
|
||||
tcExit();
|
||||
}
|
||||
|
||||
max17050Exit();
|
||||
tmp451Exit();
|
||||
|
||||
ExitLoad();
|
||||
|
||||
ExitMiscThread();
|
||||
|
||||
pwmChannelSessionClose(&iCon);
|
||||
pwmExit();
|
||||
rgltrExit();
|
||||
batteryInfoExit();
|
||||
pmdmntExit();
|
||||
display::Shutdown();
|
||||
nvExit();
|
||||
}
|
||||
|
||||
SysClkSocType GetSocType() {
|
||||
return gSocType;
|
||||
}
|
||||
|
||||
HorizonOCConsoleType GetConsoleType() {
|
||||
return gConsoleType;
|
||||
}
|
||||
|
||||
u8 GetDramID() {
|
||||
return gDramID;
|
||||
}
|
||||
|
||||
bool IsDram8GB() {
|
||||
SecmonArgs args = {};
|
||||
args.X[0] = 0xF0000002;
|
||||
args.X[1] = MC_REGISTER_BASE + MC_EMEM_CFG_0;
|
||||
svcCallSecureMonitor(&args);
|
||||
|
||||
if (args.X[1] == (MC_REGISTER_BASE + MC_EMEM_CFG_0)) { // if param 1 is identical read failed
|
||||
notification::writeNotification("Horizon OC\nSecmon read failed!\n This may be a hardware issue!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return args.X[1] == 0x00002000 ? true : false;
|
||||
}
|
||||
|
||||
/* TODO: Put this into a different file. */
|
||||
void SetDisplayRefreshDockedState(bool docked) {
|
||||
if (GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
display::SetDockedState(docked);
|
||||
}
|
||||
}
|
||||
|
||||
FuseData *GetFuseData() {
|
||||
return &fuseData;
|
||||
}
|
||||
|
||||
u8 GetGpuSpeedoBracket() {
|
||||
return speedoBracket;
|
||||
}
|
||||
|
||||
bool IsUsingRetroSuperDisplay() {
|
||||
return false; /* stub for now. */
|
||||
}
|
||||
|
||||
}
|
||||
55
Source/hoc-clk/sysmodule/src/board/board.hpp
Normal file
55
Source/hoc-clk/sysmodule/src/board/board.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include "board_fuse.hpp"
|
||||
#include "board_load.hpp"
|
||||
#include "board_name.hpp"
|
||||
#include "board_freq.hpp"
|
||||
#include "board_sensor.hpp"
|
||||
#include "board_volt.hpp"
|
||||
#include "board_profile.hpp"
|
||||
|
||||
#define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0))
|
||||
#define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0))
|
||||
|
||||
namespace board {
|
||||
|
||||
void Initialize();
|
||||
void Exit();
|
||||
SysClkSocType GetSocType();
|
||||
HorizonOCConsoleType GetConsoleType();
|
||||
u8 GetDramID();
|
||||
u8 GetGpuSpeedoBracket();
|
||||
bool IsDram8GB();
|
||||
void SetDisplayRefreshDockedState(bool docked);
|
||||
FuseData *GetFuseData();
|
||||
bool IsUsingRetroSuperDisplay();
|
||||
|
||||
}
|
||||
230
Source/hoc-clk/sysmodule/src/board/board_freq.cpp
Normal file
230
Source/hoc-clk/sysmodule/src/board/board_freq.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <nxExt.h>
|
||||
#include "display_refresh_rate.hpp"
|
||||
#include "board.hpp"
|
||||
#include "board_name.hpp"
|
||||
#include "../errors.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
PcvModule 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);
|
||||
}
|
||||
|
||||
return static_cast<PcvModule>(0);
|
||||
}
|
||||
|
||||
PcvModuleId GetPcvModuleId(SysClkModule sysclkModule) {
|
||||
PcvModuleId pcvModuleId;
|
||||
Result rc = pcvGetModuleId(&pcvModuleId, GetPcvModule(sysclkModule));
|
||||
ASSERT_RESULT_OK(rc, "pcvGetModuleId");
|
||||
|
||||
return pcvModuleId;
|
||||
}
|
||||
|
||||
void ClkrstSetHz(ClkrstSession &session, u32 hz) {
|
||||
ASSERT_RESULT_OK(clkrstSetClockRate(&session, hz), "clkrstSetClockRate");
|
||||
}
|
||||
|
||||
void PcvSetHz(PcvModule moduleID, u32 hz) {
|
||||
ASSERT_RESULT_OK(pcvSetClockRate(moduleID, hz), "pcvSetClockRate");
|
||||
}
|
||||
|
||||
void SetHz(SysClkModule module, u32 hz) {
|
||||
Result rc = 0;
|
||||
bool usesGovenor = module > SysClkModule_MEM;
|
||||
|
||||
|
||||
if (module == HorizonOCModule_Display) {
|
||||
display::SetRate(hz);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usesGovenor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
ClkrstSession session = {};
|
||||
rc = clkrstOpenSession(&session, GetPcvModuleId(module), 3);
|
||||
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
|
||||
ClkrstSetHz(session, hz);
|
||||
|
||||
/* Voltage bug workaround. */
|
||||
if (module == SysClkModule_CPU) {
|
||||
svcSleepThread(250'000);
|
||||
ClkrstSetHz(session, hz);
|
||||
}
|
||||
|
||||
clkrstCloseSession(&session);
|
||||
} else {
|
||||
PcvSetHz(GetPcvModule(module), hz);
|
||||
|
||||
if (module == SysClkModule_CPU) {
|
||||
svcSleepThread(250'000);
|
||||
PcvSetHz(GetPcvModule(module), hz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetDisplayRate(u32 hz) {
|
||||
display::GetRate(&hz, false);
|
||||
return hz;
|
||||
}
|
||||
|
||||
u32 GetHz(SysClkModule module) {
|
||||
Result rc = 0;
|
||||
u32 hz = 0;
|
||||
|
||||
if (module == HorizonOCModule_Display) {
|
||||
return GetDisplayRate(hz);
|
||||
}
|
||||
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
ClkrstSession session = {};
|
||||
|
||||
rc = clkrstOpenSession(&session, GetPcvModuleId(module), 3);
|
||||
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
|
||||
|
||||
rc = clkrstGetClockRate(&session, &hz);
|
||||
ASSERT_RESULT_OK(rc, "clkrstGetClockRate");
|
||||
|
||||
clkrstCloseSession(&session);
|
||||
} else {
|
||||
rc = pcvGetClockRate(GetPcvModule(module), &hz);
|
||||
ASSERT_RESULT_OK(rc, "pcvGetClockRate");
|
||||
}
|
||||
|
||||
return hz;
|
||||
}
|
||||
|
||||
u32 GetRealHz(SysClkModule module) {
|
||||
u32 hz = 0;
|
||||
switch (module) {
|
||||
case SysClkModule_CPU:
|
||||
return t210ClkCpuFreq();
|
||||
case SysClkModule_GPU:
|
||||
return t210ClkGpuFreq();
|
||||
case SysClkModule_MEM:
|
||||
return t210ClkMemFreq();
|
||||
case HorizonOCModule_Display:
|
||||
return GetDisplayRate(hz);
|
||||
return hz;
|
||||
default:
|
||||
ASSERT_ENUM_VALID(SysClkModule, module);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetFreqList(SysClkModule module, u32 *outList, u32 maxCount, u32 *outCount) {
|
||||
Result rc = 0;
|
||||
PcvClockRatesListType type;
|
||||
s32 tmpInMaxCount = maxCount;
|
||||
s32 tmpOutCount = 0;
|
||||
|
||||
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
ClkrstSession session = {};
|
||||
|
||||
rc = clkrstOpenSession(&session, GetPcvModuleId(module), 3);
|
||||
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
|
||||
|
||||
rc = clkrstGetPossibleClockRates(&session, outList, tmpInMaxCount, &type, &tmpOutCount);
|
||||
ASSERT_RESULT_OK(rc, "clkrstGetPossibleClockRates");
|
||||
|
||||
clkrstCloseSession(&session);
|
||||
} else {
|
||||
rc = pcvGetPossibleClockRates(GetPcvModule(module), outList, tmpInMaxCount, &type, &tmpOutCount);
|
||||
ASSERT_RESULT_OK(rc, "pcvGetPossibleClockRates");
|
||||
}
|
||||
|
||||
if (type != PcvClockRatesListType_Discrete) {
|
||||
ERROR_THROW("Unexpected PcvClockRatesListType: %u (module = %s)", type, GetModuleName(module, false));
|
||||
}
|
||||
|
||||
*outCount = tmpOutCount;
|
||||
}
|
||||
|
||||
u32 GetHighestDockedDisplayRate() {
|
||||
if (GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
return display::GetDockedHighestAllowed();
|
||||
}
|
||||
|
||||
return 60;
|
||||
}
|
||||
|
||||
void ResetToStock() {
|
||||
Result rc;
|
||||
if (hosversionAtLeast(9,0,0)) {
|
||||
std::uint32_t confId = 0;
|
||||
rc = apmExtGetCurrentPerformanceConfiguration(&confId);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
|
||||
SysClkApmConfiguration* apmConfiguration = nullptr;
|
||||
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) {
|
||||
ERROR_THROW("Unknown apm configuration: %x", confId);
|
||||
}
|
||||
|
||||
SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz);
|
||||
SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz);
|
||||
SetHz(SysClkModule_MEM, apmConfiguration->mem_hz);
|
||||
} else {
|
||||
u32 mode = 0;
|
||||
rc = apmExtGetPerformanceMode(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode");
|
||||
|
||||
rc = apmExtSysRequestPerformanceMode(mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode");
|
||||
}
|
||||
}
|
||||
|
||||
void ResetToStockDisplay() {
|
||||
if (GetConsoleType() != HorizonOCConsoleType_Hoag) {
|
||||
display::SetRate(60);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
90
Source/hoc-clk/sysmodule/src/board/board_freq.hpp
Normal file
90
Source/hoc-clk/sysmodule/src/board/board_freq.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <nxExt.h>
|
||||
#include "../errors.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
void SetHz(SysClkModule module, u32 hz);
|
||||
|
||||
u32 GetHz(SysClkModule module);
|
||||
u32 GetRealHz(SysClkModule module);
|
||||
void GetFreqList(SysClkModule module, u32 *outList, u32 maxCount, u32 *outCount);
|
||||
u32 GetHighestDockedDisplayRate();
|
||||
|
||||
void ResetToStock();
|
||||
void ResetToStockDisplay();
|
||||
|
||||
template <typename Getter>
|
||||
void ResetToStockModule(Getter getHzFunc, SysClkModule module) {
|
||||
Result rc = 0;
|
||||
|
||||
if (hosversionAtLeast(9, 0, 0)) {
|
||||
u32 confId = 0;
|
||||
rc = apmExtGetCurrentPerformanceConfiguration(&confId);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
|
||||
SysClkApmConfiguration* apmConfiguration = nullptr;
|
||||
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) {
|
||||
ERROR_THROW("Unknown apm configuration: %x", confId);
|
||||
}
|
||||
|
||||
SetHz(module, getHzFunc(*apmConfiguration));
|
||||
} else {
|
||||
u32 mode = 0;
|
||||
rc = apmExtGetPerformanceMode(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode");
|
||||
|
||||
rc = apmExtSysRequestPerformanceMode(mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode");
|
||||
}
|
||||
}
|
||||
|
||||
inline void ResetToStockCpu() {
|
||||
ResetToStockModule([](const SysClkApmConfiguration& cfg) {return cfg.cpu_hz; }, SysClkModule_CPU);
|
||||
}
|
||||
|
||||
inline void ResetToStockGpu() {
|
||||
ResetToStockModule([](const SysClkApmConfiguration& cfg){ return cfg.gpu_hz; }, SysClkModule_GPU);
|
||||
}
|
||||
|
||||
inline void ResetToStockMem() {
|
||||
ResetToStockModule([](const SysClkApmConfiguration& cfg){ return cfg.mem_hz; }, SysClkModule_MEM);
|
||||
}
|
||||
|
||||
}
|
||||
111
Source/hoc-clk/sysmodule/src/board/board_fuse.cpp
Normal file
111
Source/hoc-clk/sysmodule/src/board/board_fuse.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <fuse.h>
|
||||
#include "board_fuse.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace board {
|
||||
|
||||
void SetGpuBracket(u8 speedo, u8 &gpuBracket) {
|
||||
if (speedo <= 1624) {
|
||||
gpuBracket = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (speedo <= 1689) {
|
||||
gpuBracket = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (speedo <= 1753) {
|
||||
gpuBracket = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
/* >= 1754 */
|
||||
gpuBracket = 3;
|
||||
}
|
||||
|
||||
void ReadFuses(FuseData &speedo) {
|
||||
u64 pid = 0;
|
||||
constexpr u64 UsbID = 0x0100000000000006;
|
||||
if (R_FAILED(pmdmntGetProcessId(&pid, UsbID))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Handle debug;
|
||||
if (R_FAILED(svcDebugActiveProcess(&debug, pid))) {
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryInfo mem_info = {};
|
||||
u32 pageinfo = 0;
|
||||
u64 addr = 0;
|
||||
|
||||
u8 stack[0x10] = {};
|
||||
const u8 compare[0x10] = {};
|
||||
u8 dump[0x400] = {};
|
||||
constexpr u64 PageSize = 0x1000;
|
||||
|
||||
while (true) {
|
||||
if (R_FAILED(svcQueryDebugProcessMemory(&mem_info, &pageinfo, debug, addr)) || mem_info.addr < addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem_info.type == MemType_Io && mem_info.size == PageSize) {
|
||||
if (R_FAILED(svcReadDebugProcessMemory(stack, debug, mem_info.addr, sizeof(stack)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(stack, compare, sizeof(stack)) == 0) {
|
||||
if (R_FAILED(svcReadDebugProcessMemory(dump, debug, mem_info.addr + 0x800, sizeof(dump)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
speedo.cpuSpeedo = *reinterpret_cast<u16*>(dump + FUSE_CPU_SPEEDO_0_CALIB);
|
||||
speedo.gpuSpeedo = *reinterpret_cast<u16*>(dump + FUSE_CPU_SPEEDO_2_CALIB);
|
||||
speedo.socSpeedo = *reinterpret_cast<u16*>(dump + FUSE_SOC_SPEEDO_0_CALIB);
|
||||
|
||||
speedo.cpuIDDQ = *reinterpret_cast<u16*>(dump + FUSE_CPU_IDDQ_CALIB) * 4;
|
||||
speedo.gpuIDDQ = *reinterpret_cast<u16*>(dump + FUSE_GPU_IDDQ_CALIB) * 5;
|
||||
speedo.socIDDQ = *reinterpret_cast<u16*>(dump + FUSE_SOC_IDDQ_CALIB) * 4;
|
||||
speedo.waferX = *reinterpret_cast<u16*>(dump + FUSE_OPT_X_COORDINATE);
|
||||
speedo.waferY = *reinterpret_cast<u16*>(dump + FUSE_OPT_Y_COORDINATE);
|
||||
|
||||
svcCloseHandle(debug);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addr = mem_info.addr + mem_info.size;
|
||||
}
|
||||
|
||||
svcCloseHandle(debug);
|
||||
}
|
||||
|
||||
}
|
||||
49
Source/hoc-clk/sysmodule/src/board/board_fuse.hpp
Normal file
49
Source/hoc-clk/sysmodule/src/board/board_fuse.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
struct FuseData {
|
||||
u16 cpuSpeedo;
|
||||
u16 gpuSpeedo;
|
||||
u16 socSpeedo;
|
||||
|
||||
u16 cpuIDDQ;
|
||||
u16 gpuIDDQ;
|
||||
u16 socIDDQ;
|
||||
|
||||
u16 waferX;
|
||||
u16 waferY;
|
||||
};
|
||||
|
||||
void ReadFuses(FuseData &speedo);
|
||||
void SetGpuBracket(u8 gpuSpeedo, u8 &gpuBracket);
|
||||
|
||||
}
|
||||
188
Source/hoc-clk/sysmodule/src/board/board_load.cpp
Normal file
188
Source/hoc-clk/sysmodule/src/board/board_load.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <nxExt.h>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <numeric>
|
||||
#include <minIni.h>
|
||||
#include <battery.h>
|
||||
#include "board_misc.hpp"
|
||||
#include "board.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
Thread gpuThread;
|
||||
LEvent threadexit;
|
||||
Thread cpuCore0Thread;
|
||||
Thread cpuCore1Thread;
|
||||
Thread cpuCore2Thread;
|
||||
|
||||
u32 gpuLoad;
|
||||
u32 _fd, _fd2;
|
||||
Result nvCheckSched;
|
||||
|
||||
u64 idletick0 = 0;
|
||||
u64 idletick1 = 0;
|
||||
u64 idletick2 = 0;
|
||||
|
||||
constexpr u64 CpuTimeOutNs = 500'000'000;
|
||||
constexpr double Systemtickfrequency = 19200000.0 * (static_cast<double>(CpuTimeOutNs) / 1'000'000'000.0);
|
||||
|
||||
void GpuLoadThread(void *nvCheckPtr) {
|
||||
Result nvCheck = *static_cast<Result *>(nvCheckPtr);
|
||||
constexpr u32 GpuSamples = 8;
|
||||
u32 gpu_load_array[GpuSamples] = {};
|
||||
size_t i = 0;
|
||||
constexpr u32 NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD = 0x80044715;
|
||||
|
||||
if (R_SUCCEEDED(nvCheck)) do {
|
||||
u32 temp;
|
||||
if (R_SUCCEEDED(nvIoctl(_fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &temp))) {
|
||||
gpu_load_array[i++ % GpuSamples] = temp;
|
||||
gpuLoad = std::accumulate(&gpu_load_array[0], &gpu_load_array[GpuSamples], 0) / GpuSamples;
|
||||
}
|
||||
svcSleepThread(16'666'000); // wait a bit (this is the perfect amount of time to keep the reading accurate)
|
||||
} while(true);
|
||||
}
|
||||
|
||||
void CheckCore(void *idletickPtr) {
|
||||
u64* idletick = static_cast<u64 *>(idletickPtr);
|
||||
while(true) {
|
||||
u64 idletickA;
|
||||
u64 idletickB;
|
||||
svcGetInfo(&idletickB, InfoType_IdleTickCount, INVALID_HANDLE, -1);
|
||||
svcWaitForAddress(&threadexit, ArbitrationType_WaitIfEqual, 0, CpuTimeOutNs);
|
||||
svcGetInfo(&idletickA, InfoType_IdleTickCount, INVALID_HANDLE, -1);
|
||||
*idletick = idletickA - idletickB;
|
||||
}
|
||||
}
|
||||
|
||||
void StartLoad(Result nvCheck, u32 fd) {
|
||||
_fd = fd;
|
||||
threadCreate(&gpuThread, GpuLoadThread, &nvCheck, NULL, 0x1000, 0x3F, -2);
|
||||
threadStart(&gpuThread);
|
||||
|
||||
leventClear(&threadexit);
|
||||
threadCreate(&cpuCore0Thread, CheckCore, &idletick0, NULL, 0x1000, 0x10, 0);
|
||||
threadCreate(&cpuCore1Thread, CheckCore, &idletick1, NULL, 0x1000, 0x10, 1);
|
||||
threadCreate(&cpuCore2Thread, CheckCore, &idletick2, NULL, 0x1000, 0x10, 2);
|
||||
|
||||
threadStart(&cpuCore0Thread);
|
||||
threadStart(&cpuCore1Thread);
|
||||
threadStart(&cpuCore2Thread);
|
||||
}
|
||||
|
||||
u32 GetMaxCpuLoad() {
|
||||
float cpuUsage0 = std::clamp(((Systemtickfrequency - idletick0) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
|
||||
float cpuUsage1 = std::clamp(((Systemtickfrequency - idletick1) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
|
||||
float cpuUsage2 = std::clamp(((Systemtickfrequency - idletick2) / static_cast<double>(Systemtickfrequency)) * 1000.0, 0.0, 1000.0);
|
||||
return std::round(std::max({cpuUsage0, cpuUsage1, cpuUsage2}));
|
||||
}
|
||||
|
||||
u32 GetPartLoad(SysClkPartLoad loadSource) {
|
||||
switch(loadSource) {
|
||||
case SysClkPartLoad_EMC:
|
||||
return t210EmcLoadAll();
|
||||
case SysClkPartLoad_EMCCpu:
|
||||
return t210EmcLoadCpu();
|
||||
case HocClkPartLoad_GPU:
|
||||
return gpuLoad;
|
||||
case HocClkPartLoad_CPUMax:
|
||||
return GetMaxCpuLoad();
|
||||
case HocClkPartLoad_BAT:
|
||||
BatteryChargeInfo info;
|
||||
batteryInfoGetChargeInfo(&info);
|
||||
return info.RawBatteryCharge;
|
||||
case HocClkPartLoad_FAN:
|
||||
return GetFanLevel();
|
||||
default:
|
||||
ASSERT_ENUM_VALID(SysClkPartLoad, loadSource);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExitLoad() {
|
||||
threadClose(&gpuThread);
|
||||
threadClose(&cpuCore0Thread);
|
||||
threadClose(&cpuCore1Thread);
|
||||
threadClose(&cpuCore2Thread);
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr u32 NVschedCtrlEnable = 0x00000601;
|
||||
constexpr u32 NVschedCtrlDisable = 0x00000602;
|
||||
}
|
||||
|
||||
void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method) {
|
||||
if (R_FAILED(nvCheckSched) && method == GpuSchedulingOverrideMethod_NvService) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 temp;
|
||||
bool enabled = false;
|
||||
switch (mode) {
|
||||
case GpuSchedulingMode_DoNotOverride: break;
|
||||
case GpuSchedulingMode_Disabled:
|
||||
if (method == GpuSchedulingOverrideMethod_NvService) {
|
||||
nvIoctl(_fd2, NVschedCtrlDisable, &temp);
|
||||
} else {
|
||||
enabled = false;
|
||||
}
|
||||
break;
|
||||
case GpuSchedulingMode_Enabled:
|
||||
if (method == GpuSchedulingOverrideMethod_NvService) {
|
||||
nvIoctl(_fd2, NVschedCtrlEnable, &temp);
|
||||
} else {
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT_ENUM_VALID(GpuSchedulingMode, mode);
|
||||
}
|
||||
|
||||
if (method == GpuSchedulingOverrideMethod_Ini) {
|
||||
constexpr const char *IniPath = "sdmc:/atmosphere/config/system_settings.ini";
|
||||
constexpr const char *Section = "am.gpu";
|
||||
constexpr const char *Key = "gpu_scheduling_enabled";
|
||||
|
||||
const char *value = enabled ? "u8!0x1" : "u8!0x0";
|
||||
|
||||
ini_puts(Section, Key, value, IniPath);
|
||||
}
|
||||
}
|
||||
|
||||
void SchedSetFD2(u32 fd2) {
|
||||
_fd2 = fd2;
|
||||
}
|
||||
|
||||
void NvSchedSucceed(Result nvSched) {
|
||||
nvCheckSched = nvSched;
|
||||
}
|
||||
|
||||
}
|
||||
40
Source/hoc-clk/sysmodule/src/board/board_load.hpp
Normal file
40
Source/hoc-clk/sysmodule/src/board/board_load.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
void StartLoad(Result nvCheck, u32 fd);
|
||||
void ExitLoad();
|
||||
u32 GetPartLoad(SysClkPartLoad loadSource);
|
||||
void SetGpuSchedulingMode(GpuSchedulingMode mode, GpuSchedulingOverrideMethod method);
|
||||
void SchedSetFD2(u32 fd2);
|
||||
void NvSchedSucceed(Result nvSched);
|
||||
|
||||
}
|
||||
72
Source/hoc-clk/sysmodule/src/board/board_misc.cpp
Normal file
72
Source/hoc-clk/sysmodule/src/board/board_misc.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <pwm.h>
|
||||
#include <cmath>
|
||||
#include <rgltr.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
Thread miscThread;
|
||||
u8 fanLevel = 0;
|
||||
PwmChannelSession *_iCon;
|
||||
|
||||
void MiscThreadFunc(void *pwmCheckPtr) {
|
||||
Result pwmCheck = *static_cast<Result *>(pwmCheckPtr);
|
||||
double temp = 0;
|
||||
double rotationDuty = 0;
|
||||
|
||||
while (true) {
|
||||
if (R_SUCCEEDED(pwmCheck)) {
|
||||
if (R_SUCCEEDED(pwmChannelSessionGetDutyCycle(_iCon, &temp))) {
|
||||
temp *= 10;
|
||||
temp = trunc(temp);
|
||||
temp /= 10;
|
||||
rotationDuty = 100.0 - temp;
|
||||
}
|
||||
}
|
||||
|
||||
fanLevel = static_cast<u8>(rotationDuty);
|
||||
svcSleepThread(300'000'000);
|
||||
}
|
||||
}
|
||||
|
||||
u8 GetFanLevel() {
|
||||
return fanLevel;
|
||||
}
|
||||
|
||||
void StartMiscThread(Result pwmCheck, PwmChannelSession *iCon) {
|
||||
_iCon = iCon;
|
||||
threadCreate(&miscThread, MiscThreadFunc, &pwmCheck, NULL, 0x1000, 0x10, 3);
|
||||
threadStart(&miscThread);
|
||||
}
|
||||
|
||||
void ExitMiscThread() {
|
||||
threadClose(&miscThread);
|
||||
}
|
||||
|
||||
}
|
||||
39
Source/hoc-clk/sysmodule/src/board/board_misc.hpp
Normal file
39
Source/hoc-clk/sysmodule/src/board/board_misc.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <pwm.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
void StartMiscThread(Result pwmCheck, PwmChannelSession *iCon);
|
||||
void ExitMiscThread();
|
||||
u8 GetFanLevel();
|
||||
|
||||
}
|
||||
53
Source/hoc-clk/sysmodule/src/board/board_name.cpp
Normal file
53
Source/hoc-clk/sysmodule/src/board/board_name.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include "board.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
const char *GetModuleName(SysClkModule module, bool pretty) {
|
||||
ASSERT_ENUM_VALID(SysClkModule, module);
|
||||
return sysclkFormatModule(module, pretty);
|
||||
}
|
||||
|
||||
const char *GetProfileName(SysClkProfile profile, bool pretty) {
|
||||
ASSERT_ENUM_VALID(SysClkProfile, profile);
|
||||
return sysclkFormatProfile(profile, pretty);
|
||||
}
|
||||
|
||||
const char *GetThermalSensorName(SysClkThermalSensor sensor, bool pretty) {
|
||||
ASSERT_ENUM_VALID(SysClkThermalSensor, sensor);
|
||||
return sysclkFormatThermalSensor(sensor, pretty);
|
||||
}
|
||||
|
||||
const char *GetPowerSensorName(SysClkPowerSensor sensor, bool pretty) {
|
||||
ASSERT_ENUM_VALID(SysClkPowerSensor, sensor);
|
||||
return sysclkFormatPowerSensor(sensor, pretty);
|
||||
}
|
||||
|
||||
}
|
||||
38
Source/hoc-clk/sysmodule/src/board/board_name.hpp
Normal file
38
Source/hoc-clk/sysmodule/src/board/board_name.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
const char *GetModuleName(SysClkModule module, bool pretty);
|
||||
const char *GetProfileName(SysClkProfile profile, bool pretty);
|
||||
const char *GetThermalSensorName(SysClkThermalSensor sensor, bool pretty);
|
||||
const char *GetPowerSensorName(SysClkPowerSensor sensor, bool pretty);
|
||||
|
||||
}
|
||||
57
Source/hoc-clk/sysmodule/src/board/board_profile.cpp
Normal file
57
Source/hoc-clk/sysmodule/src/board/board_profile.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <nxExt.h>
|
||||
#include "board.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
SysClkProfile GetProfile() {
|
||||
u32 mode = 0;
|
||||
Result rc = apmExtGetPerformanceMode(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode");
|
||||
|
||||
if (mode) {
|
||||
return SysClkProfile_Docked;
|
||||
}
|
||||
|
||||
PsmChargerType chargerType;
|
||||
|
||||
rc = psmGetChargerType(&chargerType);
|
||||
ASSERT_RESULT_OK(rc, "psmGetChargerType");
|
||||
|
||||
if (chargerType == PsmChargerType_EnoughPower) {
|
||||
return SysClkProfile_HandheldChargingOfficial;
|
||||
} else if (chargerType == PsmChargerType_LowPower) {
|
||||
return SysClkProfile_HandheldChargingUSB;
|
||||
}
|
||||
|
||||
return SysClkProfile_Handheld;
|
||||
}
|
||||
|
||||
}
|
||||
34
Source/hoc-clk/sysmodule/src/board/board_profile.hpp
Normal file
34
Source/hoc-clk/sysmodule/src/board/board_profile.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
SysClkProfile GetProfile();
|
||||
|
||||
}
|
||||
107
Source/hoc-clk/sysmodule/src/board/board_sensor.cpp
Normal file
107
Source/hoc-clk/sysmodule/src/board/board_sensor.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <sysclk.h>
|
||||
#include <switch.h>
|
||||
#include <nxExt.h>
|
||||
#include <cmath>
|
||||
#include <battery.h>
|
||||
#include <pwm.h>
|
||||
#include "board.hpp"
|
||||
#include "../soctherm.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
s32 GetTemperatureMilli(SysClkThermalSensor sensor) {
|
||||
s32 millis = 0;
|
||||
BatteryChargeInfo info;
|
||||
|
||||
soctherm::TSensorTemps temps = {};
|
||||
soctherm::ReadSensors(temps);
|
||||
|
||||
switch(sensor) {
|
||||
case SysClkThermalSensor_SOC: {
|
||||
millis = tmp451TempSoc();
|
||||
break;
|
||||
}
|
||||
case SysClkThermalSensor_PCB: {
|
||||
millis = tmp451TempPcb();
|
||||
break;
|
||||
}
|
||||
case SysClkThermalSensor_Skin: {
|
||||
if (HOSSVC_HAS_TC) {
|
||||
Result rc;
|
||||
rc = tcGetSkinTemperatureMilliC(&millis);
|
||||
ASSERT_RESULT_OK(rc, "tcGetSkinTemperatureMilliC");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_Battery: {
|
||||
batteryInfoGetChargeInfo(&info);
|
||||
millis = batteryInfoGetTemperatureMiliCelsius(&info);
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_PMIC: {
|
||||
millis = 50000;
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_CPU: {
|
||||
millis = temps.cpu;
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_GPU: {
|
||||
millis = temps.gpu;
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_MEM: {
|
||||
millis = temps.mem;
|
||||
break;
|
||||
}
|
||||
case HorizonOCThermalSensor_PLLX: {
|
||||
millis = temps.pllx;
|
||||
}
|
||||
default: {
|
||||
ASSERT_ENUM_VALID(SysClkThermalSensor, sensor);
|
||||
}
|
||||
}
|
||||
|
||||
return std::max(0, millis);
|
||||
}
|
||||
|
||||
s32 GetPowerMw(SysClkPowerSensor sensor) {
|
||||
switch (sensor) {
|
||||
case SysClkPowerSensor_Now:
|
||||
return max17050PowerNow();
|
||||
case SysClkPowerSensor_Avg:
|
||||
return max17050PowerAvg();
|
||||
default:
|
||||
ASSERT_ENUM_VALID(SysClkPowerSensor, sensor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
36
Source/hoc-clk/sysmodule/src/board/board_sensor.hpp
Normal file
36
Source/hoc-clk/sysmodule/src/board/board_sensor.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
s32 GetTemperatureMilli(SysClkThermalSensor sensor);
|
||||
s32 GetPowerMw(SysClkPowerSensor sensor);
|
||||
|
||||
}
|
||||
455
Source/hoc-clk/sysmodule/src/board/board_volt.cpp
Normal file
455
Source/hoc-clk/sysmodule/src/board/board_volt.cpp
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include <memmem.h>
|
||||
#include <registers.h>
|
||||
#include <cstring>
|
||||
#include <rgltr.h>
|
||||
#include <battery.h>
|
||||
#include "board.hpp"
|
||||
#include "board_freq.hpp"
|
||||
#include "board_volt.hpp"
|
||||
#include "../file_utils.hpp"
|
||||
|
||||
namespace board {
|
||||
|
||||
GpuVoltData voltData = {};
|
||||
u64 cldvfs;
|
||||
CpuDfllData cachedTune;
|
||||
|
||||
/* ... This really needs some cleanup... */
|
||||
namespace {
|
||||
struct EristaCpuUvEntry {
|
||||
u32 tune0;
|
||||
u32 tune1;
|
||||
};
|
||||
|
||||
struct MarikoCpuUvEntry {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
};
|
||||
|
||||
EristaCpuUvEntry eristaCpuUvTable[5] = {
|
||||
{0xffff, 0x27007ff},
|
||||
{0xefff, 0x27407ff},
|
||||
{0xdfff, 0x27807ff},
|
||||
{0xdfdf, 0x27a07ff},
|
||||
{0xcfdf, 0x37007ff},
|
||||
};
|
||||
|
||||
MarikoCpuUvEntry marikoCpuUvLow[12] = {
|
||||
{0xffa0, 0xffff, 0x21107ff, 0},
|
||||
{0x0, 0xffdf, 0x21107ff, 0x27207ff},
|
||||
{0xffdf, 0xffdf, 0x21107ff, 0x27307ff},
|
||||
{0xffff, 0xffdf, 0x21107ff, 0x27407ff},
|
||||
{0x0, 0xffdf, 0x21607ff, 0x27707ff},
|
||||
{0x0, 0xffdf, 0x21607ff, 0x27807ff},
|
||||
{0x0, 0xdfff, 0x21607ff, 0x27b07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27b07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27c07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27d07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27e07ff},
|
||||
{0xdfff, 0xdfff, 0x21707ff, 0x27f07ff},
|
||||
};
|
||||
|
||||
MarikoCpuUvEntry marikoCpuUvHigh[12] = {
|
||||
{0x0, 0xffff, 0, 0},
|
||||
{0x0, 0xffdf, 0, 0x27207ff},
|
||||
{0x0, 0xffdf, 0, 0x27307ff},
|
||||
{0x0, 0xffdf, 0, 0x27407ff},
|
||||
{0x0, 0xffdf, 0, 0x27707ff},
|
||||
{0x0, 0xffdf, 0, 0x27807ff},
|
||||
{0x0, 0xdfff, 0, 0x27b07ff},
|
||||
{0x0, 0xdfff, 0, 0x27c07ff},
|
||||
{0x0, 0xdfff, 0, 0x27d07ff},
|
||||
{0x0, 0xdfff, 0, 0x27e07ff},
|
||||
{0x0, 0xdfff, 0, 0x27f07ff},
|
||||
{0x0, 0xdfff, 0, 0x27f07ff},
|
||||
};
|
||||
}
|
||||
|
||||
void CacheDfllData() {
|
||||
u64 temp;
|
||||
Result rc = svcQueryMemoryMapping(&cldvfs, &temp, CLDVFS_REGION_BASE, CLDVFS_REGION_SIZE);
|
||||
ASSERT_RESULT_OK(rc, "svcQueryMemoryMapping (cldvfs)");
|
||||
|
||||
if (GetSocType() == SysClkSocType_Erista) {
|
||||
cachedTune.tune0Low = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
|
||||
cachedTune.tune1Low = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE1_0);
|
||||
} else {
|
||||
SetHz(SysClkModule_CPU, 1785000000);
|
||||
cachedTune.tune0High = *reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
|
||||
ResetToStockCpu();
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: clean up this code. */
|
||||
void SetDfllTunings(u32 levelLow, u32 levelHigh, u32 tbreakPoint) {
|
||||
u32* tune0_ptr = reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE0_0);
|
||||
u32* tune1_ptr = reinterpret_cast<u32 *>(cldvfs + CL_DVFS_TUNE1_0);
|
||||
if (GetSocType() == SysClkSocType_Mariko) {
|
||||
if (GetHz(SysClkModule_CPU) < tbreakPoint && (levelLow || levelHigh)) {
|
||||
if (levelLow) {
|
||||
*tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
|
||||
*tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (levelLow) {
|
||||
*tune0_ptr = marikoCpuUvLow[levelLow-1].tune0_low;
|
||||
*tune1_ptr = marikoCpuUvLow[levelLow-1].tune1_low;
|
||||
}
|
||||
if (levelHigh) {
|
||||
*tune0_ptr = marikoCpuUvHigh[levelHigh-1].tune0_high;
|
||||
*tune1_ptr = marikoCpuUvHigh[levelHigh-1].tune1_high;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
|
||||
*tune0_ptr = 0xCFFF;
|
||||
*tune1_ptr = 0xFF072201;
|
||||
return;
|
||||
} else if (GetHz(SysClkModule_CPU) >= tbreakPoint || (!levelHigh)) {
|
||||
*tune0_ptr = cachedTune.tune0High; // per console?
|
||||
*tune1_ptr = 0xFFF7FF3F;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (GetHz(SysClkModule_CPU) < tbreakPoint || (!levelLow)) { // account for tbreak
|
||||
*tune0_ptr = cachedTune.tune0Low; // I think each erista has a different tune0/tune1?
|
||||
*tune1_ptr = cachedTune.tune1Low;
|
||||
return;
|
||||
} else {
|
||||
if (levelLow) {
|
||||
*tune0_ptr = eristaCpuUvTable[levelLow-1].tune0;
|
||||
*tune1_ptr = eristaCpuUvTable[levelLow-1].tune1;
|
||||
} else {
|
||||
*tune0_ptr = 0x0;
|
||||
*tune1_ptr = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
enum TableConfig: u32 {
|
||||
DEFAULT_TABLE = 1,
|
||||
TBREAK_1581 = 2,
|
||||
TBREAK_1683 = 3,
|
||||
EXTREME_TABLE = 4,
|
||||
};
|
||||
*/
|
||||
u32 CalculateTbreak(u32 table) {
|
||||
if (GetSocType() == SysClkSocType_Erista) {
|
||||
return 1581000000;
|
||||
} else {
|
||||
switch (table) {
|
||||
case 1 ... 2:
|
||||
case 4:
|
||||
return 1581000000;
|
||||
case 3:
|
||||
return 1683000000;
|
||||
default:
|
||||
return 1581000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch Power domains (max77620):
|
||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||
*-------+---------------+---------+--------+------------+---------+------------------
|
||||
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
|
||||
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | 0.85V (AO, pcv)
|
||||
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V (pcv)
|
||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
|
||||
* ldo8 | XUSB, DP, MCU | 50000 | 800000 | 1050000 | 2800000 | 1.05V/2.8V (pcv)
|
||||
|
||||
typedef enum {
|
||||
PcvPowerDomainId_Max77620_Sd0 = 0x3A000080,
|
||||
PcvPowerDomainId_Max77620_Sd1 = 0x3A000081, // vdd2
|
||||
PcvPowerDomainId_Max77620_Sd2 = 0x3A000082,
|
||||
PcvPowerDomainId_Max77620_Sd3 = 0x3A000083,
|
||||
PcvPowerDomainId_Max77620_Ldo0 = 0x3A0000A0,
|
||||
PcvPowerDomainId_Max77620_Ldo1 = 0x3A0000A1,
|
||||
PcvPowerDomainId_Max77620_Ldo2 = 0x3A0000A2,
|
||||
PcvPowerDomainId_Max77620_Ldo3 = 0x3A0000A3,
|
||||
PcvPowerDomainId_Max77620_Ldo4 = 0x3A0000A4,
|
||||
PcvPowerDomainId_Max77620_Ldo5 = 0x3A0000A5,
|
||||
PcvPowerDomainId_Max77620_Ldo6 = 0x3A0000A6,
|
||||
PcvPowerDomainId_Max77620_Ldo7 = 0x3A0000A7,
|
||||
PcvPowerDomainId_Max77620_Ldo8 = 0x3A0000A8,
|
||||
PcvPowerDomainId_Max77621_Cpu = 0x3A000003,
|
||||
PcvPowerDomainId_Max77621_Gpu = 0x3A000004,
|
||||
PcvPowerDomainId_Max77812_Cpu = 0x3A000003,
|
||||
PcvPowerDomainId_Max77812_Gpu = 0x3A000004,
|
||||
PcvPowerDomainId_Max77812_Dram = 0x3A000005, // vddq
|
||||
} PowerDomainId;
|
||||
*/
|
||||
u32 GetVoltage(HocClkVoltage voltage) {
|
||||
RgltrSession session;
|
||||
Result rc = 0;
|
||||
u32 out = 0;
|
||||
BatteryChargeInfo info;
|
||||
|
||||
switch (voltage) {
|
||||
case HocClkVoltage_SOC:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd0);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_EMCVDD2:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Sd1);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_CPU:
|
||||
if (GetSocType() == SysClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Cpu);
|
||||
} else {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Cpu);
|
||||
}
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_GPU:
|
||||
if (GetSocType() == SysClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77621_Gpu);
|
||||
} else {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Gpu);
|
||||
}
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_EMCVDDQ_MarikoOnly:
|
||||
if (GetSocType() == SysClkSocType_Mariko) {
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77812_Dram);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
} else {
|
||||
out = GetVoltage(HocClkVoltage_EMCVDD2);
|
||||
}
|
||||
break;
|
||||
case HocClkVoltage_Display:
|
||||
rc = rgltrOpenSession(&session, PcvPowerDomainId_Max77620_Ldo0);
|
||||
ASSERT_RESULT_OK(rc, "rgltrOpenSession")
|
||||
rgltrGetVoltage(&session, &out);
|
||||
rgltrCloseSession(&session);
|
||||
break;
|
||||
case HocClkVoltage_Battery:
|
||||
batteryInfoGetChargeInfo(&info);
|
||||
out = info.VoltageAvg;
|
||||
break;
|
||||
default:
|
||||
ASSERT_ENUM_VALID(HocClkVoltage, voltage);
|
||||
}
|
||||
|
||||
return out > 0 ? out : 0;
|
||||
}
|
||||
|
||||
Handle GetPcvHandle() {
|
||||
constexpr u64 PcvID = 0x10000000000001a;
|
||||
u64 processIDList[80]{};
|
||||
s32 processCount = 0;
|
||||
Handle handle = INVALID_HANDLE;
|
||||
|
||||
DebugEventInfo debugEvent{};
|
||||
|
||||
/* Get all running processes. */
|
||||
Result resultGetProcessList = svcGetProcessList(&processCount, processIDList, std::size(processIDList));
|
||||
if (R_FAILED(resultGetProcessList)) {
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Try to find pcv. */
|
||||
for (int i = 0; i < processCount; ++i) {
|
||||
if (handle != INVALID_HANDLE) {
|
||||
svcCloseHandle(handle);
|
||||
handle = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Try to debug process, if it fails, try next process. */
|
||||
Result resultSvcDebugProcess = svcDebugActiveProcess(&handle, processIDList[i]);
|
||||
if (R_FAILED(resultSvcDebugProcess)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to get a debug event. */
|
||||
Result resultDebugEvent = svcGetDebugEvent(&debugEvent, handle);
|
||||
if (R_SUCCEEDED(resultDebugEvent)) {
|
||||
if (debugEvent.info.create_process.program_id == PcvID) {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to get handle. */
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
void CacheGpuVoltTable() {
|
||||
UnkRegulator reg = {
|
||||
.voltageMin = 600000,
|
||||
.voltageStep = 12500,
|
||||
.voltageMax = 1400000,
|
||||
};
|
||||
|
||||
Handle handle = GetPcvHandle();
|
||||
if (handle == INVALID_HANDLE) {
|
||||
fileUtils::LogLine("[dvfs] Invalid handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryInfo memoryInfo = {};
|
||||
u64 address = 0;
|
||||
u32 pageInfo = 0;
|
||||
constexpr u32 PageSize = 0x1000;
|
||||
u8 buffer[PageSize];
|
||||
|
||||
/* Loop until failure. */
|
||||
while (true) {
|
||||
/* Find pcv heap. */
|
||||
while (true) {
|
||||
Result resultProcessMemory = svcQueryDebugProcessMemory(&memoryInfo, &pageInfo, handle, address);
|
||||
address = memoryInfo.addr + memoryInfo.size;
|
||||
|
||||
if (R_FAILED(resultProcessMemory) || !address) {
|
||||
svcCloseHandle(handle);
|
||||
fileUtils::LogLine("[dvfs] Failed to get process data. %u", R_DESCRIPTION(resultProcessMemory));
|
||||
handle = INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (memoryInfo.size && (memoryInfo.perm & 3) == 3 && static_cast<char>(memoryInfo.type) == 0x4) {
|
||||
/* Found valid memory. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 base = 0; base < memoryInfo.size; base += PageSize) {
|
||||
u32 memorySize = std::min(memoryInfo.size, static_cast<u64>(PageSize));
|
||||
if (R_FAILED(svcReadDebugProcessMemory(buffer, handle, base + memoryInfo.addr, memorySize))) {
|
||||
break;
|
||||
}
|
||||
|
||||
u8 *resultFindReg = static_cast<u8 *>(memmem_impl(buffer, sizeof(buffer), ®, sizeof(reg)));
|
||||
u32 index = resultFindReg - buffer;
|
||||
|
||||
if (!resultFindReg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Assuming mariko. */
|
||||
const u32 vmax = 800;
|
||||
constexpr u32 VoltageTableOffset = 312;
|
||||
if (!std::memcmp(&buffer[index + VoltageTableOffset], &vmax, sizeof(vmax))) {
|
||||
std::memcpy(voltData.voltTable, &buffer[index + VoltageTableOffset], sizeof(voltData.voltTable));
|
||||
voltData.voltTableAddress = base + memoryInfo.addr + VoltageTableOffset + index;
|
||||
}
|
||||
|
||||
svcCloseHandle(handle);
|
||||
handle = INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
svcCloseHandle(handle);
|
||||
handle = INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
void PcvHijackGpuVolts(u32 vmin) {
|
||||
u32 table[192];
|
||||
static_assert(sizeof(table) == sizeof(voltData.voltTable), "Invalid gpu voltage table size!");
|
||||
std::memcpy(table, voltData.voltTable, sizeof(voltData.voltTable));
|
||||
|
||||
if (voltData.ramVmin == vmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < std::size(table); ++i) {
|
||||
if (table[i] && table[i] <= vmin) {
|
||||
table[i] = vmin;
|
||||
}
|
||||
}
|
||||
|
||||
Handle handle = GetPcvHandle();
|
||||
if (handle == INVALID_HANDLE) {
|
||||
fileUtils::LogLine("Invalid handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = svcWriteDebugProcessMemory(handle, table, voltData.voltTableAddress, sizeof(table));
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
voltData.ramVmin = vmin;
|
||||
}
|
||||
|
||||
svcCloseHandle(handle);
|
||||
fileUtils::LogLine("[dvfs] voltage set to %u mV", vmin);
|
||||
}
|
||||
|
||||
u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket) {
|
||||
static const u32 ramTable[][22] = {
|
||||
{ 2133, 2200, 2266, 2300, 2366, 2400, 2433, 2466, 2533, 2566, 2600, 2633, 2700, 2733, 2766, 2833, 2866, 2900, 2933, 3033, 3066, 3100, },
|
||||
{ 2300, 2366, 2433, 2466, 2533, 2566, 2633, 2700, 2733, 2800, 2833, 2900, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3266, },
|
||||
{ 2433, 2466, 2533, 2600, 2666, 2733, 2766, 2800, 2833, 2866, 2933, 2966, 3033, 3066, 3100, 3133, 3166, 3200, 3233, 3300, 3333, 3366, },
|
||||
{ 2500, 2533, 2600, 2633, 2666, 2733, 2800, 2866, 2900, 2966, 3033, 3100, 3166, 3200, 3233, 3266, 3300, 3333, 3366, 3400, 3400, 3400, },
|
||||
};
|
||||
|
||||
static const u32 gpuVoltArray[] = { 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790, 800, };
|
||||
|
||||
if (freqMhz <= 1600) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < std::size(gpuVoltArray); ++i) {
|
||||
if (freqMhz <= ramTable[bracket][i]) {
|
||||
return gpuVoltArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
return gpuVoltArray[std::size(gpuVoltArray) - 1];
|
||||
}
|
||||
|
||||
}
|
||||
64
Source/hoc-clk/sysmodule/src/board/board_volt.hpp
Normal file
64
Source/hoc-clk/sysmodule/src/board/board_volt.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace board {
|
||||
|
||||
struct GpuVoltData {
|
||||
u32 voltTable[6][32] = {};
|
||||
u64 voltTableAddress;
|
||||
u32 ramVmin;
|
||||
};
|
||||
|
||||
/* TODO: Find out what component this actually targets. */
|
||||
struct UnkRegulator {
|
||||
u32 voltageMin;
|
||||
u32 voltageStep;
|
||||
u32 voltageMax;
|
||||
};
|
||||
|
||||
struct CpuDfllData {
|
||||
u32 tune0Low;
|
||||
u32 tune0High;
|
||||
u32 tune1Low;
|
||||
u32 tune1High;
|
||||
// u32 tune_high_min_millivolts;
|
||||
// u32 tune_high_margin_millivolts;
|
||||
// u64 dvco_calibration_max;
|
||||
};
|
||||
|
||||
void SetDfllTunings(u32 levelLow, u32 levelHigh, u32 tbreakPoint);
|
||||
void CacheDfllData();
|
||||
u32 CalculateTbreak(u32 table);
|
||||
u32 GetVoltage(HocClkVoltage voltage);
|
||||
void CacheGpuVoltTable();
|
||||
void PcvHijackGpuVolts(u32 vmin);
|
||||
u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket);
|
||||
|
||||
}
|
||||
736
Source/hoc-clk/sysmodule/src/board/display_refresh_rate.cpp
Normal file
736
Source/hoc-clk/sysmodule/src/board/display_refresh_rate.cpp
Normal file
@@ -0,0 +1,736 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, based on reasearch by MasaGratoR and Cooler3D
|
||||
*
|
||||
* 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 "display_refresh_rate.hpp"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <switch.h>
|
||||
|
||||
namespace display {
|
||||
#define DSI_CLOCK_HZ 234000000llu
|
||||
#define NVDISP_GET_MODE2 0x803C021B
|
||||
#define NVDISP_SET_MODE2 0x403C021C
|
||||
#define NVDISP_VALIDATE_MODE2 0xC03C021D
|
||||
#define NVDISP_GET_MODE_DB2 0xEF20021E
|
||||
#define NVDISP_GET_PANEL_DATA 0xC01C0226
|
||||
|
||||
#define MAX_REFRESH_RATE 72
|
||||
|
||||
static DisplayRefreshConfig g_config = {0};
|
||||
static bool g_initialized = false;
|
||||
|
||||
static uint8_t g_dockedHighestRefreshRate = 60;
|
||||
static uint8_t g_dockedLinkRate = 10;
|
||||
static bool g_wasRetroSuperTurnedOff = false;
|
||||
static uint32_t g_lastVActive = 1080;
|
||||
static bool g_canChangeRefreshRateDocked = false;
|
||||
static uint8_t g_lastVActiveSet = 0;
|
||||
|
||||
static const uint8_t g_dockedRefreshRates[] = {40, 45, 50, 55, 60, 70, 72, 75, 80, 90, 95, 100, 110, 120, 130, 140, 144, 150, 160, 165, 170, 180, 190, 200, 210, 220, 230, 240};
|
||||
// Calculate with this tool:
|
||||
|
||||
// https://tomverbeure.github.io/video_timings_calculator?horiz_pixels=1920&vert_pixels=1080&refresh_rate=240&margins=false&interlaced=false&bpc=8&color_fmt=rgb444&video_opt=false&custom_hblank=80&custom_vblank=6
|
||||
|
||||
/*
|
||||
typedef struct {
|
||||
uint16_t hFrontPorch;
|
||||
uint8_t hSyncWidth;
|
||||
uint8_t hBackPorch;
|
||||
uint8_t vFrontPorch;
|
||||
uint8_t vSyncWidth;
|
||||
uint8_t vBackPorch;
|
||||
uint8_t VIC;
|
||||
uint32_t pixelClock_kHz;
|
||||
} DockedTimings;
|
||||
*/
|
||||
static const DockedTimings g_dockedTimings1080p[] = {
|
||||
{8, 32, 40, 7, 8, 6, 0, 88080}, // 40Hz
|
||||
{8, 32, 40, 9, 8, 6, 0, 99270}, // 45Hz
|
||||
{528, 44, 148, 4, 5, 36, 31, 148500}, // 50Hz
|
||||
{8, 32, 40, 15, 8, 6, 0, 121990}, // 55Hz
|
||||
{88, 44, 148, 4, 5, 36, 16, 148500}, // 60Hz
|
||||
{8, 32, 40, 22, 8, 6, 0, 156240}, // 70Hz
|
||||
{8, 32, 40, 23, 8, 6, 0, 160848}, // 72Hz
|
||||
{8, 32, 40, 25, 8, 6, 0, 167850}, // 75Hz
|
||||
{8, 32, 40, 28, 8, 6, 0, 179520}, // 80Hz
|
||||
{8, 32, 40, 33, 8, 6, 0, 202860}, // 90Hz
|
||||
{8, 32, 40, 36, 8, 6, 0, 214700}, // 95Hz
|
||||
{528, 44, 148, 4, 5, 36, 64, 297000}, // 100Hz
|
||||
{8, 32, 40, 44, 8, 6, 0, 250360}, // 110Hz
|
||||
{88, 44, 148, 4, 5, 36, 63, 297000}, // 120Hz
|
||||
{8, 32, 40, 55, 8, 6, 0, 298750}, //130Hz CVT-RBv2
|
||||
{8, 32, 40, 61, 8, 6, 0, 323400}, //140Hz CVT-RBv2
|
||||
{8, 32, 40, 63, 8, 6, 0, 333216}, //144Hz CVT-RBv2
|
||||
{8, 32, 40, 67, 8, 6, 0, 348300}, //150Hz CVT-RBv2
|
||||
{8, 32, 40, 72, 8, 6, 0, 373120}, //160Hz CVT-RBv2
|
||||
{8, 32, 40, 75, 8, 6, 0, 385770}, //165Hz CVT-RBv2
|
||||
{8, 32, 40, 78, 8, 6, 0, 398480}, //170Hz CVT-RBv2
|
||||
{8, 32, 40, 84, 8, 6, 0, 424080}, //180Hz CVT-RBv2
|
||||
{8, 32, 40, 90, 8, 6, 0, 449920}, //190Hz CVT-RBv2
|
||||
{8, 32, 40, 96, 8, 6, 0, 476000}, //200Hz CVT-RBv2
|
||||
{8, 32, 40, 102, 8, 6, 0, 502320}, //210Hz CVT-RBv2
|
||||
{8, 32, 40, 108, 8, 6, 0, 528880}, //220Hz CVT-RBv2
|
||||
{8, 32, 40, 114, 8, 6, 0, 555680}, //230Hz CVT-RBv2
|
||||
{8, 32, 40, 121, 8, 6, 0, 583200}, //240Hz CVT-RBv2
|
||||
// technically you can go to 476hz, but in practice, why would you?
|
||||
};
|
||||
|
||||
// These timings *should* work but are untested
|
||||
static const HandheldTimings g_handheldTimingsRETRO[] = {
|
||||
{72, 136, 72, 1, 660, 9, 78000}, // 40Hz
|
||||
{72, 136, 72, 1, 612, 9, 77982}, // 41Hz
|
||||
{72, 136, 72, 1, 567, 9, 77994}, // 42Hz
|
||||
{72, 136, 72, 1, 524, 9, 78002}, // 43Hz
|
||||
{72, 136, 72, 1, 483, 9, 78012}, // 44Hz
|
||||
{72, 136, 72, 1, 443, 9, 77985}, // 45Hz
|
||||
{72, 136, 72, 1, 406, 9, 78016}, // 46Hz
|
||||
{72, 136, 72, 1, 370, 9, 78020}, // 47Hz
|
||||
{72, 136, 72, 1, 335, 9, 78000}, // 48Hz
|
||||
{72, 136, 72, 1, 302, 9, 78008}, // 49Hz
|
||||
{72, 136, 72, 1, 270, 9, 78000}, // 50Hz
|
||||
{72, 136, 72, 1, 239, 9, 77979}, // 51Hz
|
||||
{72, 136, 72, 1, 210, 9, 78000}, // 52Hz
|
||||
{72, 136, 72, 1, 182, 9, 78016}, // 53Hz
|
||||
{72, 136, 72, 1, 154, 9, 77976}, // 54Hz
|
||||
{72, 136, 72, 1, 128, 9, 77990}, // 55Hz
|
||||
{72, 136, 72, 1, 103, 9, 78008}, // 56Hz
|
||||
{72, 136, 72, 1, 78, 9, 77976}, // 57Hz
|
||||
{72, 136, 72, 1, 55, 9, 78010}, // 58Hz
|
||||
{72, 136, 72, 1, 32, 9, 77998}, // 59Hz
|
||||
{72, 136, 72, 1, 10, 9, 78000}, // 60Hz
|
||||
};
|
||||
|
||||
static const MinMaxRefreshRate g_handheldModeRefreshRate = {40, 80};
|
||||
|
||||
static uint8_t _getDockedRefreshRateIterator(uint32_t refreshRate) {
|
||||
for (size_t i = 0; i < sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]); i++) {
|
||||
if (g_dockedRefreshRates[i] == refreshRate) return i;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static void _changeOledElvssSettings(const uint32_t* offsets, const uint32_t* value, uint32_t size, uint32_t start) {
|
||||
if (!g_config.dsiVirtAddr || !value || !size) return;
|
||||
|
||||
volatile uint32_t* dsi = (uint32_t*)g_config.dsiVirtAddr;
|
||||
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
#define DSI_WR_DATA 0xA
|
||||
#define DSI_TRIGGER 0x13
|
||||
#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15
|
||||
#define MIPI_DSI_DCS_LONG_WRITE 0x39
|
||||
#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0
|
||||
#define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1
|
||||
|
||||
dsi[DSI_VIDEO_MODE_CONTROL] = true;
|
||||
svcSleepThread(20000000);
|
||||
|
||||
dsi[DSI_WR_DATA] = MIPI_DSI_DCS_LONG_WRITE | (5 << 8);
|
||||
dsi[DSI_WR_DATA] = 0x5A5A5AE2;
|
||||
dsi[DSI_WR_DATA] = 0x5A;
|
||||
dsi[DSI_TRIGGER] = 0;
|
||||
|
||||
for (size_t i = start; i < size; i++) {
|
||||
dsi[DSI_WR_DATA] = ((MIPI_DCS_PRIV_SM_SET_REG_OFFSET | ((offsets[i] % 0x100) << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM;
|
||||
dsi[DSI_TRIGGER] = 0;
|
||||
dsi[DSI_WR_DATA] = ((MIPI_DCS_PRIV_SM_SET_ELVSS | (value[i] << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM;
|
||||
dsi[DSI_TRIGGER] = 0;
|
||||
}
|
||||
|
||||
dsi[DSI_WR_DATA] = MIPI_DSI_DCS_LONG_WRITE | (5 << 8);
|
||||
dsi[DSI_WR_DATA] = 0xA55A5AE2;
|
||||
dsi[DSI_WR_DATA] = 0xA5;
|
||||
dsi[DSI_TRIGGER] = 0;
|
||||
|
||||
dsi[DSI_VIDEO_MODE_CONTROL] = false;
|
||||
svcSleepThread(20000000);
|
||||
}
|
||||
void SetDockedState(bool isDocked) {
|
||||
g_config.isDocked = isDocked;
|
||||
}
|
||||
|
||||
bool Initialize(const DisplayRefreshConfig* config) {
|
||||
if (!config) return false;
|
||||
|
||||
g_config = *config;
|
||||
g_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CorrectOledGamma(uint32_t refresh_rate) {
|
||||
static uint32_t last_refresh_rate = 60;
|
||||
static int counter = 0;
|
||||
|
||||
if (g_config.isDocked || refresh_rate < 45 || refresh_rate > 60) {
|
||||
last_refresh_rate = 60;
|
||||
return;
|
||||
}
|
||||
|
||||
if (counter != 9) {
|
||||
counter++;
|
||||
return;
|
||||
}
|
||||
counter = 0;
|
||||
|
||||
uint32_t offsets[] = {0x1A, 0x24, 0x25};
|
||||
uint32_t values[] = {2, 0, 0x83};
|
||||
|
||||
if (refresh_rate == 60) {
|
||||
if (last_refresh_rate == 60) return;
|
||||
} else if (refresh_rate == 45) {
|
||||
if (last_refresh_rate == 45) return;
|
||||
uint32_t vals[] = {4, 1, 0};
|
||||
memcpy(values, vals, sizeof(vals));
|
||||
} else if (refresh_rate == 50) {
|
||||
if (last_refresh_rate == 50) return;
|
||||
uint32_t vals[] = {3, 1, 0};
|
||||
memcpy(values, vals, sizeof(vals));
|
||||
} else if (refresh_rate == 55) {
|
||||
if (last_refresh_rate == 55) return;
|
||||
uint32_t vals[] = {3, 1, 0};
|
||||
memcpy(values, vals, sizeof(vals));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
_changeOledElvssSettings(offsets, values, 3, 0);
|
||||
}
|
||||
last_refresh_rate = refresh_rate;
|
||||
}
|
||||
|
||||
void SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p) {
|
||||
// Function kept for API compatibility but does nothing
|
||||
(void)refreshRates;
|
||||
(void)is720p;
|
||||
}
|
||||
|
||||
uint8_t GetDockedHighestAllowed(void) {
|
||||
return (g_dockedHighestRefreshRate > 60) ? g_dockedHighestRefreshRate : 60;
|
||||
}
|
||||
|
||||
static void _getDockedHighestRefreshRate(uint32_t fd_in) {
|
||||
uint8_t highestRefreshRate = 60;
|
||||
uint32_t fd = fd_in;
|
||||
|
||||
if(!fd) nvOpen(&fd, "/dev/nvdisp-disp1");
|
||||
NvdcModeDB2 db2 = {0};
|
||||
int rc = nvIoctl(fd, NVDISP_GET_MODE_DB2, &db2);
|
||||
|
||||
if (rc == 0) {
|
||||
for (size_t i = 0; i < db2.num_modes; i++) {
|
||||
if (db2.modes[i].hActive < 1920 || db2.modes[i].vActive < 1080)
|
||||
continue;
|
||||
|
||||
uint32_t v_total = db2.modes[i].vActive + db2.modes[i].vSyncWidth + db2.modes[i].vFrontPorch + db2.modes[i].vBackPorch;
|
||||
uint32_t h_total = db2.modes[i].hActive + db2.modes[i].hSyncWidth + db2.modes[i].hFrontPorch + db2.modes[i].hBackPorch;
|
||||
double refreshRate = round((double)(db2.modes[i].pclkKHz * 1000) / (double)(v_total * h_total));
|
||||
|
||||
if (highestRefreshRate < (uint8_t)refreshRate)
|
||||
highestRefreshRate = (uint8_t)refreshRate;
|
||||
}
|
||||
} else {
|
||||
g_dockedHighestRefreshRate = 60;
|
||||
}
|
||||
|
||||
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
|
||||
if (highestRefreshRate > g_dockedRefreshRates[numRates - 1])
|
||||
highestRefreshRate = g_dockedRefreshRates[numRates - 1];
|
||||
|
||||
NvdcMode2 display_b = {0};
|
||||
rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
|
||||
|
||||
struct dpaux_read_0x100 {
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
struct {
|
||||
unsigned char link_rate;
|
||||
unsigned int lane_count: 5;
|
||||
unsigned int unk1: 2;
|
||||
unsigned int isFramingEnhanced: 1;
|
||||
unsigned char downspread;
|
||||
unsigned char training_pattern;
|
||||
unsigned char lane_pattern[4];
|
||||
unsigned char unk2[8];
|
||||
} set;
|
||||
} dpaux = {6, 0x100, 0x10};
|
||||
|
||||
rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
|
||||
if (rc == 0) {
|
||||
g_dockedLinkRate = dpaux.set.link_rate;
|
||||
// if (display_b.hActive == 1920 && display_b.vActive == 1080 && highestRefreshRate > 75 && dpaux.set.link_rate < 20 && )
|
||||
// highestRefreshRate = 75;
|
||||
}
|
||||
|
||||
if (!fd_in) nvClose(fd);
|
||||
g_dockedHighestRefreshRate = highestRefreshRate;
|
||||
}
|
||||
|
||||
static bool _setPLLDHandheldRefreshRate(uint32_t new_refreshRate) {
|
||||
if (!g_config.clkVirtAddr) return false;
|
||||
|
||||
uint32_t fd = 0;
|
||||
if (nvOpen(&fd, "/dev/nvdisp-disp0")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dpaux_read {
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
struct {
|
||||
unsigned int rev_minor : 4;
|
||||
unsigned int rev_major : 4;
|
||||
unsigned char link_rate;
|
||||
unsigned int lane_count: 5;
|
||||
unsigned int unk1: 2;
|
||||
unsigned int isFramingEnhanced: 1;
|
||||
unsigned char unk2[13];
|
||||
} DPCD;
|
||||
} dpaux = {6, 0, 0x10};
|
||||
|
||||
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
|
||||
nvClose(fd);
|
||||
if (rc != 0x75c) return false;
|
||||
|
||||
PLLD_BASE base = {0};
|
||||
PLLD_MISC misc = {0};
|
||||
memcpy(&base, (void*)(g_config.clkVirtAddr + 0xD0), 4);
|
||||
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
|
||||
|
||||
uint32_t value = ((base.PLLD_DIVN / base.PLLD_DIVM) * 10) / 4;
|
||||
if (value == 0 || value == 80) return false;
|
||||
|
||||
if (new_refreshRate > g_handheldModeRefreshRate.max) {
|
||||
new_refreshRate = g_handheldModeRefreshRate.max;
|
||||
} else if (new_refreshRate < g_handheldModeRefreshRate.min) {
|
||||
bool skip = false;
|
||||
for (size_t i = 2; i <= 4; i++) {
|
||||
if (new_refreshRate * i == 60) {
|
||||
skip = true;
|
||||
new_refreshRate = 60;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!skip) {
|
||||
for (size_t i = 2; i <= 4; i++) {
|
||||
if (((new_refreshRate * i) >= g_handheldModeRefreshRate.min) && ((new_refreshRate * i) <= g_handheldModeRefreshRate.max)) {
|
||||
skip = true;
|
||||
new_refreshRate *= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip) new_refreshRate = 60;
|
||||
}
|
||||
|
||||
uint32_t pixelClock = (9375 * ((4096 * ((2 * base.PLLD_DIVN) + 1)) + misc.PLLD_SDM_DIN)) / (8 * base.PLLD_DIVM);
|
||||
uint16_t refreshRateNow = pixelClock / (DSI_CLOCK_HZ / 60);
|
||||
|
||||
if (refreshRateNow == new_refreshRate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t base_refreshRate = new_refreshRate - (new_refreshRate % 5);
|
||||
base.PLLD_DIVN = (4 * base_refreshRate) / 10;
|
||||
base.PLLD_DIVM = 1;
|
||||
|
||||
uint64_t expected_pixel_clock = (DSI_CLOCK_HZ * new_refreshRate) / 60;
|
||||
misc.PLLD_SDM_DIN = ((8 * base.PLLD_DIVM * expected_pixel_clock) / 9375) - (4096 * ((2 * base.PLLD_DIVN) + 1));
|
||||
|
||||
memcpy((void*)(g_config.clkVirtAddr + 0xD0), &base, 4);
|
||||
memcpy((void*)(g_config.clkVirtAddr + 0xDC), &misc, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _setNvDispDockedRefreshRate(uint32_t new_refreshRate) {
|
||||
if (g_config.isLite || !g_canChangeRefreshRateDocked)
|
||||
return false;
|
||||
|
||||
uint32_t fd = 0;
|
||||
if (nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NvdcMode2 display_b = {0};
|
||||
int rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
|
||||
if (rc != 0) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!display_b.pclkKHz) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!((display_b.vActive == 480 && display_b.hActive == 720) ||
|
||||
(display_b.vActive == 720 && display_b.hActive == 1280) ||
|
||||
(display_b.vActive == 1080 && display_b.hActive == 1920))) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (display_b.vActive != g_lastVActiveSet) {
|
||||
g_lastVActiveSet = display_b.vActive;
|
||||
}
|
||||
|
||||
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
|
||||
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
|
||||
uint32_t refreshRateNow = ((display_b.pclkKHz) * 1000 + 999) / (h_total * v_total);
|
||||
|
||||
int8_t itr = -1;
|
||||
const size_t numRates = sizeof(g_dockedRefreshRates) / sizeof(g_dockedRefreshRates[0]);
|
||||
|
||||
// Find closest matching refresh rate
|
||||
if ((new_refreshRate <= 60) && ((60 % new_refreshRate) == 0)) {
|
||||
itr = _getDockedRefreshRateIterator(60);
|
||||
}
|
||||
|
||||
if (itr == -1) {
|
||||
for (size_t i = 0; i < numRates; i++) {
|
||||
uint8_t val = g_dockedRefreshRates[i];
|
||||
if ((val % new_refreshRate) == 0) {
|
||||
itr = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itr == -1) {
|
||||
if (!g_config.matchLowestDocked) {
|
||||
itr = _getDockedRefreshRateIterator(60);
|
||||
} else {
|
||||
for (size_t i = 0; i < numRates; i++) {
|
||||
if (new_refreshRate < g_dockedRefreshRates[i]) {
|
||||
itr = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itr == -1) itr = _getDockedRefreshRateIterator(60);
|
||||
|
||||
// Clamp to highest allowed refresh rate
|
||||
if (g_dockedRefreshRates[itr] > g_dockedHighestRefreshRate) {
|
||||
for (int8_t i = itr; i >= 0; i--) {
|
||||
if (g_dockedRefreshRates[i] <= g_dockedHighestRefreshRate) {
|
||||
itr = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshRateNow == g_dockedRefreshRates[itr]) {
|
||||
nvClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itr >= 0 && itr < (int8_t)numRates) {
|
||||
if (display_b.vActive == 720) {
|
||||
uint32_t clock = ((h_total * v_total) * g_dockedRefreshRates[itr]) / 1000;
|
||||
display_b.pclkKHz = clock;
|
||||
} else {
|
||||
display_b.hFrontPorch = g_dockedTimings1080p[itr].hFrontPorch;
|
||||
display_b.hSyncWidth = g_dockedTimings1080p[itr].hSyncWidth;
|
||||
display_b.hBackPorch = g_dockedTimings1080p[itr].hBackPorch;
|
||||
display_b.vFrontPorch = g_dockedTimings1080p[itr].vFrontPorch;
|
||||
display_b.vSyncWidth = g_dockedTimings1080p[itr].vSyncWidth;
|
||||
display_b.vBackPorch = g_dockedTimings1080p[itr].vBackPorch;
|
||||
display_b.pclkKHz = g_dockedTimings1080p[itr].pixelClock_kHz;
|
||||
display_b.vmode = (g_dockedRefreshRates[itr] >= 100 ? 0x400000 : 0x200000);
|
||||
display_b.unk1 = (g_dockedRefreshRates[itr] >= 100 ? 0x80 : 0);
|
||||
display_b.sync = 3;
|
||||
display_b.bitsPerPixel = 24;
|
||||
}
|
||||
|
||||
rc = nvIoctl(fd, NVDISP_VALIDATE_MODE2, &display_b);
|
||||
if (rc == 0) {
|
||||
rc = nvIoctl(fd, NVDISP_SET_MODE2, &display_b);
|
||||
}
|
||||
}
|
||||
|
||||
nvClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _setNvDispHandheldRefreshRate(uint32_t new_refreshRate) {
|
||||
if (!g_config.isRetroSUPER) return false;
|
||||
|
||||
if (!g_config.displaySync) {
|
||||
g_wasRetroSuperTurnedOff = false;
|
||||
} else if (g_wasRetroSuperTurnedOff) {
|
||||
svcSleepThread(2000000000);
|
||||
g_wasRetroSuperTurnedOff = false;
|
||||
}
|
||||
|
||||
svcSleepThread(1000000000);
|
||||
|
||||
uint32_t fd = 0;
|
||||
if (nvOpen(&fd, "/dev/nvdisp-disp0")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NvdcMode2 display_b = {0};
|
||||
int rc = nvIoctl(fd, NVDISP_GET_MODE2, &display_b);
|
||||
if (rc != 0) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!display_b.pclkKHz) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((display_b.vActive == 1280 && display_b.hActive == 720) == false) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
|
||||
uint32_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
|
||||
uint32_t refreshRateNow = ((display_b.pclkKHz) * 1000 + 999) / (h_total * v_total);
|
||||
|
||||
if (new_refreshRate > g_handheldModeRefreshRate.max) {
|
||||
new_refreshRate = g_handheldModeRefreshRate.max;
|
||||
} else if (new_refreshRate < g_handheldModeRefreshRate.min) {
|
||||
bool skip = false;
|
||||
for (size_t i = 2; i <= 4; i++) {
|
||||
if (new_refreshRate * i == 60) {
|
||||
skip = true;
|
||||
new_refreshRate = 60;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!skip) {
|
||||
for (size_t i = 2; i <= (sizeof(g_handheldTimingsRETRO) / sizeof(g_handheldTimingsRETRO[0])); i++) {
|
||||
if (((new_refreshRate * i) >= g_handheldModeRefreshRate.min) && ((new_refreshRate * i) <= g_handheldModeRefreshRate.max)) {
|
||||
skip = true;
|
||||
new_refreshRate *= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip) new_refreshRate = 60;
|
||||
}
|
||||
|
||||
if (new_refreshRate == refreshRateNow) {
|
||||
nvClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t itr = (new_refreshRate - 40) / 5;
|
||||
display_b.hFrontPorch = g_handheldTimingsRETRO[itr].hFrontPorch;
|
||||
display_b.hSyncWidth = g_handheldTimingsRETRO[itr].hSyncWidth;
|
||||
display_b.hBackPorch = g_handheldTimingsRETRO[itr].hBackPorch;
|
||||
display_b.vFrontPorch = g_handheldTimingsRETRO[itr].vFrontPorch;
|
||||
display_b.vSyncWidth = g_handheldTimingsRETRO[itr].vSyncWidth;
|
||||
display_b.vBackPorch = g_handheldTimingsRETRO[itr].vBackPorch;
|
||||
display_b.pclkKHz = g_handheldTimingsRETRO[itr].pixelClock_kHz;
|
||||
|
||||
rc = nvIoctl(fd, NVDISP_VALIDATE_MODE2, &display_b);
|
||||
if (rc == 0) {
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
nvIoctl(fd, NVDISP_SET_MODE2, &display_b);
|
||||
}
|
||||
}
|
||||
|
||||
nvClose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetRate(uint32_t new_refreshRate) {
|
||||
if (!new_refreshRate || !g_initialized) return false;
|
||||
|
||||
uint32_t fd = 0;
|
||||
|
||||
if (g_config.isRetroSUPER && !g_config.isDocked) {
|
||||
return _setNvDispHandheldRefreshRate(new_refreshRate);
|
||||
}
|
||||
|
||||
else if ((!g_config.isRetroSUPER && g_config.isLite) || R_FAILED(nvOpen(&fd, "/dev/nvdisp-disp1"))) {
|
||||
if (_setPLLDHandheldRefreshRate(new_refreshRate) == false)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
struct dpaux_read {
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
struct {
|
||||
unsigned int rev_minor : 4;
|
||||
unsigned int rev_major : 4;
|
||||
unsigned char link_rate;
|
||||
unsigned int lane_count: 5;
|
||||
unsigned int unk1: 2;
|
||||
unsigned int isFramingEnhanced: 1;
|
||||
unsigned char unk2[13];
|
||||
} DPCD;
|
||||
} dpaux = {6, 0, 0x10};
|
||||
|
||||
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
|
||||
nvClose(fd);
|
||||
|
||||
if (rc != 0) {
|
||||
if (!g_config.isRetroSUPER) {
|
||||
return _setPLLDHandheldRefreshRate(new_refreshRate);
|
||||
} else {
|
||||
return _setNvDispHandheldRefreshRate(new_refreshRate);
|
||||
}
|
||||
} else {
|
||||
if(g_config.isDocked)
|
||||
return _setNvDispDockedRefreshRate(new_refreshRate);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetRate(uint32_t* out_refreshRate, bool internal) {
|
||||
if (!out_refreshRate || !g_initialized || !g_config.clkVirtAddr) return false;
|
||||
static uint32_t value = 60;
|
||||
|
||||
if (g_config.isRetroSUPER && !g_config.isDocked) {
|
||||
uint32_t fd = 0;
|
||||
PLLD_BASE temp = {0};
|
||||
PLLD_MISC misc = {0};
|
||||
memcpy(&temp, (void*)(g_config.clkVirtAddr + 0xD0), 4);
|
||||
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
|
||||
|
||||
value = ((temp.PLLD_DIVN / temp.PLLD_DIVM) * 10) / 4;
|
||||
|
||||
if (value != 0 && value != 80) {
|
||||
if (!nvOpen(&fd, "/dev/nvdisp-disp0")) {
|
||||
NvdcMode2 display_b = {0};
|
||||
if (nvIoctl(fd, NVDISP_GET_MODE2, &display_b) == 0) {
|
||||
uint64_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
|
||||
uint64_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
|
||||
uint64_t pixelClock = display_b.pclkKHz * 1000 + 999;
|
||||
value = (u32)(pixelClock / (h_total * v_total));
|
||||
}
|
||||
nvClose(fd);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
g_wasRetroSuperTurnedOff = true;
|
||||
}
|
||||
}
|
||||
else if ((!g_config.isPossiblySpoofedRetro) || (g_config.isPossiblySpoofedRetro && !g_config.isRetroSUPER)) {
|
||||
PLLD_BASE temp = {0};
|
||||
PLLD_MISC misc = {0};
|
||||
memcpy(&temp, (void*)(g_config.clkVirtAddr + 0xD0), 4);
|
||||
memcpy(&misc, (void*)(g_config.clkVirtAddr + 0xDC), 4);
|
||||
|
||||
value = ((temp.PLLD_DIVN / temp.PLLD_DIVM) * 10) / 4;
|
||||
|
||||
if (value == 0 || value == 80) {
|
||||
// Docked mode
|
||||
if (g_config.isLite) return false;
|
||||
|
||||
g_config.isDocked = true;
|
||||
|
||||
if (!g_canChangeRefreshRateDocked) {
|
||||
uint32_t fd = 0;
|
||||
if (!nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
struct dpaux_read_0x100 {
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
struct {
|
||||
unsigned char link_rate;
|
||||
unsigned int lane_count: 5;
|
||||
unsigned int unk1: 2;
|
||||
unsigned int isFramingEnhanced: 1;
|
||||
unsigned char downspread;
|
||||
unsigned char training_pattern;
|
||||
unsigned char lane_pattern[4];
|
||||
unsigned char unk2[8];
|
||||
} set;
|
||||
} dpaux = {6, 0x100, 0x10};
|
||||
|
||||
int rc = nvIoctl(fd, NVDISP_GET_PANEL_DATA, &dpaux);
|
||||
nvClose(fd);
|
||||
|
||||
if (rc == 0) {
|
||||
_getDockedHighestRefreshRate(0);
|
||||
g_canChangeRefreshRateDocked = true;
|
||||
} else {
|
||||
svcSleepThread(1000000000);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(internal) {
|
||||
*out_refreshRate = value;
|
||||
return true;
|
||||
}
|
||||
uint32_t fd = 0;
|
||||
if (!nvOpen(&fd, "/dev/nvdisp-disp1")) {
|
||||
NvdcMode2 display_b = {0};
|
||||
if (nvIoctl(fd, NVDISP_GET_MODE2, &display_b) == 0) {
|
||||
if (!display_b.pclkKHz) {
|
||||
nvClose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_lastVActive != display_b.vActive) {
|
||||
g_lastVActive = display_b.vActive;
|
||||
_getDockedHighestRefreshRate(fd);
|
||||
}
|
||||
|
||||
uint64_t h_total = display_b.hActive + display_b.hFrontPorch + display_b.hSyncWidth + display_b.hBackPorch;
|
||||
uint64_t v_total = display_b.vActive + display_b.vFrontPorch + display_b.vSyncWidth + display_b.vBackPorch;
|
||||
uint64_t pixelClock = display_b.pclkKHz * 1000 + 999;
|
||||
value = (u32)(pixelClock / (h_total * v_total));
|
||||
} else {
|
||||
value = 60;
|
||||
}
|
||||
nvClose(fd);
|
||||
} else {
|
||||
value = 60;
|
||||
}
|
||||
}
|
||||
else if (!g_config.isRetroSUPER) {
|
||||
// Handheld mode
|
||||
g_config.isDocked = false;
|
||||
g_canChangeRefreshRateDocked = false;
|
||||
|
||||
uint32_t pixelClock = (9375ULL * ((4096 * ((2 * temp.PLLD_DIVN) + 1)) + misc.PLLD_SDM_DIN)) / (8 * temp.PLLD_DIVM);
|
||||
value = pixelClock / (DSI_CLOCK_HZ / 60);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*out_refreshRate = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Shutdown(void) {
|
||||
g_initialized = false;
|
||||
memset(&g_config, 0, sizeof(g_config));
|
||||
}
|
||||
}
|
||||
127
Source/hoc-clk/sysmodule/src/board/display_refresh_rate.hpp
Normal file
127
Source/hoc-clk/sysmodule/src/board/display_refresh_rate.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, based on reasearch by MasaGratoR and Cooler3D
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
namespace display {
|
||||
typedef struct {
|
||||
uint16_t hFrontPorch;
|
||||
uint8_t hSyncWidth;
|
||||
uint8_t hBackPorch;
|
||||
uint8_t vFrontPorch;
|
||||
uint8_t vSyncWidth;
|
||||
uint8_t vBackPorch;
|
||||
uint8_t VIC;
|
||||
uint32_t pixelClock_kHz;
|
||||
} DockedTimings;
|
||||
|
||||
typedef struct {
|
||||
uint8_t hSyncWidth;
|
||||
uint16_t hFrontPorch;
|
||||
uint8_t hBackPorch;
|
||||
uint8_t vSyncWidth;
|
||||
uint16_t vFrontPorch;
|
||||
uint8_t vBackPorch;
|
||||
uint32_t pixelClock_kHz;
|
||||
} HandheldTimings;
|
||||
|
||||
typedef struct {
|
||||
uint8_t min;
|
||||
uint8_t max;
|
||||
} MinMaxRefreshRate;
|
||||
|
||||
typedef struct {
|
||||
uint32_t unk0;
|
||||
uint32_t hActive;
|
||||
uint32_t vActive;
|
||||
uint32_t hSyncWidth;
|
||||
uint32_t vSyncWidth;
|
||||
uint32_t hFrontPorch;
|
||||
uint32_t vFrontPorch;
|
||||
uint32_t hBackPorch;
|
||||
uint32_t vBackPorch;
|
||||
uint32_t pclkKHz;
|
||||
uint32_t bitsPerPixel;
|
||||
uint32_t vmode;
|
||||
uint32_t sync;
|
||||
uint32_t unk1;
|
||||
uint32_t reserved;
|
||||
} NvdcMode2;
|
||||
|
||||
typedef struct {
|
||||
NvdcMode2 modes[201];
|
||||
uint32_t num_modes;
|
||||
} NvdcModeDB2;
|
||||
|
||||
typedef struct {
|
||||
unsigned int PLLD_DIVM: 8;
|
||||
unsigned int reserved_1: 3;
|
||||
unsigned int PLLD_DIVN: 8;
|
||||
unsigned int reserved_2: 1;
|
||||
unsigned int PLLD_DIVP: 3;
|
||||
unsigned int CSI_CLK_SRC: 1;
|
||||
unsigned int reserved_3: 1;
|
||||
unsigned int PLL_D: 1;
|
||||
unsigned int reserved_4: 1;
|
||||
unsigned int PLLD_LOCK: 1;
|
||||
unsigned int reserved_5: 1;
|
||||
unsigned int PLLD_REF_DIS: 1;
|
||||
unsigned int PLLD_ENABLE: 1;
|
||||
unsigned int PLLD_BYPASS: 1;
|
||||
} PLLD_BASE;
|
||||
|
||||
typedef struct {
|
||||
signed int PLLD_SDM_DIN: 16;
|
||||
unsigned int PLLD_EN_SDM: 1;
|
||||
unsigned int PLLD_LOCK_OVERRIDE: 1;
|
||||
unsigned int PLLD_EN_LCKDET: 1;
|
||||
unsigned int PLLD_FREQLOCK: 1;
|
||||
unsigned int PLLD_IDDQ: 1;
|
||||
unsigned int PLLD_ENABLE_CLK: 1;
|
||||
unsigned int PLLD_KVCO: 1;
|
||||
unsigned int PLLD_KCP: 2;
|
||||
unsigned int PLLD_PTS: 2;
|
||||
unsigned int PLLD_LDPULSE_ADJ: 3;
|
||||
unsigned int reserved: 2;
|
||||
} PLLD_MISC;
|
||||
|
||||
typedef struct {
|
||||
uint64_t clkVirtAddr;
|
||||
uint64_t dsiVirtAddr;
|
||||
bool isDocked;
|
||||
bool isLite;
|
||||
bool isRetroSUPER;
|
||||
bool isPossiblySpoofedRetro;
|
||||
bool dontForce60InDocked;
|
||||
bool matchLowestDocked;
|
||||
bool displaySync;
|
||||
bool displaySyncOutOfFocus60;
|
||||
bool displaySyncDocked;
|
||||
bool displaySyncDockedOutOfFocus60;
|
||||
} DisplayRefreshConfig;
|
||||
bool Initialize(const DisplayRefreshConfig* config);
|
||||
void SetDockedState(bool isDocked);
|
||||
bool SetRate(uint32_t new_refreshRate);
|
||||
bool GetRate(uint32_t* out_refreshRate, bool internal);
|
||||
uint8_t GetDockedHighestAllowed(void);
|
||||
void CorrectOledGamma(uint32_t refresh_rate);
|
||||
void SetAllowedDockedRatesIPC(uint32_t refreshRates, bool is720p);
|
||||
void Shutdown(void);
|
||||
}
|
||||
642
Source/hoc-clk/sysmodule/src/clock_manager.cpp
Normal file
642
Source/hoc-clk/sysmodule/src/clock_manager.cpp
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "clock_manager.hpp"
|
||||
#include <cstring>
|
||||
#include "file_utils.hpp"
|
||||
#include "board/board.hpp"
|
||||
#include "process_management.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "ipc_service.hpp"
|
||||
#include "kip.hpp"
|
||||
#include <i2c.h>
|
||||
#include "board/display_refresh_rate.hpp"
|
||||
#include <cstdio>
|
||||
#include <crc32.h>
|
||||
#include "config.hpp"
|
||||
#include "integrations.hpp"
|
||||
#include <nxExt/cpp/lockable_mutex.h>
|
||||
#include "kip.hpp"
|
||||
#include "governor.hpp"
|
||||
|
||||
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
||||
|
||||
namespace clockManager {
|
||||
|
||||
|
||||
bool gRunning = false;
|
||||
LockableMutex gContextMutex;
|
||||
SysClkContext gContext = {};
|
||||
FreqTable gFreqTable[SysClkModule_EnumMax];
|
||||
std::uint64_t gLastTempLogNs = 0;
|
||||
std::uint64_t gLastFreqLogNs = 0;
|
||||
std::uint64_t gLastPowerLogNs = 0;
|
||||
std::uint64_t gLastCsvWriteNs = 0;
|
||||
|
||||
bool IsAssignableHz(SysClkModule module, std::uint32_t hz)
|
||||
{
|
||||
switch (module) {
|
||||
case SysClkModule_CPU:
|
||||
return hz >= 500000000;
|
||||
case SysClkModule_MEM:
|
||||
return hz >= 665600000;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile)
|
||||
{
|
||||
if (config::GetConfigValue(HocClkConfigValue_UncappedClocks)) {
|
||||
return ~0; // Integer limit, uncapped clocks ON
|
||||
} else {
|
||||
if (module == SysClkModule_GPU) {
|
||||
if (profile < SysClkProfile_HandheldCharging) {
|
||||
switch (board::GetSocType()) {
|
||||
case SysClkSocType_Erista:
|
||||
return 460800000;
|
||||
case SysClkSocType_Mariko:
|
||||
switch (config::GetConfigValue(KipConfigValue_marikoGpuUV)) {
|
||||
case 0:
|
||||
return 614400000;
|
||||
case 1:
|
||||
return 691200000;
|
||||
case 2:
|
||||
return 768000000;
|
||||
default:
|
||||
return 614400000;
|
||||
}
|
||||
default:
|
||||
return 460800000;
|
||||
}
|
||||
} else if (profile <= SysClkProfile_HandheldChargingUSB) {
|
||||
switch (board::GetSocType()) {
|
||||
case SysClkSocType_Erista:
|
||||
return 768000000;
|
||||
case SysClkSocType_Mariko:
|
||||
switch (config::GetConfigValue(KipConfigValue_marikoGpuUV)) {
|
||||
case 0:
|
||||
return 844800000;
|
||||
case 1:
|
||||
return 921600000;
|
||||
case 2:
|
||||
return 998400000;
|
||||
default:
|
||||
return 844800000;
|
||||
}
|
||||
default:
|
||||
return 768000000;
|
||||
}
|
||||
}
|
||||
} else if (module == SysClkModule_CPU) {
|
||||
if (profile < SysClkProfile_HandheldCharging && board::GetSocType() == SysClkSocType_Erista) {
|
||||
return 1581000000;
|
||||
} else {
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t GetNearestHz(SysClkModule module, std::uint32_t inHz, std::uint32_t maxHz)
|
||||
{
|
||||
std::uint32_t *freqs = &gFreqTable[module].list[0];
|
||||
size_t count = gFreqTable[module].count - 1;
|
||||
|
||||
size_t i = 0;
|
||||
while (i < count) {
|
||||
if (maxHz > 0 && freqs[i] >= maxHz) {
|
||||
break;
|
||||
}
|
||||
if (inHz <= ((std::uint64_t)freqs[i] + freqs[i + 1]) / 2) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return freqs[i];
|
||||
}
|
||||
|
||||
void ResetToStockClocks()
|
||||
{
|
||||
board::ResetToStockCpu();
|
||||
if (config::GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) {
|
||||
if (board::GetSocType() == SysClkSocType_Erista)
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
|
||||
else
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_marikoCpuUVLow), config::GetConfigValue(KipConfigValue_marikoCpuUVHigh), board::CalculateTbreak(config::GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
|
||||
bool ConfigIntervalTimeout(SysClkConfigValue intervalMsConfigValue, std::uint64_t ns, std::uint64_t *lastLogNs)
|
||||
{
|
||||
std::uint64_t logInterval = config::GetConfigValue(intervalMsConfigValue) * 1000000ULL;
|
||||
bool shouldLog = logInterval && ((ns - *lastLogNs) > logInterval);
|
||||
|
||||
if (shouldLog) {
|
||||
*lastLogNs = ns;
|
||||
}
|
||||
|
||||
return shouldLog;
|
||||
}
|
||||
|
||||
void RefreshFreqTableRow(SysClkModule module)
|
||||
{
|
||||
std::scoped_lock lock{gContextMutex};
|
||||
|
||||
std::uint32_t freqs[SYSCLK_FREQ_LIST_MAX];
|
||||
std::uint32_t count;
|
||||
|
||||
fileUtils::LogLine("[mgr] %s freq list refresh", board::GetModuleName(module, true));
|
||||
board::GetFreqList(module, &freqs[0], SYSCLK_FREQ_LIST_MAX, &count);
|
||||
|
||||
std::uint32_t *hz = &gFreqTable[module].list[0];
|
||||
gFreqTable[module].count = 0;
|
||||
for (std::uint32_t i = 0; i < count; i++) {
|
||||
if (!IsAssignableHz(module, freqs[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*hz = freqs[i];
|
||||
fileUtils::LogLine("[mgr] %02u - %u - %u.%u MHz", gFreqTable[module].count, *hz, *hz / 1000000, *hz / 100000 - *hz / 1000000 * 10);
|
||||
|
||||
gFreqTable[module].count++;
|
||||
hz++;
|
||||
}
|
||||
|
||||
fileUtils::LogLine("[mgr] count = %u", gFreqTable[module].count);
|
||||
}
|
||||
|
||||
void HandleSafetyFeatures()
|
||||
{
|
||||
if (config::GetConfigValue(HocClkConfigValue_HandheldTDP) && (gContext.profile != SysClkProfile_Docked)) {
|
||||
if (board::GetConsoleType() == HorizonOCConsoleType_Hoag) {
|
||||
if (board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)config::GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (board::GetPowerMw(SysClkPowerSensor_Avg) < -(int)config::GetConfigValue(HocClkConfigValue_HandheldTDPLimit)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((tmp451TempSoc() / 1000) > (int)config::GetConfigValue(HocClkConfigValue_ThermalThrottleThreshold)) && config::GetConfigValue(HocClkConfigValue_ThermalThrottle)) {
|
||||
ResetToStockClocks();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleMiscFeatures()
|
||||
{
|
||||
if (config::GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
|
||||
I2c_Bq24193_SetFastChargeCurrentLimit(config::GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
|
||||
}
|
||||
}
|
||||
|
||||
void DVFSBeforeSet(u32 targetHz)
|
||||
{
|
||||
s32 dvfsOffset = config::GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
u32 vmin = board::GetMinimumGpuVmin(targetHz / 1000000, board::GetGpuSpeedoBracket()) + dvfsOffset;
|
||||
|
||||
board::PcvHijackGpuVolts(vmin);
|
||||
|
||||
/* Update the voltage. */
|
||||
if (I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU) < vmin) {
|
||||
I2c_BuckConverter_SetMvOut(&I2c_Mariko_GPU, vmin);
|
||||
}
|
||||
|
||||
gContext.voltages[HocClkVoltage_GPU] = vmin * 1000;
|
||||
}
|
||||
|
||||
void DVFSAfterSet(u32 targetHz)
|
||||
{
|
||||
s32 dvfsOffset = config::GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||
dvfsOffset = std::max(dvfsOffset, -80);
|
||||
u32 vmin = board::GetMinimumGpuVmin(targetHz / 1000000, board::GetGpuSpeedoBracket());
|
||||
|
||||
if (vmin) {
|
||||
vmin += dvfsOffset;
|
||||
}
|
||||
|
||||
u32 maxHz = GetMaxAllowedHz(SysClkModule_GPU, gContext.profile);
|
||||
u32 nearestHz = GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
||||
board::PcvHijackGpuVolts(vmin);
|
||||
|
||||
if (targetHz) {
|
||||
board::SetHz(SysClkModule_GPU, ~0);
|
||||
board::SetHz(SysClkModule_GPU, nearestHz);
|
||||
} else {
|
||||
board::SetHz(SysClkModule_GPU, ~0);
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
}
|
||||
|
||||
void HandleCpuUv()
|
||||
{
|
||||
if (board::GetSocType() == SysClkSocType_Erista)
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
|
||||
else
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_marikoCpuUVLow), config::GetConfigValue(KipConfigValue_marikoCpuUVHigh), board::CalculateTbreak(config::GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
|
||||
void DVFSReset()
|
||||
{
|
||||
if (board::GetSocType() == SysClkSocType_Mariko && config::GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
board::PcvHijackGpuVolts(0);
|
||||
|
||||
u32 targetHz = gContext.overrideFreqs[SysClkModule_GPU];
|
||||
if (!targetHz) {
|
||||
targetHz = config::GetAutoClockHz(gContext.applicationId, SysClkModule_GPU, gContext.profile, false);
|
||||
if (!targetHz) {
|
||||
targetHz = config::GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, gContext.profile, false);
|
||||
}
|
||||
}
|
||||
u32 maxHz = GetMaxAllowedHz(SysClkModule_GPU, gContext.profile);
|
||||
u32 nearestHz = GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
||||
|
||||
board::SetHz(SysClkModule_GPU, ~0);
|
||||
if (targetHz) {
|
||||
board::SetHz(SysClkModule_GPU, nearestHz);
|
||||
} else {
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleFreqReset(SysClkModule module, bool isBoost)
|
||||
{
|
||||
switch (module) {
|
||||
case SysClkModule_CPU:
|
||||
if (!(isBoost || (config::GetConfigValue(HocClkConfigValue_OverwriteBoostMode) && isBoost)))
|
||||
board::ResetToStockCpu();
|
||||
if (config::GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) {
|
||||
if (board::GetSocType() == SysClkSocType_Erista)
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_eristaCpuUV), 0, 1581000000);
|
||||
else
|
||||
board::SetDfllTunings(config::GetConfigValue(KipConfigValue_marikoCpuUVLow), config::GetConfigValue(KipConfigValue_marikoCpuUVHigh), board::CalculateTbreak(config::GetConfigValue(KipConfigValue_tableConf)));
|
||||
}
|
||||
break;
|
||||
case SysClkModule_GPU:
|
||||
board::ResetToStockGpu();
|
||||
break;
|
||||
case SysClkModule_MEM:
|
||||
board::ResetToStockMem();
|
||||
DVFSReset();
|
||||
break;
|
||||
case HorizonOCModule_Display:
|
||||
if (config::GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate)) {
|
||||
board::ResetToStockDisplay();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetClocks(bool isBoost)
|
||||
{
|
||||
std::uint32_t targetHz = 0;
|
||||
std::uint32_t maxHz = 0;
|
||||
std::uint32_t nearestHz = 0;
|
||||
|
||||
if (isBoost && !config::GetConfigValue(HocClkConfigValue_OverwriteBoostMode)) {
|
||||
u32 boostFreq = board::GetHz(SysClkModule_CPU);
|
||||
if (boostFreq / 1000000 > 1785) {
|
||||
board::SetHz(SysClkModule_CPU, boostFreq);
|
||||
}
|
||||
return; // Return if we aren't overwriting boost mode
|
||||
}
|
||||
|
||||
bool returnRaw = false; // Return a value scaled to MHz instead of raw value
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
u32 oldHz = board::GetHz((SysClkModule)module); // Get Old hz (used primarily for DVFS Logic)
|
||||
|
||||
if (module > SysClkModule_MEM)
|
||||
returnRaw = true;
|
||||
else
|
||||
returnRaw = false;
|
||||
targetHz = gContext.overrideFreqs[module];
|
||||
if (!targetHz) {
|
||||
targetHz = config::GetAutoClockHz(gContext.applicationId, (SysClkModule)module, gContext.profile, returnRaw);
|
||||
if (!targetHz)
|
||||
targetHz = config::GetAutoClockHz(GLOBAL_PROFILE_ID, (SysClkModule)module, gContext.profile, returnRaw);
|
||||
}
|
||||
|
||||
if (module == HorizonOCModule_Governor) {
|
||||
governor::HandleGovernor(targetHz);
|
||||
}
|
||||
|
||||
bool noCPU = governor::isCpuGovernorEnabled;
|
||||
bool noGPU = governor::isGpuGovernorEnabled;
|
||||
bool noDisp = governor::isVRREnabled;
|
||||
if (noDisp && module == HorizonOCModule_Display)
|
||||
continue;
|
||||
|
||||
if (module == HorizonOCModule_Display && config::GetConfigValue(HorizonOCConfigValue_OverwriteRefreshRate) && !noDisp) {
|
||||
if (targetHz) {
|
||||
board::SetHz(HorizonOCModule_Display, targetHz);
|
||||
gContext.freqs[HorizonOCModule_Display] = targetHz;
|
||||
gContext.realFreqs[HorizonOCModule_Display] = targetHz;
|
||||
} else {
|
||||
HandleFreqReset(HorizonOCModule_Display, isBoost);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip GPU and CPU if governors handle them
|
||||
if (module > SysClkModule_MEM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (noCPU && module == SysClkModule_CPU)
|
||||
continue;
|
||||
if (noGPU && module == SysClkModule_GPU)
|
||||
continue;
|
||||
|
||||
if (targetHz) {
|
||||
maxHz = GetMaxAllowedHz((SysClkModule)module, gContext.profile);
|
||||
nearestHz = GetNearestHz((SysClkModule)module, targetHz, maxHz);
|
||||
|
||||
if (nearestHz != gContext.freqs[module]) {
|
||||
fileUtils::LogLine(
|
||||
"[mgr] %s clock set : %u.%u MHz (target = %u.%u MHz)",
|
||||
board::GetModuleName((SysClkModule)module, true),
|
||||
nearestHz / 1000000, nearestHz / 100000 - nearestHz / 1000000 * 10,
|
||||
targetHz / 1000000, targetHz / 100000 - targetHz / 1000000 * 10
|
||||
);
|
||||
|
||||
if (module == SysClkModule_MEM && board::GetSocType() == SysClkSocType_Mariko && targetHz > oldHz && config::GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
DVFSBeforeSet(targetHz);
|
||||
}
|
||||
|
||||
board::SetHz((SysClkModule)module, nearestHz);
|
||||
gContext.freqs[module] = nearestHz;
|
||||
|
||||
if (module == SysClkModule_CPU && config::GetConfigValue(HorizonOCConfigValue_LiveCpuUv)) {
|
||||
HandleCpuUv();
|
||||
}
|
||||
|
||||
if (module == SysClkModule_MEM && board::GetSocType() == SysClkSocType_Mariko && targetHz < oldHz && config::GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
DVFSAfterSet(targetHz);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HandleFreqReset((SysClkModule)module, isBoost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RefreshContext()
|
||||
{
|
||||
bool hasChanged = false;
|
||||
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
|
||||
std::uint64_t applicationId = processManagement::GetCurrentApplicationId();
|
||||
if (applicationId != gContext.applicationId) {
|
||||
fileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
|
||||
gContext.applicationId = applicationId;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
SysClkProfile profile = board::GetProfile();
|
||||
if (profile != gContext.profile) {
|
||||
fileUtils::LogLine("[mgr] Profile change: %s", board::GetProfileName(profile, true));
|
||||
gContext.profile = profile;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
// restore clocks to stock values on app or profile change
|
||||
if (hasChanged) {
|
||||
board::ResetToStock();
|
||||
if (board::GetSocType() == SysClkSocType_Mariko && config::GetConfigValue(HorizonOCConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
board::PcvHijackGpuVolts(0);
|
||||
board::SetHz(SysClkModule_GPU, ~0);
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
WaitForNextTick();
|
||||
}
|
||||
|
||||
std::uint32_t hz = 0;
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
hz = board::GetHz((SysClkModule)module);
|
||||
if (hz != 0 && hz != gContext.freqs[module]) {
|
||||
fileUtils::LogLine("[mgr] %s clock change: %u.%u MHz", board::GetModuleName((SysClkModule)module, true), hz / 1000000, hz / 100000 - hz / 1000000 * 10);
|
||||
gContext.freqs[module] = hz;
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
hz = config::GetOverrideHz((SysClkModule)module);
|
||||
if (hz != gContext.overrideFreqs[module]) {
|
||||
if (hz) {
|
||||
fileUtils::LogLine("[mgr] %s override change: %u.%u MHz", board::GetModuleName((SysClkModule)module, true), hz / 1000000, hz / 100000 - hz / 1000000 * 10);
|
||||
}
|
||||
gContext.overrideFreqs[module] = hz;
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t ns = armTicksToNs(armGetSystemTick());
|
||||
|
||||
// temperatures do not and should not force a refresh, hasChanged untouched
|
||||
std::uint32_t millis = 0;
|
||||
bool shouldLogTemp = ConfigIntervalTimeout(SysClkConfigValue_TempLogIntervalMs, ns, &gLastTempLogNs);
|
||||
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++) {
|
||||
millis = board::GetTemperatureMilli((SysClkThermalSensor)sensor);
|
||||
if (shouldLogTemp) {
|
||||
fileUtils::LogLine("[mgr] %s temp: %u.%u °C", board::GetThermalSensorName((SysClkThermalSensor)sensor, true), millis / 1000, (millis - millis / 1000 * 1000) / 100);
|
||||
}
|
||||
gContext.temps[sensor] = millis;
|
||||
}
|
||||
|
||||
// power stats do not and should not force a refresh, hasChanged untouched
|
||||
std::int32_t mw = 0;
|
||||
bool shouldLogPower = ConfigIntervalTimeout(SysClkConfigValue_PowerLogIntervalMs, ns, &gLastPowerLogNs);
|
||||
for (unsigned int sensor = 0; sensor < SysClkPowerSensor_EnumMax; sensor++) {
|
||||
mw = board::GetPowerMw((SysClkPowerSensor)sensor);
|
||||
if (shouldLogPower) {
|
||||
fileUtils::LogLine("[mgr] Power %s: %d mW", board::GetPowerSensorName((SysClkPowerSensor)sensor, false), mw);
|
||||
}
|
||||
gContext.power[sensor] = mw;
|
||||
}
|
||||
|
||||
// real freqs do not and should not force a refresh, hasChanged untouched
|
||||
std::uint32_t realHz = 0;
|
||||
bool shouldLogFreq = ConfigIntervalTimeout(SysClkConfigValue_FreqLogIntervalMs, ns, &gLastFreqLogNs);
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
realHz = board::GetRealHz((SysClkModule)module);
|
||||
if (shouldLogFreq) {
|
||||
fileUtils::LogLine("[mgr] %s real freq: %u.%u MHz", board::GetModuleName((SysClkModule)module, true), realHz / 1000000, realHz / 100000 - realHz / 1000000 * 10);
|
||||
}
|
||||
gContext.realFreqs[module] = realHz;
|
||||
}
|
||||
|
||||
// ram load do not and should not force a refresh, hasChanged untouched
|
||||
for (unsigned int loadSource = 0; loadSource < SysClkPartLoad_EnumMax; loadSource++) {
|
||||
gContext.partLoad[loadSource] = board::GetPartLoad((SysClkPartLoad)loadSource);
|
||||
}
|
||||
|
||||
for (unsigned int voltageSource = 0; voltageSource < HocClkVoltage_EnumMax; voltageSource++) {
|
||||
gContext.voltages[voltageSource] = board::GetVoltage((HocClkVoltage)voltageSource);
|
||||
}
|
||||
|
||||
if (ConfigIntervalTimeout(SysClkConfigValue_CsvWriteIntervalMs, ns, &gLastCsvWriteNs)) {
|
||||
fileUtils::WriteContextToCsv(&gContext);
|
||||
}
|
||||
|
||||
// this->context->maxDisplayFreq = board::GetHighestDockedDisplayRate();
|
||||
u32 targetHz = gContext.overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz) {
|
||||
targetHz = config::GetAutoClockHz(gContext.applicationId, HorizonOCModule_Display, gContext.profile, true);
|
||||
if (!targetHz)
|
||||
targetHz = config::GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, gContext.profile, true);
|
||||
}
|
||||
|
||||
if (board::GetConsoleType() != HorizonOCConsoleType_Hoag)
|
||||
board::SetDisplayRefreshDockedState(gContext.profile == SysClkProfile_Docked);
|
||||
|
||||
if (gContext.isSaltyNXInstalled)
|
||||
gContext.fps = integrations::GetSaltyNXFPS();
|
||||
else
|
||||
gContext.fps = 254; // N/A
|
||||
|
||||
if (gContext.isSaltyNXInstalled)
|
||||
gContext.resolutionHeight = integrations::GetSaltyNXResolutionHeight();
|
||||
else
|
||||
gContext.resolutionHeight = 0; // N/A
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
config::Initialize();
|
||||
|
||||
gContext = {};
|
||||
gContext.applicationId = 0;
|
||||
gContext.profile = SysClkProfile_Handheld;
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
gContext.freqs[module] = 0;
|
||||
gContext.realFreqs[module] = 0;
|
||||
gContext.overrideFreqs[module] = 0;
|
||||
RefreshFreqTableRow((SysClkModule)module);
|
||||
}
|
||||
|
||||
gRunning = false;
|
||||
gLastTempLogNs = 0;
|
||||
gLastCsvWriteNs = 0;
|
||||
|
||||
kip::GetKipData();
|
||||
|
||||
board::FuseData *fuse = board::GetFuseData();
|
||||
|
||||
gContext.speedos[0] = fuse->cpuSpeedo;
|
||||
gContext.speedos[1] = fuse->gpuSpeedo;
|
||||
gContext.speedos[2] = fuse->socSpeedo;
|
||||
gContext.iddq[0] = fuse->cpuIDDQ;
|
||||
gContext.iddq[1] = fuse->gpuIDDQ;
|
||||
gContext.iddq[2] = fuse->socIDDQ;
|
||||
gContext.waferX = fuse->waferX;
|
||||
gContext.waferY = fuse->waferY;
|
||||
|
||||
gContext.dramID = board::GetDramID();
|
||||
gContext.isDram8GB = board::IsDram8GB();
|
||||
board::SetGpuSchedulingMode((GpuSchedulingMode)config::GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)config::GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
|
||||
gContext.gpuSchedulingMode = (GpuSchedulingMode)config::GetConfigValue(HorizonOCConfigValue_GPUScheduling);
|
||||
|
||||
gContext.isSysDockInstalled = integrations::GetSysDockState();
|
||||
gContext.isSaltyNXInstalled = integrations::GetSaltyNXState();
|
||||
if (gContext.isSaltyNXInstalled) {
|
||||
integrations::LoadSaltyNX();
|
||||
}
|
||||
|
||||
gContext.isUsingRetroSuper = integrations::GetRETROSuperStatus();
|
||||
governor::startThreads();
|
||||
}
|
||||
|
||||
void Exit()
|
||||
{
|
||||
governor::exitThreads();
|
||||
config::Exit();
|
||||
}
|
||||
|
||||
SysClkContext GetCurrentContext()
|
||||
{
|
||||
std::scoped_lock lock{gContextMutex};
|
||||
return gContext;
|
||||
}
|
||||
|
||||
void SetRunning(bool running)
|
||||
{
|
||||
gRunning = running;
|
||||
}
|
||||
|
||||
bool Running()
|
||||
{
|
||||
return gRunning;
|
||||
}
|
||||
|
||||
void GetFreqList(SysClkModule module, std::uint32_t *list, std::uint32_t maxCount, std::uint32_t *outCount)
|
||||
{
|
||||
ASSERT_ENUM_VALID(SysClkModule, module);
|
||||
|
||||
*outCount = std::min(maxCount, gFreqTable[module].count);
|
||||
memcpy(list, &gFreqTable[module].list[0], *outCount * sizeof(gFreqTable[0].list[0]));
|
||||
}
|
||||
|
||||
void Tick()
|
||||
{
|
||||
fileUtils::LogLine("CPU Temp: %d", board::GetTemperatureMilli(HorizonOCThermalSensor_CPU));
|
||||
std::scoped_lock lock{gContextMutex};
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
|
||||
bool isBoost = apmExtIsBoostMode(mode);
|
||||
|
||||
HandleSafetyFeatures();
|
||||
|
||||
if (RefreshContext() || config::Refresh()) {
|
||||
HandleMiscFeatures();
|
||||
SetClocks(isBoost);
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForNextTick()
|
||||
{
|
||||
if (board::GetHz(SysClkModule_MEM) > 665000000)
|
||||
svcSleepThread(config::GetConfigValue(SysClkConfigValue_PollingIntervalMs) * 1000000ULL);
|
||||
else
|
||||
svcSleepThread(5000 * 1000000ULL); // 5 seconds in sleep mode
|
||||
}
|
||||
} // namespace clockManager
|
||||
69
Source/hoc-clk/sysmodule/src/clock_manager.hpp
Normal file
69
Source/hoc-clk/sysmodule/src/clock_manager.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
#include <nxExt/cpp/lockable_mutex.h>
|
||||
|
||||
namespace clockManager {
|
||||
|
||||
struct FreqTable {
|
||||
std::uint32_t count;
|
||||
std::uint32_t list[SYSCLK_FREQ_LIST_MAX];
|
||||
};
|
||||
|
||||
|
||||
extern bool hasChanged;
|
||||
|
||||
// instance variables
|
||||
extern bool gRunning;
|
||||
extern LockableMutex gContextMutex;
|
||||
extern SysClkContext gContext;
|
||||
extern FreqTable gFreqTable[SysClkModule_EnumMax];
|
||||
extern std::uint64_t gLastTempLogNs;
|
||||
extern std::uint64_t gLastFreqLogNs;
|
||||
extern std::uint64_t gLastPowerLogNs;
|
||||
extern std::uint64_t gLastCsvWriteNs;
|
||||
|
||||
|
||||
void Initialize();
|
||||
void Exit();
|
||||
|
||||
SysClkContext GetCurrentContext();
|
||||
|
||||
void SetRunning(bool running);
|
||||
bool Running();
|
||||
|
||||
std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile);
|
||||
bool IsAssignableHz(SysClkModule module, std::uint32_t hz);
|
||||
|
||||
void GetFreqList(SysClkModule module, std::uint32_t* list, std::uint32_t maxCount, std::uint32_t* outCount);
|
||||
|
||||
void Tick();
|
||||
void WaitForNextTick();
|
||||
}
|
||||
477
Source/hoc-clk/sysmodule/src/config.cpp
Normal file
477
Source/hoc-clk/sysmodule/src/config.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "config.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <initializer_list>
|
||||
#include <minIni.h>
|
||||
#include <nxExt.h>
|
||||
#include "board/board.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "file_utils.hpp"
|
||||
|
||||
namespace config {
|
||||
|
||||
uint64_t configValues[SysClkConfigValue_EnumMax];
|
||||
|
||||
namespace {
|
||||
|
||||
bool gLoaded = false;
|
||||
std::string gPath;
|
||||
time_t gMtime = 0;
|
||||
std::atomic_bool gEnabled{false};
|
||||
std::uint32_t gOverrideFreqs[SysClkModule_EnumMax];
|
||||
std::map<std::tuple<std::uint64_t, SysClkProfile, SysClkModule>, std::uint32_t> gProfileMHzMap;
|
||||
std::map<std::uint64_t, std::uint8_t> gProfileCountMap;
|
||||
LockableMutex gConfigMutex;
|
||||
LockableMutex gOverrideMutex;
|
||||
|
||||
time_t CheckModificationTime() {
|
||||
time_t mtime = 0;
|
||||
struct stat st;
|
||||
if (stat(gPath.c_str(), &st) == 0) {
|
||||
mtime = st.st_mtime;
|
||||
}
|
||||
return mtime;
|
||||
}
|
||||
|
||||
std::uint32_t FindClockMHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile) {
|
||||
if (gLoaded) {
|
||||
auto it = gProfileMHzMap.find(std::make_tuple(tid, profile, module));
|
||||
if (it != gProfileMHzMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t FindClockHzFromProfiles(std::uint64_t tid, SysClkModule module, std::initializer_list<SysClkProfile> profiles, u32 mhzMultiplier = 1000000) {
|
||||
std::uint32_t mhz = 0;
|
||||
|
||||
if (gLoaded) {
|
||||
for (auto profile: profiles) {
|
||||
mhz = FindClockMHz(tid, module, profile);
|
||||
if (mhz) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::max((std::uint32_t)0, mhz * mhzMultiplier);
|
||||
}
|
||||
|
||||
int BrowseIniFunc(const char* section, const char* key, const char* value, void* userdata) {
|
||||
(void)userdata;
|
||||
std::uint64_t input;
|
||||
if (!strcmp(section, CONFIG_VAL_SECTION)) {
|
||||
for (unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) {
|
||||
if (!strcmp(key, sysclkFormatConfigValue((SysClkConfigValue)kval, false))) {
|
||||
input = strtoul(value, NULL, 0);
|
||||
if (!sysclkValidConfigValue((SysClkConfigValue)kval, input)) {
|
||||
input = sysclkDefaultConfigValue((SysClkConfigValue)kval);
|
||||
fileUtils::LogLine("[cfg] Invalid value for key '%s' in section '%s': using default %d", key, section, input);
|
||||
}
|
||||
configValues[kval] = input;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Unrecognized config value", key, section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::uint64_t tid = strtoul(section, NULL, 16);
|
||||
|
||||
if (!tid || strlen(section) != 16) {
|
||||
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Invalid TitleID", key, section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SysClkProfile parsedProfile = SysClkProfile_EnumMax;
|
||||
SysClkModule parsedModule = SysClkModule_EnumMax;
|
||||
|
||||
for (unsigned int profile = 0; profile < SysClkProfile_EnumMax; profile++) {
|
||||
const char* profileCode = board::GetProfileName((SysClkProfile)profile, false);
|
||||
size_t profileCodeLen = strlen(profileCode);
|
||||
|
||||
if (!strncmp(key, profileCode, profileCodeLen) && key[profileCodeLen] == '_') {
|
||||
const char* subkey = key + profileCodeLen + 1;
|
||||
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
const char* moduleCode = board::GetModuleName((SysClkModule)module, false);
|
||||
size_t moduleCodeLen = strlen(moduleCode);
|
||||
if (!strncmp(subkey, moduleCode, moduleCodeLen) && subkey[moduleCodeLen] == '\0') {
|
||||
parsedProfile = (SysClkProfile)profile;
|
||||
parsedModule = (SysClkModule)module;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedModule == SysClkModule_EnumMax || parsedProfile == SysClkProfile_EnumMax) {
|
||||
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Unrecognized key", key, section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::uint32_t mhz = strtoul(value, NULL, 10);
|
||||
if (!mhz) {
|
||||
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Invalid value", key, section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
gProfileMHzMap[std::make_tuple(tid, parsedProfile, parsedModule)] = mhz;
|
||||
auto it = gProfileCountMap.find(tid);
|
||||
if (it == gProfileCountMap.end()) {
|
||||
gProfileCountMap[tid] = 1;
|
||||
} else {
|
||||
it->second++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Close() {
|
||||
gLoaded = false;
|
||||
gProfileMHzMap.clear();
|
||||
gProfileCountMap.clear();
|
||||
for (unsigned int i = 0; i < SysClkConfigValue_EnumMax; i++) {
|
||||
configValues[i] = sysclkDefaultConfigValue((SysClkConfigValue)i);
|
||||
}
|
||||
}
|
||||
|
||||
void Load() {
|
||||
fileUtils::LogLine("[cfg] Reading %s", gPath.c_str());
|
||||
|
||||
Close();
|
||||
gMtime = CheckModificationTime();
|
||||
if (!gMtime) {
|
||||
fileUtils::LogLine("[cfg] Error finding file");
|
||||
} else if (!ini_browse(&BrowseIniFunc, nullptr, gPath.c_str())) {
|
||||
fileUtils::LogLine("[cfg] Error loading file");
|
||||
}
|
||||
|
||||
gLoaded = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
gPath = FILE_CONFIG_DIR "/config.ini";
|
||||
gLoaded = false;
|
||||
gProfileMHzMap.clear();
|
||||
gProfileCountMap.clear();
|
||||
gMtime = 0;
|
||||
gEnabled = false;
|
||||
for (unsigned int i = 0; i < SysClkModule_EnumMax; i++) {
|
||||
gOverrideFreqs[i] = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < SysClkConfigValue_EnumMax; i++) {
|
||||
configValues[i] = sysclkDefaultConfigValue((SysClkConfigValue)i);
|
||||
}
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
Close();
|
||||
}
|
||||
|
||||
bool Refresh() {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
if (!gLoaded || gMtime != CheckModificationTime()) {
|
||||
Load();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasProfilesLoaded() {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
return gLoaded;
|
||||
}
|
||||
|
||||
std::uint32_t GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile, bool returnRaw) {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
switch (profile) {
|
||||
case SysClkProfile_Handheld:
|
||||
return FindClockHzFromProfiles(tid, module, {SysClkProfile_Handheld}, returnRaw ? 1 : 1000000);
|
||||
case SysClkProfile_HandheldCharging:
|
||||
case SysClkProfile_HandheldChargingUSB:
|
||||
return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingUSB, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}, returnRaw ? 1 : 1000000);
|
||||
case SysClkProfile_HandheldChargingOfficial:
|
||||
return FindClockHzFromProfiles(tid, module, {SysClkProfile_HandheldChargingOfficial, SysClkProfile_HandheldCharging, SysClkProfile_Handheld}, returnRaw ? 1 : 1000000);
|
||||
case SysClkProfile_Docked:
|
||||
return FindClockHzFromProfiles(tid, module, {SysClkProfile_Docked}, returnRaw ? 1 : 1000000);
|
||||
default:
|
||||
ERROR_THROW("Unhandled SysClkProfile: %u", profile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetProfiles(std::uint64_t tid, SysClkTitleProfileList* out_profiles) {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
for (unsigned int profile = 0; profile < SysClkProfile_EnumMax; profile++) {
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
out_profiles->mhzMap[profile][module] = FindClockMHz(tid, (SysClkModule)module, (SysClkProfile)profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SetProfiles(std::uint64_t tid, SysClkTitleProfileList* profiles, bool immediate) {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
uint8_t numProfiles = 0;
|
||||
|
||||
char section[17] = {0};
|
||||
snprintf(section, sizeof(section), "%016lX", tid);
|
||||
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
keys.reserve(SysClkProfile_EnumMax * SysClkModule_EnumMax);
|
||||
values.reserve(SysClkProfile_EnumMax * SysClkModule_EnumMax);
|
||||
|
||||
std::uint32_t* mhz = &profiles->mhz[0];
|
||||
|
||||
for (unsigned int profile = 0; profile < SysClkProfile_EnumMax; profile++) {
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
if (*mhz) {
|
||||
numProfiles++;
|
||||
|
||||
std::string key = std::string(board::GetProfileName((SysClkProfile)profile, false)) +
|
||||
"_" +
|
||||
board::GetModuleName((SysClkModule)module, false);
|
||||
std::string value = std::to_string(*mhz);
|
||||
|
||||
keys.push_back(key);
|
||||
values.push_back(value);
|
||||
}
|
||||
mhz++;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const char*> keyPointers;
|
||||
std::vector<const char*> valuePointers;
|
||||
keyPointers.reserve(keys.size() + 1);
|
||||
valuePointers.reserve(values.size() + 1);
|
||||
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
keyPointers.push_back(keys[i].c_str());
|
||||
valuePointers.push_back(values[i].c_str());
|
||||
}
|
||||
keyPointers.push_back(NULL);
|
||||
valuePointers.push_back(NULL);
|
||||
|
||||
if (!ini_putsection(section, keyPointers.data(), valuePointers.data(), gPath.c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
mhz = &profiles->mhz[0];
|
||||
gProfileCountMap[tid] = numProfiles;
|
||||
for (unsigned int profile = 0; profile < SysClkProfile_EnumMax; profile++) {
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
if (*mhz) {
|
||||
gProfileMHzMap[std::make_tuple(tid, (SysClkProfile)profile, (SysClkModule)module)] = *mhz;
|
||||
} else {
|
||||
gProfileMHzMap.erase(std::make_tuple(tid, (SysClkProfile)profile, (SysClkModule)module));
|
||||
}
|
||||
mhz++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint8_t GetProfileCount(std::uint64_t tid) {
|
||||
auto it = gProfileCountMap.find(tid);
|
||||
if (it == gProfileCountMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void SetEnabled(bool enabled) {
|
||||
gEnabled = enabled;
|
||||
}
|
||||
|
||||
bool Enabled() {
|
||||
return gEnabled;
|
||||
}
|
||||
|
||||
void SetOverrideHz(SysClkModule module, std::uint32_t hz) {
|
||||
ASSERT_ENUM_VALID(SysClkModule, module);
|
||||
std::scoped_lock lock{gOverrideMutex};
|
||||
gOverrideFreqs[module] = hz;
|
||||
}
|
||||
|
||||
std::uint32_t GetOverrideHz(SysClkModule module) {
|
||||
ASSERT_ENUM_VALID(SysClkModule, module);
|
||||
std::scoped_lock lock{gOverrideMutex};
|
||||
return gOverrideFreqs[module];
|
||||
}
|
||||
|
||||
std::uint64_t GetConfigValue(SysClkConfigValue kval) {
|
||||
ASSERT_ENUM_VALID(SysClkConfigValue, kval);
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
return configValues[kval];
|
||||
}
|
||||
|
||||
const char* GetConfigValueName(SysClkConfigValue kval, bool pretty) {
|
||||
ASSERT_ENUM_VALID(SysClkConfigValue, kval);
|
||||
return sysclkFormatConfigValue(kval, pretty);
|
||||
}
|
||||
|
||||
void GetConfigValues(SysClkConfigValueList* out_configValues) {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
for (unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) {
|
||||
out_configValues->values[kval] = configValues[kval];
|
||||
}
|
||||
}
|
||||
|
||||
bool SetConfigValues(SysClkConfigValueList* configValues, bool immediate) {
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
|
||||
std::vector<const char*> iniKeys;
|
||||
std::vector<std::string> iniValues;
|
||||
iniKeys.reserve(SysClkConfigValue_EnumMax + 1);
|
||||
iniValues.reserve(SysClkConfigValue_EnumMax);
|
||||
|
||||
for (unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) {
|
||||
if (!sysclkValidConfigValue((SysClkConfigValue)kval, configValues->values[kval]) ||
|
||||
configValues->values[kval] == sysclkDefaultConfigValue((SysClkConfigValue)kval)) {
|
||||
continue;
|
||||
}
|
||||
iniValues.push_back(std::to_string(configValues->values[kval]));
|
||||
iniKeys.push_back(sysclkFormatConfigValue((SysClkConfigValue)kval, false));
|
||||
}
|
||||
|
||||
iniKeys.push_back(NULL);
|
||||
|
||||
std::vector<const char*> valuePointers;
|
||||
valuePointers.reserve(iniValues.size() + 1);
|
||||
for (const auto& val : iniValues) {
|
||||
valuePointers.push_back(val.c_str());
|
||||
}
|
||||
valuePointers.push_back(NULL);
|
||||
|
||||
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
for (unsigned int kval = 0; kval < SysClkConfigValue_EnumMax; kval++) {
|
||||
if (sysclkValidConfigValue((SysClkConfigValue)kval, configValues->values[kval])) {
|
||||
config::configValues[kval] = configValues->values[kval];
|
||||
} else {
|
||||
config::configValues[kval] = sysclkDefaultConfigValue((SysClkConfigValue)kval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResetConfigValue(SysClkConfigValue kval) {
|
||||
if (!SYSCLK_ENUM_VALID(SysClkConfigValue, kval)) {
|
||||
fileUtils::LogLine("[cfg] Invalid SysClkConfigValue: %u", kval);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
|
||||
std::uint64_t defaultValue = sysclkDefaultConfigValue(kval);
|
||||
|
||||
std::vector<const char*> iniKeys;
|
||||
std::vector<std::string> iniValues;
|
||||
iniKeys.reserve(2);
|
||||
iniValues.reserve(1);
|
||||
|
||||
iniKeys.push_back(sysclkFormatConfigValue(kval, false));
|
||||
iniValues.push_back("");
|
||||
iniKeys.push_back(NULL);
|
||||
|
||||
std::vector<const char*> valuePointers;
|
||||
valuePointers.reserve(iniValues.size() + 1);
|
||||
for (const auto& val : iniValues) {
|
||||
valuePointers.push_back(val.c_str());
|
||||
}
|
||||
valuePointers.push_back(NULL);
|
||||
|
||||
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
|
||||
fileUtils::LogLine("[cfg] Failed to reset config value %u in INI", kval);
|
||||
return false;
|
||||
}
|
||||
|
||||
configValues[kval] = defaultValue;
|
||||
fileUtils::LogLine("[cfg] Reset config value %u to default: %llu", kval, defaultValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetConfigValue(SysClkConfigValue kval, std::uint64_t value, bool immediate) {
|
||||
if (!SYSCLK_ENUM_VALID(SysClkConfigValue, kval)) {
|
||||
return false;
|
||||
}
|
||||
if (!sysclkValidConfigValue(kval, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{gConfigMutex};
|
||||
|
||||
std::vector<const char*> iniKeys;
|
||||
std::vector<std::string> iniValues;
|
||||
iniKeys.reserve(2);
|
||||
iniValues.reserve(1);
|
||||
|
||||
iniKeys.push_back(sysclkFormatConfigValue(kval, false));
|
||||
iniValues.push_back(std::to_string(value));
|
||||
iniKeys.push_back(NULL);
|
||||
|
||||
std::vector<const char*> valuePointers;
|
||||
valuePointers.reserve(2);
|
||||
valuePointers.push_back(iniValues[0].c_str());
|
||||
valuePointers.push_back(NULL);
|
||||
|
||||
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
configValues[kval] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
61
Source/hoc-clk/sysmodule/src/config.hpp
Normal file
61
Source/hoc-clk/sysmodule/src/config.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
|
||||
#define CONFIG_VAL_SECTION "values"
|
||||
|
||||
namespace config {
|
||||
|
||||
void Initialize();
|
||||
void Exit();
|
||||
|
||||
bool Refresh();
|
||||
bool HasProfilesLoaded();
|
||||
|
||||
std::uint8_t GetProfileCount(std::uint64_t tid);
|
||||
void GetProfiles(std::uint64_t tid, SysClkTitleProfileList* out_profiles);
|
||||
bool SetProfiles(std::uint64_t tid, SysClkTitleProfileList* profiles, bool immediate);
|
||||
std::uint32_t GetAutoClockHz(std::uint64_t tid, SysClkModule module, SysClkProfile profile, bool returnRaw);
|
||||
|
||||
void SetEnabled(bool enabled);
|
||||
bool Enabled();
|
||||
void SetOverrideHz(SysClkModule module, std::uint32_t hz);
|
||||
std::uint32_t GetOverrideHz(SysClkModule module);
|
||||
|
||||
std::uint64_t GetConfigValue(SysClkConfigValue val);
|
||||
const char* GetConfigValueName(SysClkConfigValue val, bool pretty);
|
||||
void GetConfigValues(SysClkConfigValueList* out_configValues);
|
||||
bool SetConfigValues(SysClkConfigValueList* configValues, bool immediate);
|
||||
bool ResetConfigValue(SysClkConfigValue kval);
|
||||
bool SetConfigValue(SysClkConfigValue kval, std::uint64_t value, bool immediate = true);
|
||||
|
||||
extern uint64_t configValues[SysClkConfigValue_EnumMax];
|
||||
|
||||
}
|
||||
57
Source/hoc-clk/sysmodule/src/errors.cpp
Normal file
57
Source/hoc-clk/sysmodule/src/errors.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "errors.hpp"
|
||||
#include "file_utils.hpp"
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
|
||||
namespace errors {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* FormatMessage(const char* format, va_list args) {
|
||||
size_t len = vsnprintf(NULL, 0, format, args) * sizeof(char);
|
||||
char* buf = (char*)malloc(len + 1);
|
||||
if (buf == NULL) {
|
||||
return format;
|
||||
}
|
||||
vsnprintf(buf, len + 1, format, args);
|
||||
return buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ThrowException(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const char* msg = FormatMessage(format, args);
|
||||
va_end(args);
|
||||
fileUtils::LogLine(format, args);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
}
|
||||
48
Source/hoc-clk/sysmodule/src/errors.hpp
Normal file
48
Source/hoc-clk/sysmodule/src/errors.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#define ERROR_THROW(format, ...) errors::ThrowException(format "\n in %s:%u", ##__VA_ARGS__, __FILE__, __LINE__)
|
||||
#define ERROR_RESULT_THROW(rc, format, ...) ERROR_THROW(format "\n RC: [0x%x] %04d-%04d", ##__VA_ARGS__, rc, R_MODULE(rc), R_DESCRIPTION(rc))
|
||||
#define ASSERT_RESULT_OK(rc, format, ...) \
|
||||
if (R_FAILED(rc)) \
|
||||
{ \
|
||||
ERROR_RESULT_THROW(rc, "ASSERT_RESULT_OK: " format, ##__VA_ARGS__); \
|
||||
}
|
||||
#define ASSERT_ENUM_VALID(n, v) \
|
||||
if (!SYSCLK_ENUM_VALID(n, v)) { \
|
||||
ERROR_THROW("No such %s: %u", #n, v); \
|
||||
}
|
||||
|
||||
namespace errors {
|
||||
|
||||
void ThrowException(const char* format, ...);
|
||||
|
||||
}
|
||||
200
Source/hoc-clk/sysmodule/src/file_utils.cpp
Normal file
200
Source/hoc-clk/sysmodule/src/file_utils.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "file_utils.hpp"
|
||||
#include <nxExt.h>
|
||||
|
||||
extern "C" void __libnx_init_time(void);
|
||||
|
||||
namespace fileUtils {
|
||||
|
||||
namespace {
|
||||
|
||||
LockableMutex g_log_mutex;
|
||||
LockableMutex g_csv_mutex;
|
||||
std::atomic_bool g_has_initialized = false;
|
||||
bool g_log_enabled = false;
|
||||
std::uint64_t g_last_flag_check = 0;
|
||||
|
||||
void RefreshFlags(bool force) {
|
||||
std::uint64_t now = armTicksToNs(armGetSystemTick());
|
||||
if (!force && (now - g_last_flag_check) < FILE_FLAG_CHECK_INTERVAL_NS) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* file = fopen(FILE_LOG_FLAG_PATH, "r");
|
||||
if (file) {
|
||||
g_log_enabled = true;
|
||||
fclose(file);
|
||||
} else {
|
||||
g_log_enabled = false;
|
||||
}
|
||||
|
||||
g_last_flag_check = now;
|
||||
}
|
||||
|
||||
void InitializeThreadFunc(void* args) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsInitialized() {
|
||||
return g_has_initialized;
|
||||
}
|
||||
|
||||
bool IsLogEnabled() {
|
||||
return g_log_enabled;
|
||||
}
|
||||
|
||||
void LogLine(const char* format, ...) {
|
||||
std::scoped_lock lock{g_log_mutex};
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (g_has_initialized) {
|
||||
RefreshFlags(false);
|
||||
|
||||
if (g_log_enabled) {
|
||||
FILE* file = fopen(FILE_LOG_FILE_PATH, "a");
|
||||
|
||||
if (file) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
struct tm* nowTm = localtime(&now.tv_sec);
|
||||
|
||||
fprintf(file, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] ", nowTm->tm_year+1900, nowTm->tm_mon+1, nowTm->tm_mday, nowTm->tm_hour, nowTm->tm_min, nowTm->tm_sec, now.tv_nsec / 1000000UL);
|
||||
vfprintf(file, format, args);
|
||||
fprintf(file, "\n");
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void WriteContextToCsv(const SysClkContext* context) {
|
||||
std::scoped_lock lock{g_csv_mutex};
|
||||
|
||||
FILE* file = fopen(FILE_CONTEXT_CSV_PATH, "a");
|
||||
|
||||
if (file) {
|
||||
// Print header
|
||||
if (!ftell(file)) {
|
||||
fprintf(file, "timestamp,profile,app_tid");
|
||||
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
fprintf(file, ",%s_hz", sysclkFormatModule((SysClkModule)module, false));
|
||||
}
|
||||
|
||||
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++) {
|
||||
fprintf(file, ",%s_milliC", sysclkFormatThermalSensor((SysClkThermalSensor)sensor, false));
|
||||
}
|
||||
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
fprintf(file, ",%s_real_hz", sysclkFormatModule((SysClkModule)module, false));
|
||||
}
|
||||
|
||||
for (unsigned int sensor = 0; sensor < SysClkPowerSensor_EnumMax; sensor++) {
|
||||
fprintf(file, ",%s_mw", sysclkFormatPowerSensor((SysClkPowerSensor)sensor, false));
|
||||
}
|
||||
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
fprintf(file, "%ld%03ld,%s,%016lx", now.tv_sec, now.tv_nsec / 1000000UL, sysclkFormatProfile(context->profile, false), context->applicationId);
|
||||
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
fprintf(file, ",%d", context->freqs[module]);
|
||||
}
|
||||
|
||||
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++) {
|
||||
fprintf(file, ",%d", context->temps[sensor]);
|
||||
}
|
||||
|
||||
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++) {
|
||||
fprintf(file, ",%d", context->realFreqs[module]);
|
||||
}
|
||||
|
||||
for (unsigned int sensor = 0; sensor < SysClkPowerSensor_EnumMax; sensor++) {
|
||||
fprintf(file, ",%d", context->power[sensor]);
|
||||
}
|
||||
|
||||
fprintf(file, "\n");
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeAsync() {
|
||||
Thread initThread = {0};
|
||||
threadCreate(&initThread, InitializeThreadFunc, NULL, NULL, 0x4000, 0x15, 0);
|
||||
threadStart(&initThread);
|
||||
}
|
||||
|
||||
Result Initialize() {
|
||||
Result rc = 0;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = timeInitialize();
|
||||
}
|
||||
|
||||
__libnx_init_time();
|
||||
timeExit();
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = fsInitialize();
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = fsdevMountSdmc();
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
RefreshFlags(true);
|
||||
g_has_initialized = true;
|
||||
LogLine("=== hoc-clk " TARGET_VERSION " ===");
|
||||
LogLine("by m4xw, natinusala, p-sam, Souldbminer, Lightos_ and Dominatorul");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
if (!g_has_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_has_initialized = false;
|
||||
g_log_enabled = false;
|
||||
|
||||
fsdevUnmountAll();
|
||||
fsExit();
|
||||
}
|
||||
|
||||
}
|
||||
53
Source/hoc-clk/sysmodule/src/file_utils.hpp
Normal file
53
Source/hoc-clk/sysmodule/src/file_utils.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <cstdarg>
|
||||
#include <sysclk.h>
|
||||
|
||||
#define FILE_CONFIG_DIR "/config/" TARGET
|
||||
#define FILE_FLAG_CHECK_INTERVAL_NS (10000ULL * 1000000000ULL)
|
||||
#define FILE_CONTEXT_CSV_PATH FILE_CONFIG_DIR "/context.csv"
|
||||
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
|
||||
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
|
||||
|
||||
namespace fileUtils {
|
||||
|
||||
void Exit();
|
||||
Result Initialize();
|
||||
bool IsInitialized();
|
||||
bool IsLogEnabled();
|
||||
void InitializeAsync();
|
||||
void LogLine(const char* format, ...);
|
||||
void WriteContextToCsv(const SysClkContext* context);
|
||||
|
||||
}
|
||||
349
Source/hoc-clk/sysmodule/src/governor.cpp
Normal file
349
Source/hoc-clk/sysmodule/src/governor.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
#include "governor.hpp"
|
||||
|
||||
namespace governor {
|
||||
|
||||
#define POLL_NS 5'000'000 // 5 ms – governor poll rate
|
||||
#define DOWN_HOLD_TICKS 10 // 50 ms – how long to in POLL_NS to hold while ramping down
|
||||
#define STEP_UTIL 900 // multiplier for step calculations
|
||||
|
||||
bool isGpuGovernorEnabled = false;
|
||||
bool isCpuGovernorEnabled = false;
|
||||
bool lastGpuGovernorState = false;
|
||||
bool lastCpuGovernorState = false;
|
||||
bool lastVrrGovernorState = false;
|
||||
bool hasChanged = true;
|
||||
bool isCpuGovernorInBoostMode = false;
|
||||
bool isVRREnabled = false;
|
||||
|
||||
// thread handles
|
||||
Thread cpuGovernorTHREAD;
|
||||
Thread gpuGovernorTHREAD;
|
||||
Thread vrrTHREAD;
|
||||
|
||||
void HandleGovernor(uint32_t targetHz)
|
||||
{
|
||||
u32 tempTargetHz = clockManager::gContext.overrideFreqs[HorizonOCModule_Governor];
|
||||
if (!tempTargetHz) {
|
||||
tempTargetHz = config::GetAutoClockHz(clockManager::gContext.applicationId, HorizonOCModule_Governor, clockManager::gContext.profile, true);
|
||||
if (!tempTargetHz)
|
||||
tempTargetHz = config::GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Governor, clockManager::gContext.profile, true);
|
||||
}
|
||||
|
||||
auto resolve = [](u8 app, u8 temp) -> u8 {
|
||||
if (temp == ComponentGovernor_Disabled) return ComponentGovernor_Disabled;
|
||||
if (temp != ComponentGovernor_DoNotOverride) return temp;
|
||||
return app;
|
||||
};
|
||||
|
||||
u8 effectiveCpu = resolve(GovernorStateCpu(targetHz), GovernorStateCpu(tempTargetHz));
|
||||
u8 effectiveGpu = resolve(GovernorStateGpu(targetHz), GovernorStateGpu(tempTargetHz));
|
||||
u8 effectiveVrr = resolve(GovernorStateVrr(targetHz), GovernorStateVrr(tempTargetHz));
|
||||
|
||||
bool newCpuGovernorState = (effectiveCpu == ComponentGovernor_Enabled);
|
||||
bool newGpuGovernorState = (effectiveGpu == ComponentGovernor_Enabled);
|
||||
bool newVrrGovernorState = (effectiveVrr == ComponentGovernor_Enabled);
|
||||
|
||||
isCpuGovernorEnabled = newCpuGovernorState;
|
||||
isGpuGovernorEnabled = newGpuGovernorState;
|
||||
isVRREnabled = newVrrGovernorState;
|
||||
|
||||
if (newCpuGovernorState == false && lastCpuGovernorState == true) {
|
||||
svcSleepThread(100'000'000); // thread syncing. probably a cleaner way to do this but hey, it works!
|
||||
board::ResetToStockCpu();
|
||||
}
|
||||
if (newGpuGovernorState == false && lastGpuGovernorState == true) {
|
||||
svcSleepThread(100'000'000);
|
||||
board::ResetToStockGpu();
|
||||
}
|
||||
if (newVrrGovernorState == false && lastVrrGovernorState == true) {
|
||||
svcSleepThread(100'000'000);
|
||||
board::ResetToStockDisplay();
|
||||
}
|
||||
if (newCpuGovernorState != lastCpuGovernorState || newGpuGovernorState != lastGpuGovernorState || newVrrGovernorState != lastVrrGovernorState) {
|
||||
fileUtils::LogLine("[mgr] Governor state changed: CPU %s, GPU %s, VRR %s", newCpuGovernorState ? "enabled" : "disabled", newGpuGovernorState ? "enabled" : "disabled", newVrrGovernorState ? "enabled" : "disabled");
|
||||
lastCpuGovernorState = newCpuGovernorState;
|
||||
lastGpuGovernorState = newGpuGovernorState;
|
||||
lastVrrGovernorState = newVrrGovernorState;
|
||||
}
|
||||
}
|
||||
|
||||
u32 SchedutilTargetHz(u32 util, u32 tableMaxHz)
|
||||
{
|
||||
u64 hz = (u64)tableMaxHz * util / STEP_UTIL;
|
||||
return (u32)(std::min(hz, static_cast<u64>(tableMaxHz)));
|
||||
}
|
||||
|
||||
u32 TableIndexForHz(const clockManager::FreqTable& table, u32 targetHz)
|
||||
{
|
||||
for (u32 i = 0; i < table.count; i++)
|
||||
if (table.list[i] >= targetHz)
|
||||
return i;
|
||||
return table.count - 1;
|
||||
}
|
||||
|
||||
u32 ResolveTargetHz(SysClkModule module)
|
||||
{
|
||||
u32 hz = clockManager::gContext.overrideFreqs[module];
|
||||
if (!hz)
|
||||
hz = config::GetAutoClockHz(
|
||||
clockManager::gContext.applicationId, module,
|
||||
clockManager::gContext.profile, false);
|
||||
if (!hz)
|
||||
hz = config::GetAutoClockHz(
|
||||
GLOBAL_PROFILE_ID, module,
|
||||
clockManager::gContext.profile, false);
|
||||
return hz;
|
||||
}
|
||||
|
||||
void CpuGovernorThread(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
u32 downHoldRemaining = 0;
|
||||
u32 lastHz = 0;
|
||||
u32 minHz = 612;
|
||||
u32 tick = 0;
|
||||
for (;;) {
|
||||
if (!clockManager::gRunning || !isCpuGovernorEnabled) {
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
|
||||
if (R_SUCCEEDED(rc) && apmExtIsBoostMode(mode)) {
|
||||
isCpuGovernorInBoostMode = true;
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
continue; // TODO: figure out a way to get boost clock easily and set it instead of just skipping the governor
|
||||
} else if (!apmExtIsBoostMode(mode)) {
|
||||
isCpuGovernorInBoostMode = false;
|
||||
}
|
||||
|
||||
auto& table = clockManager::gFreqTable[SysClkModule_CPU];
|
||||
|
||||
if (table.count == 0)
|
||||
continue;
|
||||
|
||||
std::scoped_lock lock{clockManager::gContextMutex};
|
||||
|
||||
u32 cpuLoad = board::GetPartLoad(HocClkPartLoad_CPUMax);
|
||||
|
||||
u32 tableMaxHz = table.list[table.count - 1];
|
||||
u32 desiredHz = SchedutilTargetHz(cpuLoad, tableMaxHz);
|
||||
u32 targetHz = ResolveTargetHz(SysClkModule_CPU);
|
||||
u32 maxHz = clockManager::GetMaxAllowedHz(SysClkModule_CPU, clockManager::gContext.profile);
|
||||
|
||||
if (targetHz && desiredHz > targetHz)
|
||||
desiredHz = targetHz;
|
||||
|
||||
if (maxHz && desiredHz > maxHz)
|
||||
desiredHz = maxHz;
|
||||
|
||||
u32 newHz = table.list[TableIndexForHz(table, desiredHz)];
|
||||
|
||||
// ramp up fast, go down slow
|
||||
bool goingDown = (lastHz != 0) && (newHz < lastHz);
|
||||
|
||||
if (!goingDown)
|
||||
downHoldRemaining = 0;
|
||||
else if (downHoldRemaining == 0)
|
||||
downHoldRemaining = DOWN_HOLD_TICKS;
|
||||
|
||||
if (downHoldRemaining > 0)
|
||||
downHoldRemaining--;
|
||||
|
||||
if (++tick > 50) {
|
||||
minHz = config::GetConfigValue(HorizonOCConfigValue_CpuGovernorMinimumFreq);
|
||||
tick = 0;
|
||||
}
|
||||
|
||||
if (newHz < minHz)
|
||||
newHz = minHz;
|
||||
|
||||
if ((!goingDown || (downHoldRemaining == 0)) && clockManager::IsAssignableHz(SysClkModule_CPU, newHz)) {
|
||||
board::SetHz(SysClkModule_CPU, newHz);
|
||||
clockManager::gContext.freqs[SysClkModule_CPU] = newHz;
|
||||
lastHz = newHz;
|
||||
}
|
||||
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
void GovernorThread(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
u32 downHoldRemaining = 0;
|
||||
u32 lastHz = 0;
|
||||
|
||||
for (;;) {
|
||||
if (!clockManager::gRunning || !isGpuGovernorEnabled) {
|
||||
downHoldRemaining = 0;
|
||||
lastHz = 0;
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& table = clockManager::gFreqTable[SysClkModule_GPU];
|
||||
if (table.count == 0)
|
||||
continue;
|
||||
|
||||
std::scoped_lock lock{clockManager::gContextMutex};
|
||||
|
||||
u32 gpuLoad = board::GetPartLoad(HocClkPartLoad_GPU);
|
||||
u32 tableMaxHz = table.list[table.count - 1];
|
||||
u32 desiredHz = SchedutilTargetHz(gpuLoad, tableMaxHz);
|
||||
u32 targetHz = ResolveTargetHz(SysClkModule_GPU);
|
||||
u32 maxHz = clockManager::GetMaxAllowedHz(SysClkModule_GPU, clockManager::gContext.profile);
|
||||
|
||||
if (targetHz && desiredHz > targetHz)
|
||||
desiredHz = targetHz;
|
||||
|
||||
if (maxHz && desiredHz > maxHz)
|
||||
desiredHz = maxHz;
|
||||
|
||||
u32 newHz = table.list[TableIndexForHz(table, desiredHz)];
|
||||
bool goingDown = (lastHz != 0) && (newHz < lastHz);
|
||||
|
||||
if (!goingDown)
|
||||
downHoldRemaining = 0;
|
||||
else if (downHoldRemaining == 0)
|
||||
downHoldRemaining = DOWN_HOLD_TICKS;
|
||||
|
||||
if (downHoldRemaining > 0)
|
||||
downHoldRemaining--;
|
||||
|
||||
if ((!goingDown || (downHoldRemaining == 0)) && clockManager::IsAssignableHz(SysClkModule_GPU, newHz)) {
|
||||
board::SetHz(SysClkModule_GPU, newHz);
|
||||
clockManager::gContext.freqs[SysClkModule_GPU] = newHz;
|
||||
lastHz = newHz;
|
||||
}
|
||||
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
void VRRThread(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
u8 tick = 0;
|
||||
for (;;) {
|
||||
if (!clockManager::gRunning || clockManager::gContext.profile == SysClkProfile_Docked || !isVRREnabled) {
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{clockManager::gContextMutex};
|
||||
|
||||
u8 fps;
|
||||
|
||||
if (clockManager::gContext.isSaltyNXInstalled) {
|
||||
fps = integrations::GetSaltyNXFPS();
|
||||
} else {
|
||||
svcSleepThread(~0ULL); // effectively disable the thread if SaltyNX isn't installed, as there's no point in it running
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fps == 254) {
|
||||
svcSleepThread(POLL_NS);
|
||||
continue;
|
||||
}
|
||||
// if(appletGetFocusState() != AppletFocusState_InFocus) {
|
||||
// board::ResetToStockDisplay();
|
||||
// continue;
|
||||
// }
|
||||
|
||||
u32 targetHz = clockManager::gContext.overrideFreqs[HorizonOCModule_Display];
|
||||
if (!targetHz) {
|
||||
targetHz = config::GetAutoClockHz(clockManager::gContext.applicationId, HorizonOCModule_Display, clockManager::gContext.profile, false);
|
||||
if (!targetHz)
|
||||
targetHz = config::GetAutoClockHz(GLOBAL_PROFILE_ID, HorizonOCModule_Display, clockManager::gContext.profile, false);
|
||||
}
|
||||
|
||||
u8 maxDisplay;
|
||||
if (targetHz) {
|
||||
maxDisplay = targetHz;
|
||||
} else {
|
||||
maxDisplay = 60; // don't assume display stuff!
|
||||
}
|
||||
|
||||
u8 minDisplay = board::GetConsoleType() == HorizonOCConsoleType_Aula ? 45 : 40;
|
||||
if (maxDisplay == minDisplay)
|
||||
continue;
|
||||
|
||||
if (fps >= minDisplay && fps <= maxDisplay) {
|
||||
board::SetHz(HorizonOCModule_Display, fps);
|
||||
clockManager::gContext.freqs[HorizonOCModule_Display] = fps;
|
||||
clockManager::gContext.realFreqs[HorizonOCModule_Display] = fps;
|
||||
} else {
|
||||
for (u32 i = 0; i < 10; i++) {
|
||||
u32 compareHz = fps * i;
|
||||
if (compareHz >= minDisplay && compareHz <= maxDisplay) {
|
||||
board::SetHz(HorizonOCModule_Display, compareHz);
|
||||
clockManager::gContext.freqs[HorizonOCModule_Display] = compareHz;
|
||||
clockManager::gContext.realFreqs[HorizonOCModule_Display] = compareHz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++tick > 50) {
|
||||
board::SetHz(HorizonOCModule_Display, maxDisplay);
|
||||
tick = 0;
|
||||
svcSleepThread(50'000'000);
|
||||
}
|
||||
|
||||
svcSleepThread(POLL_NS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void startThreads() {
|
||||
|
||||
threadCreate(
|
||||
&cpuGovernorTHREAD,
|
||||
CpuGovernorThread,
|
||||
nullptr,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
threadCreate(
|
||||
&gpuGovernorTHREAD,
|
||||
GovernorThread,
|
||||
nullptr,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
threadCreate(
|
||||
&vrrTHREAD,
|
||||
VRRThread,
|
||||
nullptr,
|
||||
NULL,
|
||||
0x2000,
|
||||
0x3F,
|
||||
-2
|
||||
);
|
||||
|
||||
threadStart(&cpuGovernorTHREAD);
|
||||
threadStart(&gpuGovernorTHREAD);
|
||||
threadStart(&vrrTHREAD);
|
||||
}
|
||||
|
||||
void exitThreads() {
|
||||
threadClose(&cpuGovernorTHREAD);
|
||||
threadClose(&gpuGovernorTHREAD);
|
||||
threadClose(&vrrTHREAD);
|
||||
}
|
||||
}
|
||||
27
Source/hoc-clk/sysmodule/src/governor.hpp
Normal file
27
Source/hoc-clk/sysmodule/src/governor.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include "board/board.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include <cstring>
|
||||
#include "file_utils.hpp"
|
||||
#include "board/board.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "config.hpp"
|
||||
#include "integrations.hpp"
|
||||
#include <nxExt/cpp/lockable_mutex.h>
|
||||
|
||||
namespace governor {
|
||||
extern bool isCpuGovernorInBoostMode;
|
||||
extern bool isVRREnabled;
|
||||
extern bool isGpuGovernorEnabled;
|
||||
extern bool isCpuGovernorEnabled;
|
||||
extern bool lastGpuGovernorState;
|
||||
extern bool lastCpuGovernorState;
|
||||
extern bool lastVrrGovernorState;
|
||||
void startThreads();
|
||||
void exitThreads();
|
||||
void HandleGovernor(uint32_t targetHz);
|
||||
void CpuGovernorThread(void* arg);
|
||||
void GovernorThread(void* arg);
|
||||
void VRRThread(void* arg);
|
||||
}
|
||||
156
Source/hoc-clk/sysmodule/src/integrations.cpp
Normal file
156
Source/hoc-clk/sysmodule/src/integrations.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "integrations.hpp"
|
||||
#include <sys/stat.h>
|
||||
#include <SaltyNX.h>
|
||||
#include "process_management.hpp"
|
||||
|
||||
namespace integrations {
|
||||
|
||||
namespace {
|
||||
|
||||
NxFpsSharedBlock* gNxFps = nullptr;
|
||||
SharedMemory gSharedMemory = {};
|
||||
bool gSharedMemoryUsed = false;
|
||||
Handle gRemoteSharedMemory = 1;
|
||||
u64 gPrevTid = 0;
|
||||
|
||||
bool CheckSaltyNXPort() {
|
||||
Handle saltysd;
|
||||
|
||||
for (int i = 0; i < 67; i++) {
|
||||
if (R_SUCCEEDED(svcConnectToNamedPort(&saltysd, "InjectServ"))) {
|
||||
svcCloseHandle(saltysd);
|
||||
break;
|
||||
}
|
||||
if (i == 66) return false;
|
||||
svcSleepThread(1'000'000);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 67; i++) {
|
||||
if (R_SUCCEEDED(svcConnectToNamedPort(&saltysd, "InjectServ"))) {
|
||||
svcCloseHandle(saltysd);
|
||||
return true;
|
||||
}
|
||||
svcSleepThread(1'000'000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SearchSharedMemoryBlock(uintptr_t base) {
|
||||
ptrdiff_t search_offset = 0;
|
||||
while (search_offset < 0x1000) {
|
||||
gNxFps = (NxFpsSharedBlock*)(base + search_offset);
|
||||
if (gNxFps->MAGIC == 0x465053)
|
||||
return;
|
||||
search_offset += 4;
|
||||
}
|
||||
gNxFps = nullptr;
|
||||
}
|
||||
|
||||
void LoadSharedMemory() {
|
||||
if (SaltySD_Connect())
|
||||
return;
|
||||
SaltySD_GetSharedMemoryHandle(&gRemoteSharedMemory);
|
||||
SaltySD_Term();
|
||||
shmemLoadRemote(&gSharedMemory, gRemoteSharedMemory, 0x1000, Perm_Rw);
|
||||
if (!shmemMap(&gSharedMemory))
|
||||
gSharedMemoryUsed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GetSysDockState() {
|
||||
struct stat st = {0};
|
||||
return stat("sdmc:/atmosphere/contents/42000000000000A0/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
bool GetSaltyNXState() {
|
||||
struct stat st = {0};
|
||||
return stat("sdmc:/atmosphere/contents/0000000000534C56/flags/boot2.flag", &st) == 0;
|
||||
}
|
||||
|
||||
bool GetRETROSuperStatus() {
|
||||
struct stat st = {0};
|
||||
return stat("sdmc:/config/horizon-oc/retro.flag", &st) == 0;
|
||||
}
|
||||
|
||||
void LoadSaltyNX() {
|
||||
if (!CheckSaltyNXPort())
|
||||
return;
|
||||
LoadSharedMemory();
|
||||
}
|
||||
|
||||
u8 GetSaltyNXFPS() {
|
||||
if (!gSharedMemoryUsed)
|
||||
return 254;
|
||||
|
||||
u64 tid = processManagement::GetCurrentApplicationId();
|
||||
if (tid == 0)
|
||||
return 254;
|
||||
|
||||
if (gPrevTid != tid) {
|
||||
gNxFps = nullptr;
|
||||
gPrevTid = tid;
|
||||
}
|
||||
|
||||
if (!gNxFps) {
|
||||
uintptr_t base = (uintptr_t)shmemGetAddr(&gSharedMemory);
|
||||
SearchSharedMemoryBlock(base);
|
||||
}
|
||||
|
||||
return gNxFps ? gNxFps->FPS : 254;
|
||||
}
|
||||
|
||||
u16 GetSaltyNXResolutionHeight() {
|
||||
if (!gSharedMemoryUsed)
|
||||
return 0;
|
||||
|
||||
u64 tid = processManagement::GetCurrentApplicationId();
|
||||
if (tid == 0)
|
||||
return 0;
|
||||
|
||||
if (gPrevTid != tid) {
|
||||
gNxFps = nullptr;
|
||||
gPrevTid = tid;
|
||||
}
|
||||
|
||||
if (!gNxFps) {
|
||||
uintptr_t base = (uintptr_t)shmemGetAddr(&gSharedMemory);
|
||||
SearchSharedMemoryBlock(base);
|
||||
}
|
||||
|
||||
if (gNxFps) {
|
||||
gNxFps->renderCalls[0].calls = 0xFFFF;
|
||||
svcSleepThread(10*1000);
|
||||
return gNxFps->renderCalls[0].height == 0 ? gNxFps->viewportCalls[0].height : gNxFps->renderCalls[0].height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
78
Source/hoc-clk/sysmodule/src/integrations.hpp
Normal file
78
Source/hoc-clk/sysmodule/src/integrations.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace integrations {
|
||||
|
||||
struct NxFpsSharedBlock {
|
||||
uint32_t MAGIC;
|
||||
uint8_t FPS;
|
||||
float FPSavg;
|
||||
bool pluginActive;
|
||||
uint8_t FPSlocked;
|
||||
uint8_t FPSmode;
|
||||
uint8_t ZeroSync;
|
||||
uint8_t patchApplied;
|
||||
uint8_t API;
|
||||
uint32_t FPSticks[10];
|
||||
uint8_t Buffers;
|
||||
uint8_t SetBuffers;
|
||||
uint8_t ActiveBuffers;
|
||||
uint8_t SetActiveBuffers;
|
||||
union {
|
||||
struct {
|
||||
bool handheld: 1;
|
||||
bool docked: 1;
|
||||
unsigned int reserved: 6;
|
||||
} NX_PACKED ds;
|
||||
uint8_t general;
|
||||
} displaySync;
|
||||
struct resolutionCalls {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t calls;
|
||||
} renderCalls[8], viewportCalls[8];
|
||||
bool forceOriginalRefreshRate;
|
||||
bool dontForce60InDocked;
|
||||
bool forceSuspend;
|
||||
uint8_t currentRefreshRate;
|
||||
float readSpeedPerSecond;
|
||||
uint8_t FPSlockedDocked;
|
||||
uint64_t frameNumber;
|
||||
} NX_PACKED;
|
||||
|
||||
bool GetSysDockState();
|
||||
bool GetSaltyNXState();
|
||||
bool GetRETROSuperStatus();
|
||||
void LoadSaltyNX();
|
||||
u8 GetSaltyNXFPS();
|
||||
u16 GetSaltyNXResolutionHeight();
|
||||
|
||||
}
|
||||
294
Source/hoc-clk/sysmodule/src/ipc_service.cpp
Normal file
294
Source/hoc-clk/sysmodule/src/ipc_service.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "ipc_service.hpp"
|
||||
#include <cstring>
|
||||
#include <switch.h>
|
||||
#include <nxExt.h>
|
||||
#include "file_utils.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "config.hpp"
|
||||
#include "kip.hpp"
|
||||
namespace ipcService {
|
||||
|
||||
namespace {
|
||||
|
||||
bool gRunning = false;
|
||||
Thread gThread;
|
||||
LockableMutex gThreadMutex;
|
||||
IpcServer gServer;
|
||||
|
||||
Result GetApiVersion(u32* out_version) {
|
||||
*out_version = SYSCLK_IPC_API_VERSION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetVersionString(char* out_buf, size_t bufSize) {
|
||||
if (bufSize) {
|
||||
strncpy(out_buf, TARGET_VERSION, bufSize-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetCurrentContext(SysClkContext* out_ctx) {
|
||||
*out_ctx = clockManager::GetCurrentContext();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result ExitHandler() {
|
||||
clockManager::SetRunning(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetProfileCount(std::uint64_t* tid, std::uint8_t* out_count) {
|
||||
if (!config::HasProfilesLoaded()) {
|
||||
return SYSCLK_ERROR(ConfigNotLoaded);
|
||||
}
|
||||
*out_count = config::GetProfileCount(*tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetProfiles(std::uint64_t* tid, SysClkTitleProfileList* out_profiles) {
|
||||
if (!config::HasProfilesLoaded()) {
|
||||
return SYSCLK_ERROR(ConfigNotLoaded);
|
||||
}
|
||||
config::GetProfiles(*tid, out_profiles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result SetProfiles(SysClkIpc_SetProfiles_Args* args) {
|
||||
if (!config::HasProfilesLoaded()) {
|
||||
return SYSCLK_ERROR(ConfigNotLoaded);
|
||||
}
|
||||
SysClkTitleProfileList profiles = args->profiles;
|
||||
if (!config::SetProfiles(args->tid, &profiles, true)) {
|
||||
return SYSCLK_ERROR(ConfigSaveFailed);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result SetEnabled(std::uint8_t* enabled) {
|
||||
config::SetEnabled(*enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result SetOverride(SysClkIpc_SetOverride_Args* args) {
|
||||
if (!SYSCLK_ENUM_VALID(SysClkModule, args->module)) {
|
||||
return SYSCLK_ERROR(Generic);
|
||||
}
|
||||
config::SetOverrideHz(args->module, args->hz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetConfigValuesHandler(SysClkConfigValueList* out_configValues) {
|
||||
if (!config::HasProfilesLoaded()) {
|
||||
return SYSCLK_ERROR(ConfigNotLoaded);
|
||||
}
|
||||
config::GetConfigValues(out_configValues);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result SetConfigValuesHandler(SysClkConfigValueList* configValues) {
|
||||
if (!config::HasProfilesLoaded()) {
|
||||
return SYSCLK_ERROR(ConfigNotLoaded);
|
||||
}
|
||||
SysClkConfigValueList copy = *configValues;
|
||||
if (!config::SetConfigValues(©, true)) {
|
||||
return SYSCLK_ERROR(ConfigSaveFailed);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t* out_list, std::size_t size, std::uint32_t* out_count) {
|
||||
if (!SYSCLK_ENUM_VALID(SysClkModule, args->module)) {
|
||||
return SYSCLK_ERROR(Generic);
|
||||
}
|
||||
if (args->maxCount != size/sizeof(*out_list)) {
|
||||
return SYSCLK_ERROR(Generic);
|
||||
}
|
||||
clockManager::GetFreqList(args->module, out_list, args->maxCount, out_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8* out_data, size_t* out_dataSize) {
|
||||
(void)arg;
|
||||
switch (r->data.cmdId) {
|
||||
case SysClkIpcCmd_GetApiVersion:
|
||||
*out_dataSize = sizeof(u32);
|
||||
return GetApiVersion((u32*)out_data);
|
||||
|
||||
case SysClkIpcCmd_GetVersionString:
|
||||
if (r->hipc.meta.num_recv_buffers >= 1) {
|
||||
return GetVersionString(
|
||||
(char*)hipcGetBufferAddress(r->hipc.data.recv_buffers),
|
||||
hipcGetBufferSize(r->hipc.data.recv_buffers)
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_GetCurrentContext:
|
||||
if (r->data.size >= sizeof(std::uint64_t) && r->hipc.meta.num_recv_buffers >= 1) {
|
||||
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
|
||||
if (bufSize >= sizeof(SysClkContext)) {
|
||||
return GetCurrentContext((SysClkContext*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_Exit:
|
||||
return ExitHandler();
|
||||
|
||||
case SysClkIpcCmd_GetProfileCount:
|
||||
if (r->data.size >= sizeof(std::uint64_t)) {
|
||||
*out_dataSize = sizeof(std::uint8_t);
|
||||
return GetProfileCount((std::uint64_t*)r->data.ptr, (std::uint8_t*)out_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_GetProfiles:
|
||||
if (r->data.size >= sizeof(std::uint64_t) && r->hipc.meta.num_recv_buffers >= 1) {
|
||||
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
|
||||
if (bufSize >= sizeof(SysClkTitleProfileList)) {
|
||||
return GetProfiles((std::uint64_t*)r->data.ptr, (SysClkTitleProfileList*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_SetProfiles:
|
||||
if (r->data.size >= sizeof(SysClkIpc_SetProfiles_Args)) {
|
||||
return SetProfiles((SysClkIpc_SetProfiles_Args*)r->data.ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_SetEnabled:
|
||||
if (r->data.size >= sizeof(std::uint8_t)) {
|
||||
return SetEnabled((std::uint8_t*)r->data.ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_SetOverride:
|
||||
if (r->data.size >= sizeof(SysClkIpc_SetOverride_Args)) {
|
||||
return SetOverride((SysClkIpc_SetOverride_Args*)r->data.ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_GetConfigValues:
|
||||
if (r->hipc.meta.num_recv_buffers >= 1) {
|
||||
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
|
||||
if (bufSize >= sizeof(SysClkConfigValueList)) {
|
||||
return GetConfigValuesHandler((SysClkConfigValueList*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_SetConfigValues:
|
||||
if (r->hipc.meta.num_send_buffers >= 1) {
|
||||
size_t bufSize = hipcGetBufferSize(r->hipc.data.send_buffers);
|
||||
if (bufSize >= sizeof(SysClkConfigValueList)) {
|
||||
return SetConfigValuesHandler((SysClkConfigValueList*)hipcGetBufferAddress(r->hipc.data.send_buffers));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SysClkIpcCmd_GetFreqList:
|
||||
if (r->data.size >= sizeof(SysClkIpc_GetFreqList_Args) && r->hipc.meta.num_recv_buffers >= 1) {
|
||||
*out_dataSize = sizeof(std::uint32_t);
|
||||
return GetFreqList(
|
||||
(SysClkIpc_GetFreqList_Args*)r->data.ptr,
|
||||
(std::uint32_t*)hipcGetBufferAddress(r->hipc.data.recv_buffers),
|
||||
hipcGetBufferSize(r->hipc.data.recv_buffers),
|
||||
(std::uint32_t*)out_data
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case HocClkIpcCmd_SetKipData:
|
||||
if (r->data.size >= 0) {
|
||||
kip::SetKipData();
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return SYSCLK_ERROR(Generic);
|
||||
}
|
||||
|
||||
void ProcessThreadFunc(void* arg) {
|
||||
(void)arg;
|
||||
Result rc;
|
||||
while (true) {
|
||||
rc = ipcServerProcess(&gServer, &ServiceHandlerFunc, nullptr);
|
||||
if (R_FAILED(rc)) {
|
||||
if (rc == KERNELRESULT(Cancelled)) {
|
||||
return;
|
||||
}
|
||||
if (rc != KERNELRESULT(ConnectionClosed)) {
|
||||
fileUtils::LogLine("[ipc] ipcServerProcess: [0x%x] %04d-%04d", rc, R_MODULE(rc), R_DESCRIPTION(rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
std::int32_t priority;
|
||||
Result rc = svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
|
||||
ASSERT_RESULT_OK(rc, "svcGetThreadPriority");
|
||||
rc = ipcServerInit(&gServer, SYSCLK_IPC_SERVICE_NAME, 42);
|
||||
ASSERT_RESULT_OK(rc, "ipcServerInit");
|
||||
rc = threadCreate(&gThread, &ProcessThreadFunc, nullptr, NULL, 0x2000, priority, -2);
|
||||
ASSERT_RESULT_OK(rc, "threadCreate");
|
||||
gRunning = false;
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
SetRunning(false);
|
||||
Result rc = threadClose(&gThread);
|
||||
ASSERT_RESULT_OK(rc, "threadClose");
|
||||
rc = ipcServerExit(&gServer);
|
||||
ASSERT_RESULT_OK(rc, "ipcServerExit");
|
||||
}
|
||||
|
||||
void SetRunning(bool running) {
|
||||
std::scoped_lock lock{gThreadMutex};
|
||||
if (gRunning == running) {
|
||||
return;
|
||||
}
|
||||
|
||||
gRunning = running;
|
||||
|
||||
if (running) {
|
||||
Result rc = threadStart(&gThread);
|
||||
ASSERT_RESULT_OK(rc, "threadStart");
|
||||
} else {
|
||||
svcCancelSynchronization(gThread.handle);
|
||||
threadWaitForExit(&gThread);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
Source/hoc-clk/sysmodule/src/ipc_service.hpp
Normal file
38
Source/hoc-clk/sysmodule/src/ipc_service.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sysclk.h>
|
||||
#include <switch.h>
|
||||
|
||||
namespace ipcService {
|
||||
|
||||
void Initialize();
|
||||
void Exit();
|
||||
void SetRunning(bool running);
|
||||
|
||||
}
|
||||
255
Source/hoc-clk/sysmodule/src/kip.cpp
Normal file
255
Source/hoc-clk/sysmodule/src/kip.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "kip.hpp"
|
||||
#include "board/board.hpp"
|
||||
|
||||
namespace kip {
|
||||
|
||||
bool kipAvailable = false;
|
||||
|
||||
void SetKipData()
|
||||
{
|
||||
// TODO: figure out if this REALLY causes issues (i doubt it)
|
||||
// if(board::GetSocType() == SysClkSocType_Mariko) {
|
||||
// if(R_FAILED(I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt) / 1000))) {
|
||||
// fileUtils::LogLine("[clock_manager] Failed set i2c vddq");
|
||||
// notification::writeNotification("Horizon OC\nFailed to write I2C\nwhile setting vddq");
|
||||
// }
|
||||
// }
|
||||
CustomizeTable table;
|
||||
FILE* fp;
|
||||
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
|
||||
|
||||
if (fp == NULL) {
|
||||
notification::writeNotification("Horizon OC\nKip opening failed");
|
||||
kipAvailable = false;
|
||||
return;
|
||||
} else {
|
||||
kipAvailable = true;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
|
||||
fileUtils::LogLine("[clock_manager] Failed to read KIP file");
|
||||
notification::writeNotification("Horizon OC\nKip read failed");
|
||||
return;
|
||||
}
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, custRev, config::GetConfigValue(KipConfigValue_custRev));
|
||||
// CUST_WRITE_FIELD_BATCH(&table, mtcConf, config::GetConfigValue(KipConfigValue_mtcConf));
|
||||
CUST_WRITE_FIELD_BATCH(&table, hpMode, config::GetConfigValue(KipConfigValue_hpMode));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, commonEmcMemVolt, config::GetConfigValue(KipConfigValue_commonEmcMemVolt));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock1, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock1));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock2, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock2));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoEmcMaxClock, config::GetConfigValue(KipConfigValue_marikoEmcMaxClock));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoEmcVddqVolt, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt));
|
||||
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, config::GetConfigValue(KipConfigValue_emcDvbShift));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, t1_tRCD, config::GetConfigValue(KipConfigValue_t1_tRCD));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t2_tRP, config::GetConfigValue(KipConfigValue_t2_tRP));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t3_tRAS, config::GetConfigValue(KipConfigValue_t3_tRAS));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t4_tRRD, config::GetConfigValue(KipConfigValue_t4_tRRD));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t5_tRFC, config::GetConfigValue(KipConfigValue_t5_tRFC));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW, config::GetConfigValue(KipConfigValue_t6_tRTW));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR, config::GetConfigValue(KipConfigValue_t7_tWTR));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t8_tREFI, config::GetConfigValue(KipConfigValue_t8_tREFI));
|
||||
CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, config::GetConfigValue(KipConfigValue_mem_burst_read_latency));
|
||||
CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, config::GetConfigValue(KipConfigValue_mem_burst_write_latency));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, config::GetConfigValue(KipConfigValue_eristaCpuUV));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuVmin, config::GetConfigValue(KipConfigValue_eristaCpuVmin));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuMaxVolt, config::GetConfigValue(KipConfigValue_eristaCpuMaxVolt));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUnlock, config::GetConfigValue(KipConfigValue_eristaCpuUnlock));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVLow, config::GetConfigValue(KipConfigValue_marikoCpuUVLow));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVHigh, config::GetConfigValue(KipConfigValue_marikoCpuUVHigh));
|
||||
CUST_WRITE_FIELD_BATCH(&table, tableConf, config::GetConfigValue(KipConfigValue_tableConf));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuLowVmin, config::GetConfigValue(KipConfigValue_marikoCpuLowVmin));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuHighVmin, config::GetConfigValue(KipConfigValue_marikoCpuHighVmin));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxVolt, config::GetConfigValue(KipConfigValue_marikoCpuMaxVolt));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxClock, config::GetConfigValue(KipConfigValue_marikoCpuMaxClock));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaCpuBoostClock, config::GetConfigValue(KipConfigValue_eristaCpuBoostClock));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoCpuBoostClock, config::GetConfigValue(KipConfigValue_marikoCpuBoostClock));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaGpuUV, config::GetConfigValue(KipConfigValue_eristaGpuUV));
|
||||
CUST_WRITE_FIELD_BATCH(&table, eristaGpuVmin, config::GetConfigValue(KipConfigValue_eristaGpuVmin));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoGpuUV, config::GetConfigValue(KipConfigValue_marikoGpuUV));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmin, config::GetConfigValue(KipConfigValue_marikoGpuVmin));
|
||||
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmax, config::GetConfigValue(KipConfigValue_marikoGpuVmax));
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, commonGpuVoltOffset, config::GetConfigValue(KipConfigValue_commonGpuVoltOffset));
|
||||
CUST_WRITE_FIELD_BATCH(&table, gpuSpeedo, config::GetConfigValue(KipConfigValue_gpuSpeedo));
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
table.marikoGpuVoltArray[i] = config::GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_76800 + i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 27; i++) {
|
||||
table.eristaGpuVoltArray[i] = config::GetConfigValue((SysClkConfigValue)(KipConfigValue_g_volt_e_76800 + i));
|
||||
}
|
||||
|
||||
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW_fine_tune, config::GetConfigValue(KipConfigValue_t6_tRTW_fine_tune));
|
||||
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR_fine_tune, config::GetConfigValue(KipConfigValue_t7_tWTR_fine_tune));
|
||||
|
||||
if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) {
|
||||
fileUtils::LogLine("[clock_manager] Failed to write KIP file");
|
||||
notification::writeNotification("Horizon OC\nKip write failed");
|
||||
}
|
||||
|
||||
SysClkConfigValueList configValues;
|
||||
config::GetConfigValues(&configValues);
|
||||
|
||||
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
|
||||
|
||||
if (config::SetConfigValues(&configValues, false)) {
|
||||
fileUtils::LogLine("[clock_manager] Successfully loaded KIP data into config");
|
||||
} else {
|
||||
fileUtils::LogLine("[clock_manager] Warning: Failed to set config values from KIP");
|
||||
notification::writeNotification("Horizon OC\nKip config set failed");
|
||||
}
|
||||
}
|
||||
|
||||
// I know this is very hacky, but the config system in the sysmodule doesn't really support writing
|
||||
|
||||
void GetKipData()
|
||||
{
|
||||
FILE* fp;
|
||||
if (config::Refresh()) {
|
||||
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
|
||||
|
||||
if (fp == NULL) {
|
||||
notification::writeNotification("Horizon OC\nKip opening failed");
|
||||
kipAvailable = false;
|
||||
return;
|
||||
} else {
|
||||
kipAvailable = true;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
SysClkConfigValueList configValues;
|
||||
config::GetConfigValues(&configValues);
|
||||
|
||||
CustomizeTable table;
|
||||
|
||||
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
|
||||
fileUtils::LogLine("[clock_manager] Failed to read KIP file for GetKipData");
|
||||
notification::writeNotification("Horizon OC\nKip read failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip") != config::GetConfigValue(KipCrc32) && !config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
|
||||
SetKipData();
|
||||
notification::writeNotification("Horizon OC\nKIP has been updated");
|
||||
notification::writeNotification("Horizon OC\nPlease reboot your console");
|
||||
notification::writeNotification("Horizon OC\nto complete the update");
|
||||
return;
|
||||
}
|
||||
if (config::GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) {
|
||||
configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false;
|
||||
notification::writeNotification("Horizon OC has been installed");
|
||||
}
|
||||
|
||||
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
|
||||
// configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
|
||||
configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
|
||||
|
||||
configValues.values[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
|
||||
configValues.values[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
|
||||
configValues.values[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
|
||||
configValues.values[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
|
||||
configValues.values[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
|
||||
configValues.values[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
|
||||
configValues.values[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
|
||||
|
||||
configValues.values[KipConfigValue_t1_tRCD] = cust_get_tRCD(&table);
|
||||
configValues.values[KipConfigValue_t2_tRP] = cust_get_tRP(&table);
|
||||
configValues.values[KipConfigValue_t3_tRAS] = cust_get_tRAS(&table);
|
||||
configValues.values[KipConfigValue_t4_tRRD] = cust_get_tRRD(&table);
|
||||
configValues.values[KipConfigValue_t5_tRFC] = cust_get_tRFC(&table);
|
||||
configValues.values[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table);
|
||||
configValues.values[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table);
|
||||
configValues.values[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table);
|
||||
configValues.values[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table);
|
||||
configValues.values[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table);
|
||||
|
||||
configValues.values[KipConfigValue_eristaCpuUV] = cust_get_erista_cpu_uv(&table);
|
||||
configValues.values[KipConfigValue_eristaCpuVmin] = cust_get_eristaCpuVmin(&table);
|
||||
configValues.values[KipConfigValue_eristaCpuMaxVolt] = cust_get_erista_cpu_max_volt(&table);
|
||||
configValues.values[KipConfigValue_eristaCpuUnlock] = cust_get_eristaCpuUnlock(&table);
|
||||
|
||||
configValues.values[KipConfigValue_marikoCpuUVLow] = cust_get_mariko_cpu_uv_low(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuUVHigh] = cust_get_mariko_cpu_uv_high(&table);
|
||||
configValues.values[KipConfigValue_tableConf] = cust_get_table_conf(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuLowVmin] = cust_get_mariko_cpu_low_vmin(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuHighVmin] = cust_get_mariko_cpu_high_vmin(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuMaxVolt] = cust_get_mariko_cpu_max_volt(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuMaxClock] = cust_get_marikoCpuMaxClock(&table);
|
||||
configValues.values[KipConfigValue_eristaCpuBoostClock] = cust_get_erista_cpu_boost(&table);
|
||||
configValues.values[KipConfigValue_marikoCpuBoostClock] = cust_get_mariko_cpu_boost(&table);
|
||||
|
||||
configValues.values[KipConfigValue_eristaGpuUV] = cust_get_erista_gpu_uv(&table);
|
||||
configValues.values[KipConfigValue_eristaGpuVmin] = cust_get_erista_gpu_vmin(&table);
|
||||
configValues.values[KipConfigValue_marikoGpuUV] = cust_get_mariko_gpu_uv(&table);
|
||||
configValues.values[KipConfigValue_marikoGpuVmin] = cust_get_mariko_gpu_vmin(&table);
|
||||
configValues.values[KipConfigValue_marikoGpuVmax] = cust_get_mariko_gpu_vmax(&table);
|
||||
configValues.values[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
|
||||
configValues.values[KipConfigValue_gpuSpeedo] = board::GetFuseData()->gpuSpeedo; // cust_get_gpu_speedo(&table);
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
configValues.values[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 27; i++) {
|
||||
configValues.values[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
|
||||
}
|
||||
|
||||
configValues.values[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
|
||||
configValues.values[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
|
||||
|
||||
// if(cust_get_cust_rev(&table) == KIP_CUST_REV)
|
||||
// return;
|
||||
|
||||
if (sizeof(SysClkConfigValueList) <= sizeof(configValues)) {
|
||||
if (config::SetConfigValues(&configValues, false)) {
|
||||
fileUtils::LogLine("[clock_manager] Successfully loaded KIP data into config");
|
||||
} else {
|
||||
fileUtils::LogLine("[clock_manager] Warning: Failed to set config values from KIP");
|
||||
notification::writeNotification("Horizon OC\nKip config set failed");
|
||||
}
|
||||
} else {
|
||||
fileUtils::LogLine("[clock_manager] Error: Config value list buffer size mismatch");
|
||||
notification::writeNotification("Horizon OC\nConfig Buffer Mismatch");
|
||||
}
|
||||
} else {
|
||||
fileUtils::LogLine("[clock_manager] Config refresh error in GetKipData!");
|
||||
notification::writeNotification("Horizon OC\nConfig refresh failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
467
Source/hoc-clk/sysmodule/src/kip.hpp
Normal file
467
Source/hoc-clk/sysmodule/src/kip.hpp
Normal file
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "config.hpp"
|
||||
#include "file_utils.hpp"
|
||||
#include <notification.h>
|
||||
#include <crc32.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
namespace kip {
|
||||
extern bool kipAvailable;
|
||||
|
||||
typedef struct {
|
||||
u8 cust[4];
|
||||
u32 custRev;
|
||||
u32 placeholder;
|
||||
u32 hpMode;
|
||||
u32 commonEmcMemVolt;
|
||||
u32 eristaEmcMaxClock;
|
||||
u32 eristaEmcMaxClock1;
|
||||
u32 eristaEmcMaxClock2;
|
||||
u32 marikoEmcMaxClock;
|
||||
u32 marikoEmcVddqVolt;
|
||||
u32 emcDvbShift;
|
||||
// advanced config
|
||||
u32 t1_tRCD;
|
||||
u32 t2_tRP;
|
||||
u32 t3_tRAS;
|
||||
u32 t4_tRRD;
|
||||
u32 t5_tRFC;
|
||||
u32 t6_tRTW;
|
||||
u32 t7_tWTR;
|
||||
u32 t8_tREFI;
|
||||
|
||||
u32 mem_burst_read_latency;
|
||||
u32 mem_burst_write_latency;
|
||||
|
||||
u32 eristaCpuUV;
|
||||
u32 eristaCpuVmin;
|
||||
u32 eristaCpuMaxVolt;
|
||||
u32 eristaCpuUnlock;
|
||||
|
||||
u32 marikoCpuUVLow;
|
||||
u32 marikoCpuUVHigh;
|
||||
u32 tableConf;
|
||||
u32 marikoCpuLowVmin;
|
||||
u32 marikoCpuHighVmin;
|
||||
u32 marikoCpuMaxVolt;
|
||||
u32 marikoCpuMaxClock;
|
||||
|
||||
u32 eristaCpuBoostClock;
|
||||
u32 marikoCpuBoostClock;
|
||||
|
||||
u32 eristaGpuUV;
|
||||
u32 eristaGpuVmin;
|
||||
|
||||
u32 marikoGpuUV;
|
||||
u32 marikoGpuVmin;
|
||||
u32 marikoGpuVmax;
|
||||
|
||||
u32 commonGpuVoltOffset;
|
||||
|
||||
u32 gpuSpeedo;
|
||||
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
|
||||
u32 t6_tRTW_fine_tune;
|
||||
u32 t7_tWTR_fine_tune;
|
||||
|
||||
u32 reserved[60];
|
||||
} CustomizeTable;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define CUST_MAGIC "CUST"
|
||||
#define CUST_MAGIC_LEN 4
|
||||
|
||||
typedef struct {
|
||||
FILE* file;
|
||||
long offset;
|
||||
CustomizeTable cached_table;
|
||||
bool has_cache;
|
||||
} CustHandle;
|
||||
|
||||
static inline bool cust_find_offset(FILE* f, long* out_offset) {
|
||||
u8 buf[512];
|
||||
long pos = 0;
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
while (1) {
|
||||
size_t r = fread(buf, 1, sizeof(buf), f);
|
||||
if (r < CUST_MAGIC_LEN) break;
|
||||
|
||||
for (size_t i = 0; i <= r - CUST_MAGIC_LEN; i++) {
|
||||
if (memcmp(&buf[i], CUST_MAGIC, CUST_MAGIC_LEN) == 0) {
|
||||
*out_offset = pos + (long)i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
pos += (long)(r - (CUST_MAGIC_LEN - 1));
|
||||
fseek(f, pos, SEEK_SET);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool cust_read_table(const char* path, CustomizeTable* out) {
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return false;
|
||||
|
||||
long off;
|
||||
if (!cust_find_offset(f, &off)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
|
||||
if (off + (long)sizeof(CustomizeTable) > size) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, off, SEEK_SET);
|
||||
bool ok = fread(out, 1, sizeof(CustomizeTable), f) == sizeof(CustomizeTable);
|
||||
fclose(f);
|
||||
|
||||
return ok && memcmp(out->cust, CUST_MAGIC, CUST_MAGIC_LEN) == 0;
|
||||
}
|
||||
|
||||
static inline bool cust_write_table(const char* path, const CustomizeTable* in) {
|
||||
FILE* f = fopen(path, "r+b");
|
||||
if (!f) return false;
|
||||
|
||||
long off;
|
||||
if (!cust_find_offset(f, &off)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
|
||||
if (off + (long)sizeof(CustomizeTable) > size) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, off, SEEK_SET);
|
||||
bool ok = fwrite(in, 1, sizeof(CustomizeTable), f) == sizeof(CustomizeTable);
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static inline bool cust_read_and_cache(const char* path, CustomizeTable* out) {
|
||||
return cust_read_table(path, out);
|
||||
}
|
||||
|
||||
#define CUST_WRITE_FIELD_BATCH(table, field, val) \
|
||||
do { \
|
||||
(table)->field = (val); \
|
||||
} while (0)
|
||||
|
||||
#define CUST_WRITE_FIELD(path, field, val) \
|
||||
do { \
|
||||
CustomizeTable t; \
|
||||
if (!cust_read_table(path, &t)) return false; \
|
||||
t.field = (val); \
|
||||
return cust_write_table(path, &t); \
|
||||
} while (0)
|
||||
|
||||
static inline bool cust_set_cust_rev(const char* p, u32 v) { CUST_WRITE_FIELD(p, custRev, v); }
|
||||
// static inline bool cust_set_mtc_conf(const char* p, u32 v) { CUST_WRITE_FIELD(p, mtcConf, v); }
|
||||
static inline bool cust_set_hp_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, hpMode, v); }
|
||||
|
||||
static inline bool cust_set_common_emc_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonEmcMemVolt, v); }
|
||||
static inline bool cust_set_erista_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock, v); }
|
||||
static inline bool cust_set_erista_emc_max1(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock1, v); }
|
||||
static inline bool cust_set_erista_emc_max2(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock2, v); }
|
||||
static inline bool cust_set_mariko_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcMaxClock, v); }
|
||||
static inline bool cust_set_mariko_emc_vddq(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcVddqVolt, v); }
|
||||
static inline bool cust_set_emc_dvb_shift(const char* p, u32 v) { CUST_WRITE_FIELD(p, emcDvbShift, v); }
|
||||
|
||||
static inline bool cust_set_tRCD(const char* p, u32 v) { CUST_WRITE_FIELD(p, t1_tRCD, v); }
|
||||
static inline bool cust_set_tRP(const char* p, u32 v) { CUST_WRITE_FIELD(p, t2_tRP, v); }
|
||||
static inline bool cust_set_tRAS(const char* p, u32 v) { CUST_WRITE_FIELD(p, t3_tRAS, v); }
|
||||
static inline bool cust_set_tRRD(const char* p, u32 v) { CUST_WRITE_FIELD(p, t4_tRRD, v); }
|
||||
static inline bool cust_set_tRFC(const char* p, u32 v) { CUST_WRITE_FIELD(p, t5_tRFC, v); }
|
||||
static inline bool cust_set_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW, v); }
|
||||
static inline bool cust_set_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR, v); }
|
||||
static inline bool cust_set_tREFI(const char* p, u32 v) { CUST_WRITE_FIELD(p, t8_tREFI, v); }
|
||||
static inline bool cust_set_tRTW_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW_fine_tune, v); }
|
||||
static inline bool cust_set_tWTR_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR_fine_tune, v); }
|
||||
static inline bool cust_set_burst_read_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_read_latency, v); }
|
||||
static inline bool cust_set_burst_write_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_write_latency, v); }
|
||||
|
||||
static inline bool cust_set_erista_cpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuUV, v); }
|
||||
static inline bool cust_set_eristaCpuVmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuVmin, v); }
|
||||
static inline bool cust_set_erista_cpu_max_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuMaxVolt, v); }
|
||||
static inline bool cust_set_eristaCpuUnlock(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuUnlock, v); }
|
||||
|
||||
static inline bool cust_set_mariko_cpu_uv_low(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuUVLow, v); }
|
||||
static inline bool cust_set_mariko_cpu_uv_high(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuUVHigh, v); }
|
||||
static inline bool cust_set_mariko_cpu_low_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuLowVmin, v); }
|
||||
static inline bool cust_set_mariko_cpu_high_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuHighVmin, v); }
|
||||
static inline bool cust_set_mariko_cpu_max_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuMaxVolt, v); }
|
||||
static inline bool cust_set_erista_cpu_boost(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuBoostClock, v); }
|
||||
static inline bool cust_set_mariko_cpu_boost(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuBoostClock, v); }
|
||||
|
||||
static inline bool cust_set_erista_gpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaGpuUV, v); }
|
||||
static inline bool cust_set_erista_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaGpuVmin, v); }
|
||||
static inline bool cust_set_mariko_gpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuUV, v); }
|
||||
static inline bool cust_set_mariko_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmin, v); }
|
||||
static inline bool cust_set_mariko_gpu_vmax(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmax, v); }
|
||||
static inline bool cust_set_common_gpu_offset(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonGpuVoltOffset, v); }
|
||||
static inline bool cust_set_gpu_speedo(const char* p, u32 v) { CUST_WRITE_FIELD(p, gpuSpeedo, v); }
|
||||
static inline bool cust_set_marikoCpuMaxClock(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuMaxClock, v); }
|
||||
|
||||
/* GPU VOLT ARRAY HELPERS */
|
||||
static inline bool cust_set_erista_gpu_volt(const char* p, int idx, u32 v) {
|
||||
if (idx < 0 || idx >= 27) return false;
|
||||
CustomizeTable t;
|
||||
if (!cust_read_table(p, &t)) return false;
|
||||
t.eristaGpuVoltArray[idx] = v;
|
||||
return cust_write_table(p, &t);
|
||||
}
|
||||
|
||||
static inline bool cust_set_mariko_gpu_volt(const char* p, int idx, u32 v) {
|
||||
if (idx < 0 || idx >= 24) return false;
|
||||
CustomizeTable t;
|
||||
if (!cust_read_table(p, &t)) return false;
|
||||
t.marikoGpuVoltArray[idx] = v;
|
||||
return cust_write_table(p, &t);
|
||||
}
|
||||
|
||||
static inline u32 cust_get_field(const CustomizeTable* t, u32 offset) {
|
||||
if (!t) return 0;
|
||||
return *(u32*)((u8*)t + offset);
|
||||
}
|
||||
|
||||
#define CUST_GET_FIELD(table, field) ((table) ? (table)->field : 0)
|
||||
|
||||
static inline u32 cust_get_cust_rev(const CustomizeTable* t) { return CUST_GET_FIELD(t, custRev); }
|
||||
// static inline u32 cust_get_mtc_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, mtcConf); }
|
||||
static inline u32 cust_get_hp_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, hpMode); }
|
||||
|
||||
static inline u32 cust_get_common_emc_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonEmcMemVolt); }
|
||||
static inline u32 cust_get_erista_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock); }
|
||||
static inline u32 cust_get_erista_emc_max1(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock1); }
|
||||
static inline u32 cust_get_erista_emc_max2(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock2); }
|
||||
static inline u32 cust_get_mariko_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcMaxClock); }
|
||||
static inline u32 cust_get_mariko_emc_vddq(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcVddqVolt); }
|
||||
static inline u32 cust_get_emc_dvb_shift(const CustomizeTable* t) { return CUST_GET_FIELD(t, emcDvbShift); }
|
||||
|
||||
static inline u32 cust_get_tRCD(const CustomizeTable* t) { return CUST_GET_FIELD(t, t1_tRCD); }
|
||||
static inline u32 cust_get_tRP(const CustomizeTable* t) { return CUST_GET_FIELD(t, t2_tRP); }
|
||||
static inline u32 cust_get_tRAS(const CustomizeTable* t) { return CUST_GET_FIELD(t, t3_tRAS); }
|
||||
static inline u32 cust_get_tRRD(const CustomizeTable* t) { return CUST_GET_FIELD(t, t4_tRRD); }
|
||||
static inline u32 cust_get_tRFC(const CustomizeTable* t) { return CUST_GET_FIELD(t, t5_tRFC); }
|
||||
static inline u32 cust_get_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW); }
|
||||
static inline u32 cust_get_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR); }
|
||||
static inline u32 cust_get_tREFI(const CustomizeTable* t) { return CUST_GET_FIELD(t, t8_tREFI); }
|
||||
static inline u32 cust_get_tRTW_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW_fine_tune); }
|
||||
static inline u32 cust_get_tWTR_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR_fine_tune); }
|
||||
static inline u32 cust_get_burst_read_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_read_latency); }
|
||||
static inline u32 cust_get_burst_write_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_write_latency); }
|
||||
|
||||
static inline u32 cust_get_erista_cpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuUV); }
|
||||
static inline u32 cust_get_eristaCpuVmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuVmin); }
|
||||
static inline u32 cust_get_erista_cpu_max_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuMaxVolt); }
|
||||
static inline u32 cust_get_eristaCpuUnlock(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuUnlock); }
|
||||
|
||||
static inline u32 cust_get_mariko_cpu_uv_low(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuUVLow); }
|
||||
static inline u32 cust_get_mariko_cpu_uv_high(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuUVHigh); }
|
||||
static inline u32 cust_get_mariko_cpu_low_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuLowVmin); }
|
||||
static inline u32 cust_get_mariko_cpu_high_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuHighVmin); }
|
||||
static inline u32 cust_get_mariko_cpu_max_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxVolt); }
|
||||
static inline u32 cust_get_erista_cpu_boost(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuBoostClock); }
|
||||
static inline u32 cust_get_mariko_cpu_boost(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuBoostClock); }
|
||||
static inline u32 cust_get_table_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, tableConf); }
|
||||
|
||||
static inline u32 cust_get_erista_gpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaGpuUV); }
|
||||
static inline u32 cust_get_erista_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaGpuVmin); }
|
||||
static inline u32 cust_get_mariko_gpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuUV); }
|
||||
static inline u32 cust_get_mariko_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmin); }
|
||||
static inline u32 cust_get_mariko_gpu_vmax(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmax); }
|
||||
static inline u32 cust_get_common_gpu_offset(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonGpuVoltOffset); }
|
||||
static inline u32 cust_get_gpu_speedo(const CustomizeTable* t) { return CUST_GET_FIELD(t, gpuSpeedo); }
|
||||
static inline u32 cust_get_marikoCpuMaxClock(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxClock); }
|
||||
|
||||
static inline u32 cust_get_erista_gpu_volt(const CustomizeTable* t, int idx) {
|
||||
if (!t || idx < 0 || idx >= 27) return 0;
|
||||
return t->eristaGpuVoltArray[idx];
|
||||
}
|
||||
|
||||
static inline u32 cust_get_mariko_gpu_volt(const CustomizeTable* t, int idx) {
|
||||
if (!t || idx < 0 || idx >= 24) return 0;
|
||||
return t->marikoGpuVoltArray[idx];
|
||||
}
|
||||
|
||||
#define DECL_ERISTA_GPU_VOLT_HELPER(freq, idx) \
|
||||
static inline bool cust_set_erista_gpu_volt_##freq( \
|
||||
const char* p, u32 v) { \
|
||||
return cust_set_erista_gpu_volt(p, idx, v); \
|
||||
}
|
||||
|
||||
#define DECL_MARIKO_GPU_VOLT_HELPER(freq, idx) \
|
||||
static inline bool cust_set_mariko_gpu_volt_##freq( \
|
||||
const char* p, u32 v) { \
|
||||
return cust_set_mariko_gpu_volt(p, idx, v); \
|
||||
}
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(76800, 0)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(115200, 1)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(153600, 2)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(192000, 3)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(230400, 4)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(268800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(307200, 6)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(345600, 7)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(384000, 8)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(422400, 9)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(460800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(499200, 11)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(537600, 12)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(576000, 13)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(614400, 14)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(652800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(691200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(729600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(768000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(806400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(844800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(883200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(921600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(960000, 23)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(998400, 24)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1036800, 25)
|
||||
DECL_ERISTA_GPU_VOLT_HELPER(1075200, 26)
|
||||
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(76800, 0)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(153600, 1)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(230400, 2)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(307200, 3)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(384000, 4)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(460800, 5)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(537600, 6)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(614400, 7)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(691200, 8)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(768000, 9)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(844800, 10)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(921600, 11)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(998400, 12)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1075200, 13)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1152000, 14)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1228800, 15)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1267200, 16)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1305600, 17)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1344000, 18)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1382400, 19)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1420800, 20)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1459200, 21)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1497600, 22)
|
||||
DECL_MARIKO_GPU_VOLT_HELPER(1536000, 23)
|
||||
|
||||
#define DECL_ERISTA_GPU_VOLT_GET(freq, idx) \
|
||||
static inline u32 cust_get_erista_gpu_volt_##freq##_val(const char* p) { \
|
||||
CustomizeTable t; \
|
||||
if (!cust_read_table(p, &t)) return 0; \
|
||||
return cust_get_erista_gpu_volt(&t, idx); \
|
||||
}
|
||||
#define DECL_MARIKO_GPU_VOLT_GET(freq, idx) \
|
||||
static inline u32 cust_get_mariko_gpu_volt_##freq##_val(const char* p) { \
|
||||
CustomizeTable t; \
|
||||
if (!cust_read_table(p, &t)) return 0; \
|
||||
return cust_get_mariko_gpu_volt(&t, idx); \
|
||||
}
|
||||
|
||||
DECL_ERISTA_GPU_VOLT_GET(76800, 0)
|
||||
DECL_ERISTA_GPU_VOLT_GET(115200, 1)
|
||||
DECL_ERISTA_GPU_VOLT_GET(153600, 2)
|
||||
DECL_ERISTA_GPU_VOLT_GET(192000, 3)
|
||||
DECL_ERISTA_GPU_VOLT_GET(230400, 4)
|
||||
DECL_ERISTA_GPU_VOLT_GET(268800, 5)
|
||||
DECL_ERISTA_GPU_VOLT_GET(307200, 6)
|
||||
DECL_ERISTA_GPU_VOLT_GET(345600, 7)
|
||||
DECL_ERISTA_GPU_VOLT_GET(384000, 8)
|
||||
DECL_ERISTA_GPU_VOLT_GET(422400, 9)
|
||||
DECL_ERISTA_GPU_VOLT_GET(460800, 10)
|
||||
DECL_ERISTA_GPU_VOLT_GET(499200, 11)
|
||||
DECL_ERISTA_GPU_VOLT_GET(537600, 12)
|
||||
DECL_ERISTA_GPU_VOLT_GET(576000, 13)
|
||||
DECL_ERISTA_GPU_VOLT_GET(614400, 14)
|
||||
DECL_ERISTA_GPU_VOLT_GET(652800, 15)
|
||||
DECL_ERISTA_GPU_VOLT_GET(691200, 16)
|
||||
DECL_ERISTA_GPU_VOLT_GET(729600, 17)
|
||||
DECL_ERISTA_GPU_VOLT_GET(768000, 18)
|
||||
DECL_ERISTA_GPU_VOLT_GET(806400, 19)
|
||||
DECL_ERISTA_GPU_VOLT_GET(844800, 20)
|
||||
DECL_ERISTA_GPU_VOLT_GET(883200, 21)
|
||||
DECL_ERISTA_GPU_VOLT_GET(921600, 22)
|
||||
DECL_ERISTA_GPU_VOLT_GET(960000, 23)
|
||||
DECL_ERISTA_GPU_VOLT_GET(998400, 24)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1036800, 25)
|
||||
DECL_ERISTA_GPU_VOLT_GET(1075200, 26)
|
||||
|
||||
DECL_MARIKO_GPU_VOLT_GET(76800, 0)
|
||||
DECL_MARIKO_GPU_VOLT_GET(153600, 1)
|
||||
DECL_MARIKO_GPU_VOLT_GET(230400, 2)
|
||||
DECL_MARIKO_GPU_VOLT_GET(307200, 3)
|
||||
DECL_MARIKO_GPU_VOLT_GET(384000, 4)
|
||||
DECL_MARIKO_GPU_VOLT_GET(460800, 5)
|
||||
DECL_MARIKO_GPU_VOLT_GET(537600, 6)
|
||||
DECL_MARIKO_GPU_VOLT_GET(614400, 7)
|
||||
DECL_MARIKO_GPU_VOLT_GET(691200, 8)
|
||||
DECL_MARIKO_GPU_VOLT_GET(768000, 9)
|
||||
DECL_MARIKO_GPU_VOLT_GET(844800, 10)
|
||||
DECL_MARIKO_GPU_VOLT_GET(921600, 11)
|
||||
DECL_MARIKO_GPU_VOLT_GET(998400, 12)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1075200, 13)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1152000, 14)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1228800, 15)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1267200, 16)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1305600, 17)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1344000, 18)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1382400, 19)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1420800, 20)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1459200, 21)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1497600, 22)
|
||||
DECL_MARIKO_GPU_VOLT_GET(1536000, 23)
|
||||
|
||||
void SetKipData();
|
||||
void GetKipData();
|
||||
}
|
||||
169
Source/hoc-clk/sysmodule/src/main.cpp
Normal file
169
Source/hoc-clk/sysmodule/src/main.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <cstdlib>
|
||||
#include <cstring>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "errors.hpp"
|
||||
#include "file_utils.hpp"
|
||||
#include "board/board.hpp"
|
||||
#include "process_management.hpp"
|
||||
#include "clock_manager.hpp"
|
||||
#include "ipc_service.hpp"
|
||||
#include "config.hpp"
|
||||
#define INNER_HEAP_SIZE 0x45000
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void virtmemSetup(void);
|
||||
|
||||
extern std::uint32_t __start__;
|
||||
|
||||
std::uint32_t __nx_applet_type = AppletType_None;
|
||||
TimeServiceType __nx_time_service_type = TimeServiceType_System;
|
||||
std::uint32_t __nx_fs_num_sessions = 1;
|
||||
u32 __nx_nv_transfermem_size = 0x8000;
|
||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||
NvServiceType __nx_nv_service_type = NvServiceType_Factory;
|
||||
|
||||
|
||||
void __libnx_initheap(void)
|
||||
{
|
||||
void* addr = nx_inner_heap;
|
||||
size_t size = nx_inner_heap_size;
|
||||
|
||||
/* Newlib Heap Management */
|
||||
extern char* fake_heap_start;
|
||||
extern char* fake_heap_end;
|
||||
|
||||
fake_heap_start = (char*)addr;
|
||||
fake_heap_end = (char*)addr + size;
|
||||
|
||||
virtmemSetup();
|
||||
}
|
||||
|
||||
void __appInit(void)
|
||||
{
|
||||
if (R_FAILED(smInitialize()))
|
||||
{
|
||||
fatalThrow(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
|
||||
}
|
||||
|
||||
Result rc = setsysInitialize();
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
SetSysFirmwareVersion fw;
|
||||
rc = setsysGetFirmwareVersion(&fw);
|
||||
if (R_SUCCEEDED(rc))
|
||||
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
|
||||
setsysExit();
|
||||
}
|
||||
|
||||
// rc = fanInitialize();
|
||||
// if (R_FAILED(rc))
|
||||
// diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
|
||||
rc = i2cInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
rc = appletInitialize();
|
||||
if (R_FAILED(rc))
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
|
||||
}
|
||||
|
||||
void __appExit(void)
|
||||
{
|
||||
// CloseFanControllerThread();
|
||||
// fanExit();
|
||||
i2cExit();
|
||||
fsExit();
|
||||
fsdevUnmountAll();
|
||||
appletExit();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Result rc = fileUtils::Initialize();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
fatalThrow(rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
board::Initialize();
|
||||
processManagement::Initialize();
|
||||
|
||||
processManagement::WaitForQLaunch();
|
||||
|
||||
clockManager::Initialize();
|
||||
ipcService::Initialize();
|
||||
|
||||
fileUtils::LogLine("Ready");
|
||||
|
||||
clockManager::SetRunning(true);
|
||||
config::SetEnabled(true);
|
||||
ipcService::SetRunning(true);
|
||||
// TemperaturePoint *table;
|
||||
// ReadConfigFile(&table);
|
||||
// InitFanController(table);
|
||||
// StartFanControllerThread();
|
||||
|
||||
while (clockManager::Running())
|
||||
{
|
||||
clockManager::Tick();
|
||||
clockManager::WaitForNextTick();
|
||||
}
|
||||
|
||||
ipcService::SetRunning(false);
|
||||
ipcService::Exit();
|
||||
clockManager::Exit();
|
||||
processManagement::Exit();
|
||||
board::Exit();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fileUtils::LogLine("[!] %s", ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::exception_ptr p = std::current_exception();
|
||||
fileUtils::LogLine("[!?] %s", p ? p.__cxa_exception_type()->name() : "...");
|
||||
}
|
||||
|
||||
fileUtils::LogLine("Exit");
|
||||
svcSleepThread(1000000ULL);
|
||||
fileUtils::Exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
87
Source/hoc-clk/sysmodule/src/process_management.cpp
Normal file
87
Source/hoc-clk/sysmodule/src/process_management.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 "process_management.hpp"
|
||||
#include "file_utils.hpp"
|
||||
#include "errors.hpp"
|
||||
|
||||
namespace processManagement {
|
||||
|
||||
namespace {
|
||||
constexpr u64 Qlaunch = 0x0100000000001000ULL;
|
||||
constexpr u32 IsQlaunch = 0x20f;
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
Result rc = 0;
|
||||
|
||||
rc = pmdmntInitialize();
|
||||
ASSERT_RESULT_OK(rc, "pmdmntInitialize");
|
||||
|
||||
rc = pminfoInitialize();
|
||||
ASSERT_RESULT_OK(rc, "pminfoInitialize");
|
||||
}
|
||||
|
||||
void WaitForQLaunch() {
|
||||
|
||||
Result rc = 0;
|
||||
u64 pid = 0;
|
||||
do {
|
||||
rc = pmdmntGetProcessId(&pid, Qlaunch);
|
||||
svcSleepThread(50 * 1000000ULL); // 50ms
|
||||
} while (R_FAILED(rc));
|
||||
}
|
||||
|
||||
u64 GetCurrentApplicationId() {
|
||||
Result rc = 0;
|
||||
u64 pid = 0;
|
||||
u64 tid = 0;
|
||||
rc = pmdmntGetApplicationProcessId(&pid);
|
||||
|
||||
if (rc == IsQlaunch) {
|
||||
return Qlaunch;
|
||||
}
|
||||
|
||||
ASSERT_RESULT_OK(rc, "pmdmntGetApplicationProcessId");
|
||||
|
||||
rc = pminfoGetProgramId(&tid, pid);
|
||||
|
||||
if (rc == IsQlaunch) {
|
||||
return Qlaunch;
|
||||
}
|
||||
|
||||
ASSERT_RESULT_OK(rc, "pminfoGetProgramId");
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
pmdmntExit();
|
||||
pminfoExit();
|
||||
}
|
||||
|
||||
}
|
||||
38
Source/hoc-clk/sysmodule/src/process_management.hpp
Normal file
38
Source/hoc-clk/sysmodule/src/process_management.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
namespace processManagement {
|
||||
|
||||
void Initialize();
|
||||
void WaitForQLaunch();
|
||||
u64 GetCurrentApplicationId();
|
||||
void Exit();
|
||||
|
||||
}
|
||||
649
Source/hoc-clk/sysmodule/src/soctherm.cpp
Normal file
649
Source/hoc-clk/sysmodule/src/soctherm.cpp
Normal file
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
* Copyright (c) 2014 - 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Mikko Perttunen <mperttunen@nvidia.com>
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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 <switch.h>
|
||||
#include <sysclk.h>
|
||||
#include "soctherm.hpp"
|
||||
#include "board/board.hpp"
|
||||
#include "file_utils.hpp"
|
||||
|
||||
namespace soctherm {
|
||||
|
||||
namespace {
|
||||
|
||||
#define FUSE_CACHE_OFFSET 0x800
|
||||
#define FUSE_TSENSOR_COMMON 0xA80
|
||||
#define CAR_CLK_SOURCE_TSENSOR 0x3B8
|
||||
#define CAR_CLK_OUT_ENB_V 0x360
|
||||
|
||||
#define CLK_RST_CONTROLLER_RST_DEVICES 0xC
|
||||
#define SWR_SOC_THERM_RST 1 << 14
|
||||
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB 0x18
|
||||
#define CLK_ENB_SOC_THERM 1 << 14
|
||||
|
||||
#define CAR_CLK_SOURCE_TSENSOR_VAL 0x8000005E
|
||||
|
||||
#define NOMINAL_CALIB_FT 105
|
||||
#define NOMINAL_CALIB_CP 25
|
||||
|
||||
#define THERMCTL_LEVEL0_GROUP_CPU 0x0
|
||||
#define THERMCTL_LEVEL0_GROUP_GPU 0x4
|
||||
#define THERMCTL_LEVEL0_GROUP_MEM 0x8
|
||||
#define THERMCTL_LEVEL0_GROUP_TSENSE 0xc
|
||||
|
||||
#define TEGRA124_SOCTHERM_SENSOR_CPU 0
|
||||
#define TEGRA124_SOCTHERM_SENSOR_MEM 1
|
||||
#define TEGRA124_SOCTHERM_SENSOR_GPU 2
|
||||
#define TEGRA124_SOCTHERM_SENSOR_PLLX 3
|
||||
#define TEGRA124_SOCTHERM_SENSOR_NUM 4
|
||||
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_NONE 0
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 1
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_MED 2
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 3
|
||||
|
||||
#define SENSOR_CONFIG2 8
|
||||
#define SENSOR_CONFIG2_THERMA_MASK (0xffffu << 16)
|
||||
#define SENSOR_CONFIG2_THERMA_SHIFT 16
|
||||
#define SENSOR_CONFIG2_THERMB_MASK 0xffff
|
||||
#define SENSOR_CONFIG2_THERMB_SHIFT 0
|
||||
|
||||
#define THERMCTL_THERMTRIP_CTL 0x80
|
||||
|
||||
#define SENSOR_PDIV 0x1c0
|
||||
#define SENSOR_PDIV_CPU_MASK (0xf << 12)
|
||||
#define SENSOR_PDIV_GPU_MASK (0xf << 8)
|
||||
#define SENSOR_PDIV_MEM_MASK (0xf << 4)
|
||||
#define SENSOR_PDIV_PLLX_MASK (0xf << 0)
|
||||
|
||||
#define SENSOR_HOTSPOT_OFF 0x1c4
|
||||
#define SENSOR_HOTSPOT_CPU_MASK (0xff << 16)
|
||||
#define SENSOR_HOTSPOT_GPU_MASK (0xff << 8)
|
||||
#define SENSOR_HOTSPOT_MEM_MASK (0xff << 0)
|
||||
|
||||
#define SENSOR_HW_PLLX_OFFSET_EN 0x1e4
|
||||
#define SENSOR_HW_PLLX_OFFSET_MEM_EN_MASK BIT(2)
|
||||
#define SENSOR_HW_PLLX_OFFSET_CPU_EN_MASK BIT(1)
|
||||
#define SENSOR_HW_PLLX_OFFSET_GPU_EN_MASK BIT(0)
|
||||
|
||||
#define SENSOR_HW_PLLX_OFFSET_MIN 0x1e8
|
||||
#define SENSOR_HW_PLLX_OFFSET_MAX 0x1ec
|
||||
#define SENSOR_HW_PLLX_OFFSET_MEM_MASK (0xff << 16)
|
||||
#define SENSOR_HW_PLLX_OFFSET_GPU_MASK (0xff << 8)
|
||||
#define SENSOR_HW_PLLX_OFFSET_CPU_MASK (0xff << 0)
|
||||
|
||||
#define SENSOR_TEMP1 0x1c8
|
||||
#define SENSOR_TEMP1_CPU_TEMP_MASK (0xffffu << 16)
|
||||
#define SENSOR_TEMP1_GPU_TEMP_MASK 0xffff
|
||||
#define SENSOR_TEMP2 0x1cc
|
||||
#define SENSOR_TEMP2_MEM_TEMP_MASK (0xffffu << 16)
|
||||
#define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff
|
||||
|
||||
#define SENSOR_VALID 0x1e0
|
||||
#define SENSOR_GPU_VALID_MASK BIT(9)
|
||||
#define SENSOR_CPU_VALID_MASK 0xf
|
||||
#define SENSOR_MEM_VALID_MASK (0x3 << 10)
|
||||
|
||||
#define TEGRA210_THERMTRIP_ANY_EN_MASK (0x1u << 31)
|
||||
#define TEGRA210_THERMTRIP_MEM_EN_MASK (0x1 << 30)
|
||||
#define TEGRA210_THERMTRIP_GPU_EN_MASK (0x1 << 29)
|
||||
#define TEGRA210_THERMTRIP_CPU_EN_MASK (0x1 << 28)
|
||||
#define TEGRA210_THERMTRIP_TSENSE_EN_MASK (0x1 << 27)
|
||||
#define TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK (0x1ff << 18)
|
||||
#define TEGRA210_THERMTRIP_CPU_THRESH_MASK (0x1ff << 9)
|
||||
#define TEGRA210_THERMTRIP_TSENSE_THRESH_MASK 0x1ff
|
||||
|
||||
#define TEGRA210_THERM_IRQ_MEM_MASK (0x3 << 24)
|
||||
#define TEGRA210_THERM_IRQ_GPU_MASK (0x3 << 16)
|
||||
#define TEGRA210_THERM_IRQ_CPU_MASK (0x3 << 8)
|
||||
#define TEGRA210_THERM_IRQ_TSENSE_MASK (0x3 << 0)
|
||||
|
||||
#define TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK (0x1ff << 18)
|
||||
#define TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK (0x1ff << 9)
|
||||
|
||||
#define TEGRA210_THRESH_GRAIN 500
|
||||
#define TEGRA210_BPTT 9
|
||||
|
||||
#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
|
||||
#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
|
||||
#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
|
||||
#define CALIB_COEFFICIENT 1000000LL
|
||||
|
||||
#define SENSOR_CONFIG0 0
|
||||
#define SENSOR_CONFIG0_STOP BIT(0)
|
||||
#define SENSOR_CONFIG0_CPTR_OVER BIT(2)
|
||||
#define SENSOR_CONFIG0_OVER BIT(3)
|
||||
#define SENSOR_CONFIG0_TCALC_OVER BIT(4)
|
||||
#define SENSOR_CONFIG0_TALL_MASK (0xfffff << 8)
|
||||
#define SENSOR_CONFIG0_TALL_SHIFT 8
|
||||
|
||||
#define PDIV_RATE_T210B0 0xCC0C
|
||||
#define PDIV_RATE_T210 0x8888
|
||||
#define HOTSPOT_VAL 0xA0500
|
||||
|
||||
#define SENSOR_CONFIG1 4
|
||||
#define SENSOR_CONFIG1_TSAMPLE_MASK 0x3ff
|
||||
#define SENSOR_CONFIG1_TSAMPLE_SHIFT 0
|
||||
#define SENSOR_CONFIG1_TIDDQ_EN_MASK (0x3f << 15)
|
||||
#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15
|
||||
#define SENSOR_CONFIG1_TEN_COUNT_MASK (0x3f << 24)
|
||||
#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24
|
||||
#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)
|
||||
|
||||
#define READBACK_VALUE_MASK 0xff00
|
||||
#define READBACK_VALUE_SHIFT 8
|
||||
#define READBACK_ADD_HALF BIT(7)
|
||||
#define READBACK_NEGATE BIT(0)
|
||||
|
||||
#define PDIV_MASK_T210B0 0xFFFF00F0
|
||||
#define HOTSPOT_MASK_T210B0 0xFF0000FF
|
||||
|
||||
#define PDIV_MASK_T210 0xFFFF0000
|
||||
#define HOTSPOT_MASK_T210 0xFF000000
|
||||
|
||||
#define TSENSOR_TSENSOR_CLKEN 0x1DC
|
||||
#define TSENSOR_TSENSOR_ENABLE 225
|
||||
|
||||
const TSensorFuse tfuse = {
|
||||
.fuse_base_cp_mask = 0x3ff << 11,
|
||||
.fuse_base_cp_shift = 11,
|
||||
.fuse_base_ft_mask = 0x7ffu << 21,
|
||||
.fuse_base_ft_shift = 21,
|
||||
.fuse_shift_ft_mask = 0x1f << 6,
|
||||
.fuse_shift_ft_shift = 6,
|
||||
.fuse_spare_realignment = 0,
|
||||
};
|
||||
|
||||
const TSensorConfig eristaConf = {
|
||||
.tall = 16300,
|
||||
.tiddq_en = 1,
|
||||
.ten_count = 1,
|
||||
.pdiv = 8,
|
||||
.pdiv_ate = 8,
|
||||
.tsample = 120,
|
||||
.tsample_ate = 480,
|
||||
};
|
||||
|
||||
const TSensorConfig marikoConf = {
|
||||
.tall = 16300,
|
||||
.tiddq_en = 1,
|
||||
.ten_count = 1,
|
||||
.pdiv = 12,
|
||||
.pdiv_ate = 6,
|
||||
.tsample = 240,
|
||||
.tsample_ate = 480,
|
||||
};
|
||||
|
||||
const struct TSensorGroup tSensorGroupCpu = {
|
||||
.name = "cpu",
|
||||
.id = TEGRA124_SOCTHERM_SENSOR_CPU,
|
||||
.sensor_temp_offset = SENSOR_TEMP1,
|
||||
.sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK,
|
||||
.pdiv_mask = SENSOR_PDIV_CPU_MASK,
|
||||
.pllx_hotspot_diff = 10,
|
||||
.pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK,
|
||||
.hw_pllx_offset_mask = SENSOR_HW_PLLX_OFFSET_CPU_MASK,
|
||||
.hw_pllx_offset_en_mask = SENSOR_HW_PLLX_OFFSET_CPU_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK,
|
||||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
|
||||
.thermctl_isr_mask = TEGRA210_THERM_IRQ_CPU_MASK,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
};
|
||||
|
||||
const struct TSensorGroup tSensorGroupGpu = {
|
||||
.name = "gpu",
|
||||
.id = TEGRA124_SOCTHERM_SENSOR_GPU,
|
||||
.sensor_temp_offset = SENSOR_TEMP1,
|
||||
.sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK,
|
||||
.pdiv_mask = SENSOR_PDIV_GPU_MASK,
|
||||
.pllx_hotspot_diff = 5,
|
||||
.pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK,
|
||||
.hw_pllx_offset_mask = SENSOR_HW_PLLX_OFFSET_GPU_MASK,
|
||||
.hw_pllx_offset_en_mask = SENSOR_HW_PLLX_OFFSET_GPU_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK,
|
||||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
|
||||
.thermctl_isr_mask = TEGRA210_THERM_IRQ_GPU_MASK,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
};
|
||||
|
||||
const struct TSensorGroup tSensorGroupPll = {
|
||||
.name = "pll",
|
||||
.id = TEGRA124_SOCTHERM_SENSOR_PLLX,
|
||||
.sensor_temp_offset = SENSOR_TEMP2,
|
||||
.sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK,
|
||||
.pdiv_mask = SENSOR_PDIV_PLLX_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK,
|
||||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
|
||||
.thermctl_isr_mask = TEGRA210_THERM_IRQ_TSENSE_MASK,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
};
|
||||
|
||||
const struct TSensorGroup eristaTSensorGroupMem = {
|
||||
.name = "mem",
|
||||
.id = TEGRA124_SOCTHERM_SENSOR_MEM,
|
||||
.sensor_temp_offset = SENSOR_TEMP2,
|
||||
.sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK,
|
||||
.pdiv_mask = SENSOR_PDIV_MEM_MASK,
|
||||
.pllx_hotspot_diff = 0,
|
||||
.pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK,
|
||||
.hw_pllx_offset_mask = SENSOR_HW_PLLX_OFFSET_MEM_MASK,
|
||||
.hw_pllx_offset_en_mask = SENSOR_HW_PLLX_OFFSET_MEM_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK,
|
||||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
|
||||
.thermctl_isr_mask = TEGRA210_THERM_IRQ_MEM_MASK,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
};
|
||||
|
||||
const TSensor eristaTSensors[] = {
|
||||
{
|
||||
.name = "cpu0",
|
||||
.base = 0xc0,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x198,
|
||||
.fuse_corr = {
|
||||
.alpha = 1085000,
|
||||
.beta = 3244200,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu1",
|
||||
.base = 0xe0,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x184,
|
||||
.fuse_corr = {
|
||||
.alpha = 1126200,
|
||||
.beta = -67500,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu2",
|
||||
.base = 0x100,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x188,
|
||||
.fuse_corr = {
|
||||
.alpha = 1098400,
|
||||
.beta = 2251100,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu3",
|
||||
.base = 0x120,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x22c,
|
||||
.fuse_corr = {
|
||||
.alpha = 1108000,
|
||||
.beta = 602700,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "gpu",
|
||||
.base = 0x180,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x254,
|
||||
.fuse_corr = {
|
||||
.alpha = 1074300,
|
||||
.beta = 2734900,
|
||||
},
|
||||
.group = &tSensorGroupGpu,
|
||||
}, {
|
||||
.name = "pllx",
|
||||
.base = 0x1a0,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x260,
|
||||
.fuse_corr = {
|
||||
.alpha = 1039700,
|
||||
.beta = 6829100,
|
||||
},
|
||||
.group = &tSensorGroupPll,
|
||||
}, {
|
||||
.name = "mem0",
|
||||
.base = 0x140,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x258,
|
||||
.fuse_corr = {
|
||||
.alpha = 1069200,
|
||||
.beta = 3549900,
|
||||
},
|
||||
.group = &eristaTSensorGroupMem,
|
||||
}, {
|
||||
.name = "mem1",
|
||||
.base = 0x160,
|
||||
.config = &eristaConf,
|
||||
.calib_fuse_offset = 0x25c,
|
||||
.fuse_corr = {
|
||||
.alpha = 1173700,
|
||||
.beta = -6263600,
|
||||
},
|
||||
.group = &eristaTSensorGroupMem,
|
||||
},
|
||||
};
|
||||
|
||||
const TSensor marikoTSensors[] = {
|
||||
{
|
||||
.name = "cpu0",
|
||||
.base = 0xc0,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x198,
|
||||
.fuse_corr = {
|
||||
.alpha = 1085000,
|
||||
.beta = 3244200,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu1",
|
||||
.base = 0xe0,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x184,
|
||||
.fuse_corr = {
|
||||
.alpha = 1126200,
|
||||
.beta = -67500,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu2",
|
||||
.base = 0x100,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x188,
|
||||
.fuse_corr = {
|
||||
.alpha = 1098400,
|
||||
.beta = 2251100,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "cpu3",
|
||||
.base = 0x120,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x22c,
|
||||
.fuse_corr = {
|
||||
.alpha = 1108000,
|
||||
.beta = 602700,
|
||||
},
|
||||
.group = &tSensorGroupCpu,
|
||||
}, {
|
||||
.name = "gpu",
|
||||
.base = 0x180,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x254,
|
||||
.fuse_corr = {
|
||||
.alpha = 1074300,
|
||||
.beta = 2734900,
|
||||
},
|
||||
.group = &tSensorGroupGpu,
|
||||
}, {
|
||||
.name = "pllx",
|
||||
.base = 0x1a0,
|
||||
.config = &marikoConf,
|
||||
.calib_fuse_offset = 0x260,
|
||||
.fuse_corr = {
|
||||
.alpha = 1039700,
|
||||
.beta = 6829100,
|
||||
},
|
||||
.group = &tSensorGroupPll,
|
||||
},
|
||||
};
|
||||
|
||||
u32 calib[SocthermTSensor_EnumMax] = {};
|
||||
u64 socthermVa, carVa, fuseVa;
|
||||
bool isMariko;
|
||||
}
|
||||
|
||||
template<typename T = u32>
|
||||
static inline T ReadReg(u64 base, u32 offset) {
|
||||
return *reinterpret_cast<volatile T*>(base + offset);
|
||||
}
|
||||
|
||||
template<typename T = u32>
|
||||
static inline void WriteReg(u64 base, u32 offset, T value) {
|
||||
*reinterpret_cast<volatile T*>(base + offset) = value;
|
||||
}
|
||||
|
||||
template<typename T = u32>
|
||||
static inline void SetBits(u64 base, u32 offset, T mask) {
|
||||
WriteReg(base, offset, ReadReg<T>(base, offset) | mask);
|
||||
}
|
||||
|
||||
template<typename T = u32>
|
||||
static inline void ClearBits(u64 base, u32 offset, T mask) {
|
||||
WriteReg(base, offset, ReadReg<T>(base, offset) & ~mask);
|
||||
}
|
||||
|
||||
Result MapAddress(u64 &va, const u64 &physAddr, const char *name) {
|
||||
u64 outSize;
|
||||
Result mapResult = svcQueryMemoryMapping(&va, &outSize, physAddr, 0x1000);
|
||||
if (R_FAILED(mapResult)) {
|
||||
fileUtils::LogLine("[Soctherm] Failed to map %s! %u", name, R_DESCRIPTION(mapResult));
|
||||
}
|
||||
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
static inline s32 sign_extend32(u32 value, int index) {
|
||||
u8 shift = 31 - index;
|
||||
return (s32) (value << shift) >> shift;
|
||||
}
|
||||
|
||||
static inline s64 div64_s64(s64 dividend, s64 divisor) {
|
||||
return dividend / divisor;
|
||||
}
|
||||
|
||||
static s64 div64_s64_precise(s64 a, s32 b) {
|
||||
s64 r, al;
|
||||
|
||||
al = a << 16;
|
||||
|
||||
r = div64_s64(al * 2 + 1, 2 * b);
|
||||
return r >> 16;
|
||||
}
|
||||
|
||||
bool IsDisabledThroughSleep() {
|
||||
return (ReadReg(carVa, CLK_RST_CONTROLLER_RST_DEVICES) & SWR_SOC_THERM_RST) || !(ReadReg(carVa, CLK_RST_CONTROLLER_CLK_OUT_ENB) & CLK_ENB_SOC_THERM);
|
||||
}
|
||||
|
||||
bool IsSensorEnabled() {
|
||||
return ReadReg(socthermVa, TSENSOR_TSENSOR_CLKEN);
|
||||
}
|
||||
|
||||
void EnableSensor(const TSensor *sensor, u32 sensorIdx) {
|
||||
u32 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
|
||||
WriteReg(socthermVa, sensor->base + SENSOR_CONFIG0, val);
|
||||
|
||||
val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
|
||||
val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
|
||||
val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
|
||||
val |= SENSOR_CONFIG1_TEMP_ENABLE;
|
||||
WriteReg(socthermVa, sensor->base + SENSOR_CONFIG1, val);
|
||||
WriteReg(socthermVa, sensor->base + SENSOR_CONFIG2, calib[sensorIdx]);
|
||||
}
|
||||
|
||||
s32 TranslateTemp(u16 val) {
|
||||
s32 t;
|
||||
|
||||
t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
|
||||
if (val & READBACK_ADD_HALF) {
|
||||
t += 500;
|
||||
}
|
||||
|
||||
if (val & READBACK_NEGATE) {
|
||||
t *= -1;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void StartSensors() {
|
||||
u32 pdiv, hotspot;
|
||||
|
||||
if (isMariko) {
|
||||
for (u32 i = 0; i < std::size(marikoTSensors); ++i) {
|
||||
EnableSensor(&marikoTSensors[i], i);
|
||||
}
|
||||
|
||||
pdiv = (ReadReg(socthermVa, SENSOR_PDIV) & PDIV_MASK_T210B0) | PDIV_RATE_T210B0;
|
||||
hotspot = (ReadReg(socthermVa, SENSOR_HOTSPOT_OFF) & HOTSPOT_MASK_T210B0) | HOTSPOT_VAL;
|
||||
} else {
|
||||
for (u32 i = 0; i < std::size(eristaTSensors); ++i) {
|
||||
EnableSensor(&eristaTSensors[i], i);
|
||||
}
|
||||
|
||||
pdiv = (ReadReg(socthermVa, SENSOR_PDIV) & PDIV_MASK_T210) | PDIV_RATE_T210;
|
||||
hotspot = (ReadReg(socthermVa, SENSOR_HOTSPOT_OFF) & HOTSPOT_MASK_T210) | HOTSPOT_VAL;
|
||||
|
||||
EnableSensor(&eristaTSensors[SocthermTSensor_MEM0], SocthermTSensor_MEM0);
|
||||
EnableSensor(&eristaTSensors[SocthermTSensor_MEM1], SocthermTSensor_MEM1);
|
||||
}
|
||||
|
||||
WriteReg(socthermVa, SENSOR_PDIV, pdiv);
|
||||
WriteReg(socthermVa, SENSOR_HOTSPOT_OFF, hotspot);
|
||||
WriteReg(socthermVa, TSENSOR_TSENSOR_CLKEN, TSENSOR_TSENSOR_ENABLE);
|
||||
}
|
||||
|
||||
void ReadSensors(TSensorTemps &temps) {
|
||||
if (IsDisabledThroughSleep()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsSensorEnabled()) {
|
||||
StartSensors();
|
||||
}
|
||||
|
||||
temps.cpu = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP1) >> 16);
|
||||
temps.gpu = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP1) & SENSOR_TEMP1_GPU_TEMP_MASK);
|
||||
temps.pllx = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP2) & SENSOR_TEMP2_PLLX_TEMP_MASK);
|
||||
|
||||
if (board::GetSocType() == SysClkSocType_Erista) {
|
||||
temps.mem = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP2) >> 16);
|
||||
} else {
|
||||
temps.mem = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void CalcSharedCal(const TSensorFuse *tfuse, TSensorSharedCalib *shared, u64 fuseVa) {
|
||||
s32 shifted_cp, shifted_ft;
|
||||
|
||||
u32 val = ReadReg(fuseVa, FUSE_TSENSOR_COMMON);
|
||||
|
||||
shared->base_cp = (val & tfuse->fuse_base_cp_mask) >> tfuse->fuse_base_cp_shift;
|
||||
shared->base_ft = (val & tfuse->fuse_base_ft_mask) >> tfuse->fuse_base_ft_shift;
|
||||
|
||||
shifted_ft = (val & tfuse->fuse_shift_ft_mask) >> tfuse->fuse_shift_ft_shift;
|
||||
shifted_ft = sign_extend32(shifted_ft, 4);
|
||||
|
||||
if (tfuse->fuse_spare_realignment) {
|
||||
val = ReadReg(fuseVa, tfuse->fuse_spare_realignment + FUSE_CACHE_OFFSET);
|
||||
}
|
||||
|
||||
shifted_cp = sign_extend32(val, 5);
|
||||
|
||||
shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp;
|
||||
shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft;
|
||||
}
|
||||
|
||||
void CalcTSensorCalib(const TSensorConfig *cfg, TSensorSharedCalib *shared, const FuseCorrCoeff *corr, u32 *calibration, u32 offset, u64 fuseVa) {
|
||||
u32 val, calib;
|
||||
s32 actual_tsensor_ft, actual_tsensor_cp;
|
||||
s32 delta_sens, delta_temp;
|
||||
s32 mult, div;
|
||||
s16 therma, thermb;
|
||||
s64 temp;
|
||||
|
||||
val = ReadReg(fuseVa, offset + FUSE_CACHE_OFFSET);
|
||||
|
||||
actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
|
||||
val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
|
||||
actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
|
||||
|
||||
delta_sens = actual_tsensor_ft - actual_tsensor_cp;
|
||||
delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
|
||||
|
||||
mult = cfg->pdiv * cfg->tsample_ate;
|
||||
div = cfg->tsample * cfg->pdiv_ate;
|
||||
|
||||
temp = (s64)delta_temp * (1LL << 13) * mult;
|
||||
therma = div64_s64_precise(temp, (s64)delta_sens * div);
|
||||
|
||||
temp = ((s64)actual_tsensor_ft * shared->actual_temp_cp) - ((s64)actual_tsensor_cp * shared->actual_temp_ft);
|
||||
thermb = div64_s64_precise(temp, delta_sens);
|
||||
|
||||
temp = (s64)therma * corr->alpha;
|
||||
therma = div64_s64_precise(temp, CALIB_COEFFICIENT);
|
||||
|
||||
temp = (s64)thermb * corr->alpha + corr->beta;
|
||||
thermb = div64_s64_precise(temp, CALIB_COEFFICIENT);
|
||||
|
||||
calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) | ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
|
||||
|
||||
*calibration = calib;
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
isMariko = board::GetSocType() == SysClkSocType_Mariko;
|
||||
|
||||
constexpr u64 SocthermPa = 0x700E2000, FusePa = 0x7000F000, CarPa = 0x60006000;
|
||||
R_UNLESS(MapAddress(socthermVa, SocthermPa, "soctherm"));
|
||||
R_UNLESS(MapAddress( fuseVa, FusePa, "fuse"));
|
||||
R_UNLESS(MapAddress( carVa, CarPa, "car"));
|
||||
|
||||
WriteReg(carVa, CAR_CLK_SOURCE_TSENSOR, CAR_CLK_SOURCE_TSENSOR_VAL);
|
||||
SetBits(carVa, CAR_CLK_OUT_ENB_V, 0x10);
|
||||
svcSleepThread(2000);
|
||||
|
||||
TSensorSharedCalib sharedCal = {};
|
||||
CalcSharedCal(&tfuse, &sharedCal, fuseVa);
|
||||
|
||||
if (isMariko) {
|
||||
for (u32 i = 0; i < std::size(marikoTSensors); ++i) {
|
||||
CalcTSensorCalib(marikoTSensors[i].config, &sharedCal, &marikoTSensors[i].fuse_corr, &calib[i], marikoTSensors[i].calib_fuse_offset, fuseVa);
|
||||
}
|
||||
} else {
|
||||
for (u32 i = 0; i < std::size(eristaTSensors); ++i) {
|
||||
CalcTSensorCalib(eristaTSensors[i].config, &sharedCal, &eristaTSensors[i].fuse_corr, &calib[i], eristaTSensors[i].calib_fuse_offset, fuseVa);
|
||||
}
|
||||
}
|
||||
|
||||
StartSensors();
|
||||
|
||||
fileUtils::LogLine("[Soctherm] Finished init.");
|
||||
}
|
||||
|
||||
}
|
||||
135
Source/hoc-clk/sysmodule/src/soctherm.hpp
Normal file
135
Source/hoc-clk/sysmodule/src/soctherm.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2014 - 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Mikko Perttunen <mperttunen@nvidia.com>
|
||||
*
|
||||
* Copyright (c) Souldbminer, Lightos_ 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "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
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <sysclk.h>
|
||||
|
||||
namespace soctherm {
|
||||
|
||||
#define R_UNLESS(rc) \
|
||||
do { \
|
||||
if (R_FAILED(rc)) { \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct TSensorConfig {
|
||||
u32 tall;
|
||||
u32 tiddq_en;
|
||||
u32 ten_count;
|
||||
u32 pdiv;
|
||||
u32 pdiv_ate;
|
||||
u32 tsample;
|
||||
u32 tsample_ate;
|
||||
};
|
||||
|
||||
struct FuseCorrCoeff {
|
||||
s32 alpha;
|
||||
s32 beta;
|
||||
};
|
||||
|
||||
struct TSensorGroup {
|
||||
const char *name;
|
||||
u8 id;
|
||||
u16 sensor_temp_offset;
|
||||
u32 sensor_temp_mask;
|
||||
u32 pdiv_mask;
|
||||
u32 pllx_hotspot_diff;
|
||||
u32 pllx_hotspot_mask;
|
||||
u32 hw_pllx_offset_mask;
|
||||
u32 hw_pllx_offset_en_mask;
|
||||
u32 thermtrip_enable_mask;
|
||||
u32 thermtrip_any_en_mask;
|
||||
u32 thermtrip_threshold_mask;
|
||||
u16 thermctl_lvl0_offset;
|
||||
u32 thermctl_isr_mask;
|
||||
u32 thermctl_lvl0_up_thresh_mask;
|
||||
u32 thermctl_lvl0_dn_thresh_mask;
|
||||
};
|
||||
|
||||
struct TSensorGroupOffsets {
|
||||
u32 max;
|
||||
u32 min;
|
||||
u32 hw_offsetting_en;
|
||||
const TSensorGroup *ttg;
|
||||
};
|
||||
|
||||
struct TSensor {
|
||||
const char *name;
|
||||
const u32 base;
|
||||
const TSensorConfig *config;
|
||||
const u32 calib_fuse_offset;
|
||||
const FuseCorrCoeff fuse_corr;
|
||||
const TSensorGroup *group;
|
||||
};
|
||||
|
||||
struct TSensorFuse {
|
||||
u32 fuse_base_cp_mask;
|
||||
u32 fuse_base_cp_shift;
|
||||
u32 fuse_base_ft_mask;
|
||||
u32 fuse_base_ft_shift;
|
||||
u32 fuse_shift_ft_mask;
|
||||
u32 fuse_shift_ft_shift;
|
||||
u32 fuse_spare_realignment;
|
||||
};
|
||||
|
||||
struct TSensorSharedCalib {
|
||||
u32 base_cp;
|
||||
u32 base_ft;
|
||||
u32 actual_temp_cp;
|
||||
u32 actual_temp_ft;
|
||||
};
|
||||
|
||||
enum SocthermTSensor : u32 {
|
||||
SocthermTSensor_CPU0 = 0,
|
||||
SocthermTSensor_CPU1 = 1,
|
||||
SocthermTSensor_CPU2 = 2,
|
||||
SocthermTSensor_CPU3 = 3,
|
||||
SocthermTSensor_GPU = 4,
|
||||
SocthermTSensor_PLLX = 5,
|
||||
SocthermTSensor_MEM0 = 6,
|
||||
SocthermTSensor_MEM1 = 7,
|
||||
SocthermTSensor_EnumMax = 8,
|
||||
};
|
||||
|
||||
struct TSensorTemps {
|
||||
s32 cpu;
|
||||
s32 gpu;
|
||||
s32 mem;
|
||||
s32 pllx;
|
||||
};
|
||||
|
||||
void Initialize();
|
||||
void ReadSensors(TSensorTemps &temps);
|
||||
|
||||
}
|
||||
5
Source/hoc-clk/sysmodule/toolbox.json
Normal file
5
Source/hoc-clk/sysmodule/toolbox.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name" : "hoc-clk",
|
||||
"tid" : "00FF0000636C6BFF",
|
||||
"requires_reboot": false
|
||||
}
|
||||
Reference in New Issue
Block a user