Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46146bd71c | ||
|
|
f7d4960cd3 | ||
|
|
a6c6a95053 | ||
|
|
5120b70231 | ||
|
|
96476a227b | ||
|
|
4586dce57b | ||
|
|
e3900de6c0 | ||
|
|
22fb4ff095 | ||
|
|
9a41e19004 | ||
|
|
b2f4e0c1b4 | ||
|
|
a0f1971353 | ||
|
|
37704d670b | ||
|
|
397d0c4295 | ||
|
|
3981527bb8 | ||
|
|
631de13133 | ||
|
|
2c7f32bbde | ||
|
|
443d43ed7e | ||
|
|
2532ceea2a | ||
|
|
0e8efbb9e9 | ||
|
|
9340183541 | ||
|
|
bd9b01e405 | ||
|
|
53957bb5c7 | ||
|
|
2b84a49ed7 | ||
|
|
895b332a86 | ||
|
|
88b81e5fb0 | ||
|
|
ac04e02a08 | ||
|
|
1c71d12d9d |
@@ -648,7 +648,7 @@ namespace ams::secmon {
|
||||
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||
|
||||
/* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
|
||||
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
|
||||
reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0);
|
||||
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||
|
||||
/* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
|
||||
@@ -907,7 +907,7 @@ namespace ams::secmon {
|
||||
reg::Write(MC + MC_SMMU_PPCS1_ASID, MC_REG_BITS_ENUM(SMMU_PPCS1_ASID_PPCS1_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_PPCS1_ASID_PPCS1_ASID, BpmpAsid));
|
||||
|
||||
/* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
|
||||
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
|
||||
reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0);
|
||||
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||
|
||||
/* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
|
||||
|
||||
@@ -22,7 +22,7 @@ SetRegisterAllowed(MC_SMMU_CONFIG); /* 0x010 */
|
||||
SetRegisterAllowed(MC_SMMU_PTB_ASID); /* 0x01C */
|
||||
SetRegisterAllowed(MC_SMMU_PTB_DATA); /* 0x020 */
|
||||
SetRegisterAllowed(MC_SMMU_TLB_FLUSH); /* 0x030 */
|
||||
SetRegisterAllowed(MC_SMMU_PTC_FLUSH); /* 0x034 */
|
||||
SetRegisterAllowed(MC_SMMU_PTC_FLUSH_0); /* 0x034 */
|
||||
SetRegisterAllowed(MC_EMEM_CFG); /* 0x050 */
|
||||
SetRegisterAllowed(MC_EMEM_ADR_CFG); /* 0x054 */
|
||||
SetRegisterAllowed(MC_EMEM_ARB_CFG); /* 0x090 */
|
||||
@@ -53,7 +53,7 @@ SetRegisterAllowed(MC_SMMU_DCB_ASID); /* 0x244 */
|
||||
SetRegisterAllowed(MC_SMMU_HC_ASID); /* 0x250 */
|
||||
SetRegisterAllowed(MC_SMMU_HDA_ASID); /* 0x254 */
|
||||
SetRegisterAllowed(MC_SMMU_ISP2_ASID); /* 0x258 */
|
||||
SetRegisterAllowed(MC_SMMU_NVENC_ASID); /* 0x264 */
|
||||
SetRegisterAllowed(MC_SMMU_MSENC_NVENC_ASID); /* 0x264 */
|
||||
SetRegisterAllowed(MC_SMMU_NV_ASID); /* 0x268 */
|
||||
SetRegisterAllowed(MC_SMMU_NV2_ASID); /* 0x26C */
|
||||
SetRegisterAllowed(MC_SMMU_PPCS_ASID); /* 0x270 */
|
||||
|
||||
108
exosphere/sdmmc_test/Makefile
Normal file
108
exosphere/sdmmc_test/Makefile
Normal file
@@ -0,0 +1,108 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# Define the atmosphere board and cpu
|
||||
#---------------------------------------------------------------------------------
|
||||
export ATMOSPHERE_BOARD := nx-hac-001
|
||||
export ATMOSPHERE_CPU := arm7tdmi
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in common atmosphere configuration
|
||||
#---------------------------------------------------------------------------------
|
||||
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
|
||||
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
|
||||
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES))))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I.
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD) check_libexo
|
||||
|
||||
$(BUILD): check_libexo
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
check_libexo:
|
||||
@$(MAKE) --no-print-directory -C ../../libraries/libexosphere arm
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).bin
|
||||
|
||||
$(OUTPUT).bin : $(OUTPUT).elf
|
||||
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
$(OUTPUT).elf : $(OFILES) ../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a
|
||||
|
||||
%.elf:
|
||||
@echo linking $(notdir $@)
|
||||
$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h: %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
194
exosphere/sdmmc_test/sdmmc_test.ld
Normal file
194
exosphere/sdmmc_test/sdmmc_test.ld
Normal file
@@ -0,0 +1,194 @@
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_ZN3ams10sdmmc_test5StartEv)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
NULL : ORIGIN = 0, LENGTH = 4K
|
||||
test_fw : ORIGIN = 0x40010000, LENGTH = 32K
|
||||
}
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* =========== CODE section =========== */
|
||||
PROVIDE(__start__ = ORIGIN(test_fw));
|
||||
. = __start__;
|
||||
__code_start = . ;
|
||||
|
||||
.crt0 :
|
||||
{
|
||||
KEEP (*(.crt0 .crt0.*))
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.vectors :
|
||||
{
|
||||
KEEP (*(.vectors .vectors.*))
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.init :
|
||||
{
|
||||
KEEP( *(.init) )
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
*(.iplt)
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP( *(.fini) )
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
|
||||
/* =========== RODATA section =========== */
|
||||
. = ALIGN(8);
|
||||
__rodata_start = . ;
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
. = ALIGN(8);
|
||||
} >test_fw
|
||||
|
||||
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >test_fw
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >test_fw
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >test_fw
|
||||
|
||||
.hash : { *(.hash) } >test_fw
|
||||
|
||||
/* =========== DATA section =========== */
|
||||
. = ALIGN(8);
|
||||
__data_start = . ;
|
||||
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >test_fw
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >test_fw
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >test_fw
|
||||
|
||||
.preinit_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
} >test_fw
|
||||
|
||||
.init_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE (__init_array_end = .);
|
||||
} >test_fw
|
||||
|
||||
.fini_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE (__fini_array_end = .);
|
||||
} >test_fw
|
||||
|
||||
.ctors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >test_fw
|
||||
|
||||
.dtors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >test_fw
|
||||
|
||||
__got_start__ = .;
|
||||
|
||||
.got : { *(.got) *(.igot) } >test_fw
|
||||
.got.plt : { *(.got.plt) *(.igot.plt) } >test_fw
|
||||
|
||||
__got_end__ = .;
|
||||
|
||||
.data ALIGN(8) :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
} >test_fw
|
||||
|
||||
__bss_start__ = .;
|
||||
.bss ALIGN(8) :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
} >test_fw
|
||||
__bss_end__ = .;
|
||||
|
||||
__end__ = ABSOLUTE(.) ;
|
||||
|
||||
__total_size__ = (__end__ - __start__);
|
||||
|
||||
__stack_top__ = 0x40031000;
|
||||
__stack_bottom__ = 0x40030000;
|
||||
|
||||
/* ==================
|
||||
==== Metadata ====
|
||||
================== */
|
||||
|
||||
/* Discard sections that difficult post-processing */
|
||||
/DISCARD/ : { *(.group .comment .note .interp) }
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
}
|
||||
7
exosphere/sdmmc_test/sdmmc_test.specs
Normal file
7
exosphere/sdmmc_test/sdmmc_test.specs
Normal file
@@ -0,0 +1,7 @@
|
||||
%rename link old_link
|
||||
|
||||
*link:
|
||||
%(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic -nostdlib -nostartfiles
|
||||
|
||||
*startfile:
|
||||
crti%O%s crtbegin%O%s
|
||||
146
exosphere/sdmmc_test/source/sdmmc_test_main.cpp
Normal file
146
exosphere/sdmmc_test/source/sdmmc_test_main.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <exosphere.hpp>
|
||||
|
||||
namespace ams::sdmmc_test {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress();
|
||||
|
||||
constexpr inline auto Port = sdmmc::Port_SdCard0;
|
||||
alignas(8) constinit u8 g_sd_work_buffer[sdmmc::SdCardWorkBufferSize];
|
||||
|
||||
constexpr inline u32 SectorIndex = 0;
|
||||
constexpr inline u32 SectorCount = 2;
|
||||
|
||||
NORETURN void PmcMainReboot() {
|
||||
/* Write enable to MAIN_RESET. */
|
||||
reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
|
||||
|
||||
/* Wait forever until we're reset. */
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
void CheckResult(const Result result) {
|
||||
volatile u32 * const DEBUG = reinterpret_cast<volatile u32 *>(0x4003C000);
|
||||
if (R_FAILED(result)) {
|
||||
DEBUG[1] = result.GetValue();
|
||||
PmcMainReboot();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Main() {
|
||||
/* Perform butchered hwinit. */
|
||||
/* TODO: replace with simpler, non-C logic. */
|
||||
/* nx_hwinit(); */
|
||||
|
||||
/* Clear output buffer for debug. */
|
||||
std::memset((void *)0x40038000, 0xAA, 0x400);
|
||||
|
||||
/* Normally, these pins get configured by boot sysmodule during initial pinmux config. */
|
||||
/* However, they're required to access the SD card. */
|
||||
{
|
||||
const uintptr_t apb_misc = dd::QueryIoMapping(0x70000000, 0x4000);
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_CLK, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CLK_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_CMD, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CMD_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT3, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT3_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT2, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT2_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT1, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT1_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT0, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, SDMMC1));
|
||||
|
||||
reg::ReadWrite(apb_misc + PINMUX_AUX_DMIC3_CLK, PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
|
||||
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
|
||||
PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, RSVD2));
|
||||
}
|
||||
|
||||
/* Debug signaler. */
|
||||
volatile u32 * const DEBUG = reinterpret_cast<volatile u32 *>(0x4003C000);
|
||||
DEBUG[0] = 0;
|
||||
DEBUG[1] = 0xAAAAAAAA;
|
||||
|
||||
/* Initialize sdmmc library. */
|
||||
sdmmc::Initialize(Port);
|
||||
DEBUG[0] = 1;
|
||||
|
||||
sdmmc::SetSdCardWorkBuffer(Port, g_sd_work_buffer, sizeof(g_sd_work_buffer));
|
||||
DEBUG[0] = 2;
|
||||
|
||||
Result result = sdmmc::Activate(Port);
|
||||
DEBUG[0] = 3;
|
||||
CheckResult(result);
|
||||
|
||||
/* Read the first two sectors from disk. */
|
||||
void * const sector_dst = reinterpret_cast<void *>(0x40038000);
|
||||
result = sdmmc::Read(sector_dst, SectorCount * sdmmc::SectorSize, Port, SectorIndex, SectorCount);
|
||||
DEBUG[0] = 4;
|
||||
CheckResult(result);
|
||||
|
||||
/* Get the connection status. */
|
||||
sdmmc::SpeedMode speed_mode;
|
||||
sdmmc::BusWidth bus_width;
|
||||
result = sdmmc::CheckSdCardConnection(std::addressof(speed_mode), std::addressof(bus_width), Port);
|
||||
|
||||
/* Save status for debug. */
|
||||
DEBUG[0] = 5;
|
||||
DEBUG[1] = result.GetValue();
|
||||
DEBUG[2] = static_cast<u32>(speed_mode);
|
||||
DEBUG[3] = static_cast<u32>(bus_width);
|
||||
|
||||
/* Perform a reboot. */
|
||||
PmcMainReboot();
|
||||
}
|
||||
|
||||
NORETURN void ExceptionHandler() {
|
||||
PmcMainReboot();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
sdmmc_test::ExceptionHandler();
|
||||
}
|
||||
|
||||
}
|
||||
37
exosphere/sdmmc_test/source/sdmmc_test_start.s
Normal file
37
exosphere/sdmmc_test/source/sdmmc_test_start.s
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
.section .crt0.text._ZN3ams10sdmmc_test5StartEv, "ax", %progbits
|
||||
.align 3
|
||||
.global _ZN3ams10sdmmc_test5StartEv
|
||||
_ZN3ams10sdmmc_test5StartEv:
|
||||
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||
msr cpsr_cxsf, #0xDF
|
||||
|
||||
/* Set the stack pointer. */
|
||||
ldr sp, =__stack_top__
|
||||
|
||||
/* Set our link register to the exception handler. */
|
||||
ldr lr, =_ZN3ams10sdmmc_test16ExceptionHandlerEv
|
||||
|
||||
/* Call init array functions. */
|
||||
bl __libc_init_array
|
||||
|
||||
/* Invoke main. */
|
||||
b _ZN3ams10sdmmc_test4MainEv
|
||||
|
||||
/* Infinite loop. */
|
||||
2: b 2b
|
||||
@@ -30,7 +30,7 @@ _ZN3ams8warmboot5StartEv:
|
||||
|
||||
/* Invoke main. */
|
||||
ldr r0, =_metadata
|
||||
bl _ZN3ams8warmboot4MainEPKNS0_8MetadataE
|
||||
b _ZN3ams8warmboot4MainEPKNS0_8MetadataE
|
||||
|
||||
/* Infinite loop. */
|
||||
1: b 1b
|
||||
@@ -15,8 +15,10 @@ endif
|
||||
|
||||
endif
|
||||
|
||||
ATMOSPHERE_BUILD_SETTINGS ?=
|
||||
|
||||
export ATMOSPHERE_DEFINES := -DATMOSPHERE
|
||||
export ATMOSPHERE_SETTINGS := -fPIE -g
|
||||
export ATMOSPHERE_SETTINGS := -fPIE -g $(ATMOSPHERE_BUILD_SETTINGS)
|
||||
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
|
||||
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \
|
||||
-Wno-format-truncation -Wno-format-zero-length -Wno-stringop-truncation
|
||||
@@ -132,10 +134,15 @@ FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arc
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),os,$(ATMOSPHERE_OS_NAME),$2)) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),cpu,$(ATMOSPHERE_CPU_NAME) $(ATMOSPHERE_CPU_EXTENSIONS),$2))
|
||||
|
||||
ATMOSPHERE_GCH_IDENTIFIER ?= ams_placeholder_gch_identifier
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# Rules for compiling pre-compiled headers
|
||||
#---------------------------------------------------------------------------------
|
||||
%.gch: %.hpp
|
||||
@echo $<
|
||||
$(CXX) -w -x c++-header -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
||||
@cp $@ $(<).gch
|
||||
%.hpp.gch/$(ATMOSPHERE_GCH_IDENTIFIER): %.hpp | %.hpp.gch
|
||||
@echo Precompiling $(notdir $<) for $(ATMOSPHERE_GCH_IDENTIFIER)
|
||||
$(SILENTCMD)$(CXX) -w -x c++-header -MMD -MP -MQ$@ -MF $(DEPSDIR)/$(notdir $*).d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
||||
|
||||
%.hpp.gch: %.hpp
|
||||
@echo Precompiling $(notdir $<)
|
||||
$(SILENTCMD)$(CXX) -w -x c++-header -MMD -MP -MQ$@ -MF $(DEPSDIR)/$(notdir $*).d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
||||
|
||||
@@ -29,7 +29,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
||||
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
|
||||
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
|
||||
|
||||
export LIBS := -lmesosphere
|
||||
export LIBS := -l$(LIBMESOSPHERE_NAME)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
|
||||
@@ -112,6 +112,7 @@ $(OFILES) : $(GCH_FILES)
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
libc.o: CFLAGS += -fno-builtin -fno-lto
|
||||
libgcc_division.arch.arm.o: CFLAGS += -fno-builtin -fno-lto
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%_bin.h %.bin.o : %.bin
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <vapours.hpp>
|
||||
|
||||
#include <exosphere/common.hpp>
|
||||
#include <exosphere/reg.hpp>
|
||||
#include <exosphere/hw.hpp>
|
||||
#include <exosphere/util.hpp>
|
||||
#include <exosphere/mmu.hpp>
|
||||
@@ -41,4 +40,3 @@
|
||||
#include <exosphere/actmon.hpp>
|
||||
#include <exosphere/pmc.hpp>
|
||||
#include <exosphere/secmon.hpp>
|
||||
#include <exosphere/tegra.hpp>
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
#include <exosphere/tegra/tegra_ahb_arbc.hpp>
|
||||
#include <exosphere/tegra/tegra_apb_misc.hpp>
|
||||
#include <exosphere/tegra/tegra_avp_cache.hpp>
|
||||
#include <exosphere/tegra/tegra_clkrst.hpp>
|
||||
#include <exosphere/tegra/tegra_emc.hpp>
|
||||
#include <exosphere/tegra/tegra_evp.hpp>
|
||||
#include <exosphere/tegra/tegra_flow_ctlr.hpp>
|
||||
#include <exosphere/tegra/tegra_ictlr.hpp>
|
||||
#include <exosphere/tegra/tegra_mc.hpp>
|
||||
#include <exosphere/tegra/tegra_mselect.hpp>
|
||||
#include <exosphere/tegra/tegra_pinmux.hpp>
|
||||
#include <exosphere/tegra/tegra_pg_up.hpp>
|
||||
#include <exosphere/tegra/tegra_pmc.hpp>
|
||||
#include <exosphere/tegra/tegra_sb.hpp>
|
||||
#include <exosphere/tegra/tegra_sysctr0.hpp>
|
||||
#include <exosphere/tegra/tegra_timer.hpp>
|
||||
@@ -20,14 +20,6 @@ namespace ams::util {
|
||||
|
||||
void SetRegisterAddress(uintptr_t address);
|
||||
|
||||
u32 GetMicroSeconds();
|
||||
void WaitMicroSeconds(int us);
|
||||
|
||||
void ClearMemory(void *ptr, size_t size);
|
||||
|
||||
template<typename T, typename U> requires std::integral<T> && std::integral<U>
|
||||
constexpr T DivideUp(T x, U y) {
|
||||
return (x + (y - 1)) / y;
|
||||
}
|
||||
|
||||
}
|
||||
27
libraries/libexosphere/source/libc/libexo_cxx.cpp
Normal file
27
libraries/libexosphere/source/libc/libexo_cxx.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <exosphere.hpp>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* cxx implementation details to be stubbed here, as needed. */
|
||||
void __cxa_pure_virtual() { AMS_ABORT("pure virtual function call"); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
160
libraries/libexosphere/source/libc/libgcc_division.arch.arm.c
Normal file
160
libraries/libexosphere/source/libc/libgcc_division.arch.arm.c
Normal file
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Form ABI specifications:
|
||||
* int __aeabi_idiv(int numerator, int denominator);
|
||||
* unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
|
||||
*
|
||||
* typedef struct { int quot; int rem; } idiv_return;
|
||||
* typedef struct { unsigned quot; unsigned rem; } uidiv_return;
|
||||
*
|
||||
* __value_in_regs idiv_return __aeabi_idivmod(int numerator,
|
||||
* int *denominator);
|
||||
* __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
|
||||
* unsigned denominator);
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* struct qr - stores qutient/remainder to handle divmod EABI interfaces. */
|
||||
struct qr {
|
||||
unsigned q; /* computed quotient */
|
||||
unsigned r; /* computed remainder */
|
||||
unsigned q_n; /* specficies if quotient shall be negative */
|
||||
unsigned r_n; /* specficies if remainder shall be negative */
|
||||
};
|
||||
|
||||
static void uint_div_qr(unsigned numerator, unsigned denominator,
|
||||
struct qr *qr);
|
||||
|
||||
/* returns in R0 and R1 by tail calling an asm function */
|
||||
unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator);
|
||||
|
||||
unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
|
||||
|
||||
/* returns in R0 and R1 by tail calling an asm function */
|
||||
signed __aeabi_idivmod(signed numerator, signed denominator);
|
||||
|
||||
signed __aeabi_idiv(signed numerator, signed denominator);
|
||||
|
||||
/*
|
||||
* __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
|
||||
* Numerator and Denominator are received in R0 and R1.
|
||||
* Where __ste_idivmod_ret_t is returned in R0 and R1.
|
||||
*
|
||||
* __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
|
||||
* unsigned denominator)
|
||||
* Numerator and Denominator are received in R0 and R1.
|
||||
* Where __ste_uidivmod_ret_t is returned in R0 and R1.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
signed ret_idivmod_values(signed quotient, signed remainder);
|
||||
unsigned ret_uidivmod_values(unsigned quotient, unsigned remainder);
|
||||
#else
|
||||
#error "Compiler not supported"
|
||||
#endif
|
||||
|
||||
static void division_qr(unsigned n, unsigned p, struct qr *qr)
|
||||
{
|
||||
unsigned i = 1, q = 0;
|
||||
if (p == 0) {
|
||||
qr->r = 0xFFFFFFFF; /* division by 0 */
|
||||
return;
|
||||
}
|
||||
|
||||
while ((p >> 31) == 0) {
|
||||
i = i << 1; /* count the max division steps */
|
||||
p = p << 1; /* increase p until it has maximum size*/
|
||||
}
|
||||
|
||||
while (i > 0) {
|
||||
q = q << 1; /* write bit in q at index (size-1) */
|
||||
if (n >= p)
|
||||
{
|
||||
n -= p;
|
||||
q++;
|
||||
}
|
||||
p = p >> 1; /* decrease p */
|
||||
i = i >> 1; /* decrease remaining size in q */
|
||||
}
|
||||
qr->r = n;
|
||||
qr->q = q;
|
||||
}
|
||||
|
||||
static void uint_div_qr(unsigned numerator, unsigned denominator, struct qr *qr)
|
||||
{
|
||||
|
||||
division_qr(numerator, denominator, qr);
|
||||
|
||||
/* negate quotient and/or remainder according to requester */
|
||||
if (qr->q_n)
|
||||
qr->q = -qr->q;
|
||||
if (qr->r_n)
|
||||
qr->r = -qr->r;
|
||||
}
|
||||
|
||||
unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
|
||||
{
|
||||
struct qr qr = { .q_n = 0, .r_n = 0 };
|
||||
|
||||
uint_div_qr(numerator, denominator, &qr);
|
||||
|
||||
return qr.q;
|
||||
}
|
||||
|
||||
unsigned __aeabi_uidivmod(unsigned numerator, unsigned denominator)
|
||||
{
|
||||
struct qr qr = { .q_n = 0, .r_n = 0 };
|
||||
|
||||
uint_div_qr(numerator, denominator, &qr);
|
||||
|
||||
return ret_uidivmod_values(qr.q, qr.r);
|
||||
}
|
||||
|
||||
signed __aeabi_idiv(signed numerator, signed denominator)
|
||||
{
|
||||
struct qr qr = { .q_n = 0, .r_n = 0 };
|
||||
|
||||
if (((numerator < 0) && (denominator > 0)) ||
|
||||
((numerator > 0) && (denominator < 0)))
|
||||
qr.q_n = 1; /* quotient shall be negate */
|
||||
if (numerator < 0) {
|
||||
numerator = -numerator;
|
||||
qr.r_n = 1; /* remainder shall be negate */
|
||||
}
|
||||
if (denominator < 0)
|
||||
denominator = -denominator;
|
||||
|
||||
uint_div_qr(numerator, denominator, &qr);
|
||||
|
||||
return qr.q;
|
||||
}
|
||||
|
||||
signed __aeabi_idivmod(signed numerator, signed denominator)
|
||||
{
|
||||
struct qr qr = { .q_n = 0, .r_n = 0 };
|
||||
|
||||
if (((numerator < 0) && (denominator > 0)) ||
|
||||
((numerator > 0) && (denominator < 0)))
|
||||
qr.q_n = 1; /* quotient shall be negate */
|
||||
if (numerator < 0) {
|
||||
numerator = -numerator;
|
||||
qr.r_n = 1; /* remainder shall be negate */
|
||||
}
|
||||
if (denominator < 0)
|
||||
denominator = -denominator;
|
||||
|
||||
uint_div_qr(numerator, denominator, &qr);
|
||||
|
||||
return ret_idivmod_values(qr.q, qr.r);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*/
|
||||
|
||||
/*
|
||||
* signed ret_idivmod_values(signed quot, signed rem);
|
||||
* return quotient and remaining the EABI way (regs r0,r1)
|
||||
*/
|
||||
.section .text.ret_idivmod_values, "ax", %progbits
|
||||
.globl ret_idivmod_values
|
||||
.align 0
|
||||
.syntax unified
|
||||
ret_idivmod_values:
|
||||
bx lr
|
||||
.type ret_idivmod_values, %function
|
||||
.size ret_idivmod_values, .-ret_idivmod_values
|
||||
|
||||
/*
|
||||
* unsigned ret_uidivmod_values(unsigned quot, unsigned rem);
|
||||
* return quotient and remaining the EABI way (regs r0,r1)
|
||||
*/
|
||||
.section .text.ret_uidivmod_values, "ax", %progbits
|
||||
.globl ret_uidivmod_values
|
||||
.align 0
|
||||
.syntax unified
|
||||
ret_uidivmod_values:
|
||||
bx lr
|
||||
.type ret_uidivmod_values, %function
|
||||
.size ret_uidivmod_values, .-ret_uidivmod_values
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
|
||||
This file 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 3, or (at your option) any
|
||||
later version.
|
||||
This file 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.
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
.section .text.__gnu_thumb1_case_uqi, "ax", %progbits
|
||||
.globl __gnu_thumb1_case_uqi
|
||||
.align 0
|
||||
.thumb_func
|
||||
.syntax unified
|
||||
__gnu_thumb1_case_uqi:
|
||||
push {r1}
|
||||
mov r1, lr
|
||||
lsrs r1, r1, #1
|
||||
lsls r1, r1, #1
|
||||
ldrb r1, [r1, r0]
|
||||
lsls r1, r1, #1
|
||||
add lr, lr, r1
|
||||
pop {r1}
|
||||
bx lr
|
||||
.type __gnu_thumb1_case_uqi, %function
|
||||
.size __gnu_thumb1_case_uqi, .-__gnu_thumb1_case_uqi
|
||||
@@ -1,12 +1,14 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in common atmosphere configuration
|
||||
#---------------------------------------------------------------------------------
|
||||
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
include $(CURRENT_DIRECTORY)/../config/common.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
|
||||
PRECOMPILED_HEADERS := include/mesosphere.hpp
|
||||
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
|
||||
@@ -28,7 +30,7 @@ LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
ifneq ($(__RECURSIVE__),1)
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
|
||||
@@ -54,7 +56,7 @@ endif
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
|
||||
export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
@@ -62,41 +64,70 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I.
|
||||
|
||||
.PHONY: clean all
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ATMOSPHERE_BUILD_CONFIGS :=
|
||||
all: release
|
||||
|
||||
define ATMOSPHERE_ADD_TARGET
|
||||
|
||||
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
|
||||
|
||||
$(strip $1): $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2)
|
||||
|
||||
$$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) : $$(ATMOSPHERE_LIBRARY_DIR) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(SOURCES) $$(INCLUDES) $$(GCH_DIRS)
|
||||
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(CURDIR)/$$@ $(3) \
|
||||
ATMOSPHERE_GCH_IDENTIFIER="$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1)" \
|
||||
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
|
||||
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
|
||||
-f $$(THIS_MAKEFILE)
|
||||
|
||||
clean-$(strip $1):
|
||||
@echo clean $(strip $1) ...
|
||||
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2)
|
||||
@rm -fr $$(foreach hdr,$$(GCH_DIRS),$$(hdr)/$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1))
|
||||
@for i in $$(GCH_DIRS) $$(ATMOSPHERE_BUILD_DIR) $$(ATMOSPHERE_LIBRARY_DIR); do [ -d $$$$i ] && rmdir --ignore-fail-on-non-empty $$$$i || true; done
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, release, $(TARGET).a, \
|
||||
ATMOSPHERE_BUILD_SETTINGS="" \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, $(TARGET)_debug.a, \
|
||||
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \
|
||||
))
|
||||
|
||||
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, $(TARGET)_audit.a, \
|
||||
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
|
||||
))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: lib/$(TARGET).a
|
||||
|
||||
lib:
|
||||
-include $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME).mk
|
||||
|
||||
ALL_GCH_IDENTIFIERS := $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(config))
|
||||
ALL_GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(foreach id,$(ALL_GCH_IDENTIFIERS),$(hdr)/$(id)))
|
||||
|
||||
.PHONY: clean all $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
|
||||
|
||||
$(ATMOSPHERE_LIBRARY_DIR) $(GCH_DIRS):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
release:
|
||||
$(ATMOSPHERE_BUILD_DIR)/%:
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
|
||||
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
|
||||
|
||||
dist-bin: all
|
||||
@tar --exclude=*~ -cjf $(TARGET).tar.bz2 include lib
|
||||
|
||||
dist-src:
|
||||
@tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source Makefile
|
||||
|
||||
dist: dist-src dist-bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr release lib *.bz2
|
||||
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2 $(ALL_GCH_FILES)
|
||||
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
|
||||
GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
|
||||
DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr)))))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
#include "kern_mc_registers.hpp"
|
||||
|
||||
#if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) || defined(MESOSPHERE_BUILD_FOR_AUDITING)
|
||||
#define MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT
|
||||
|
||||
@@ -78,13 +78,11 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
void WaitOtherCpuPowerOff() {
|
||||
constexpr u64 PmcPhysicalAddress = 0x7000E400;
|
||||
constexpr u64 APBDEV_PMC_PWRGATE_STATUS = PmcPhysicalAddress + 0x38;
|
||||
|
||||
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
|
||||
|
||||
u32 value;
|
||||
do {
|
||||
bool res = smc::ReadWriteRegister(std::addressof(value), APBDEV_PMC_PWRGATE_STATUS, 0, 0);
|
||||
bool res = smc::ReadWriteRegister(std::addressof(value), PmcPhysicalAddress + APBDEV_PMC_PWRGATE_STATUS, 0, 0);
|
||||
MESOSPHERE_ASSERT(res);
|
||||
} while ((value & PWRGATE_STATUS_CE123_MASK) != 0);
|
||||
}
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
|
||||
#include "kern_bpmp_api.hpp"
|
||||
#include "kern_atomics_registers.hpp"
|
||||
#include "kern_clkrst_registers.hpp"
|
||||
#include "kern_evp_registers.hpp"
|
||||
#include "kern_flow_registers.hpp"
|
||||
#include "kern_ictlr_registers.hpp"
|
||||
#include "kern_pmc_registers.hpp"
|
||||
#include "kern_sema_registers.hpp"
|
||||
|
||||
namespace ams::kern::board::nintendo::nx::lps {
|
||||
|
||||
@@ -1,526 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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
|
||||
|
||||
#define MC_INTSTATUS 0x0
|
||||
#define MC_INTMASK 0x4
|
||||
#define MC_ERR_STATUS 0x8
|
||||
#define MC_ERR_ADR 0xc
|
||||
#define MC_SMMU_CONFIG 0x10
|
||||
#define MC_SMMU_TLB_CONFIG 0x14
|
||||
#define MC_SMMU_PTC_CONFIG 0x18
|
||||
#define MC_SMMU_PTB_ASID 0x1c
|
||||
#define MC_SMMU_PTB_DATA 0x20
|
||||
#define MC_SMMU_TLB_FLUSH 0x30
|
||||
#define MC_SMMU_PTC_FLUSH_0 0x34
|
||||
#define MC_SMMU_PTC_FLUSH_1 0x9b8
|
||||
#define MC_SMMU_ASID_SECURITY 0x38
|
||||
#define MC_SMMU_ASID_SECURITY_1 0x3c
|
||||
#define MC_SMMU_ASID_SECURITY_2 0x9e0
|
||||
#define MC_SMMU_ASID_SECURITY_3 0x9e4
|
||||
#define MC_SMMU_ASID_SECURITY_4 0x9e8
|
||||
#define MC_SMMU_ASID_SECURITY_5 0x9ec
|
||||
#define MC_SMMU_ASID_SECURITY_6 0x9f0
|
||||
#define MC_SMMU_ASID_SECURITY_7 0x9f4
|
||||
#define MC_SMMU_AFI_ASID 0x238
|
||||
#define MC_SMMU_AVPC_ASID 0x23c
|
||||
#define MC_SMMU_DC_ASID 0x240
|
||||
#define MC_SMMU_DCB_ASID 0x244
|
||||
#define MC_SMMU_HC_ASID 0x250
|
||||
#define MC_SMMU_HDA_ASID 0x254
|
||||
#define MC_SMMU_ISP2_ASID 0x258
|
||||
#define MC_SMMU_MSENC_NVENC_ASID 0x264
|
||||
#define MC_SMMU_NV_ASID 0x268
|
||||
#define MC_SMMU_NV2_ASID 0x26c
|
||||
#define MC_SMMU_PPCS_ASID 0x270
|
||||
#define MC_SMMU_SATA_ASID 0x274
|
||||
#define MC_SMMU_VDE_ASID 0x27c
|
||||
#define MC_SMMU_VI_ASID 0x280
|
||||
#define MC_SMMU_VIC_ASID 0x284
|
||||
#define MC_SMMU_XUSB_HOST_ASID 0x288
|
||||
#define MC_SMMU_XUSB_DEV_ASID 0x28c
|
||||
#define MC_SMMU_TSEC_ASID 0x294
|
||||
#define MC_SMMU_PPCS1_ASID 0x298
|
||||
#define MC_SMMU_DC1_ASID 0xa88
|
||||
#define MC_SMMU_SDMMC1A_ASID 0xa94
|
||||
#define MC_SMMU_SDMMC2A_ASID 0xa98
|
||||
#define MC_SMMU_SDMMC3A_ASID 0xa9c
|
||||
#define MC_SMMU_SDMMC4A_ASID 0xaa0
|
||||
#define MC_SMMU_ISP2B_ASID 0xaa4
|
||||
#define MC_SMMU_GPU_ASID 0xaa8
|
||||
#define MC_SMMU_GPUB_ASID 0xaac
|
||||
#define MC_SMMU_PPCS2_ASID 0xab0
|
||||
#define MC_SMMU_NVDEC_ASID 0xab4
|
||||
#define MC_SMMU_APE_ASID 0xab8
|
||||
#define MC_SMMU_SE_ASID 0xabc
|
||||
#define MC_SMMU_NVJPG_ASID 0xac0
|
||||
#define MC_SMMU_HC1_ASID 0xac4
|
||||
#define MC_SMMU_SE1_ASID 0xac8
|
||||
#define MC_SMMU_AXIAP_ASID 0xacc
|
||||
#define MC_SMMU_ETR_ASID 0xad0
|
||||
#define MC_SMMU_TSECB_ASID 0xad4
|
||||
#define MC_SMMU_TSEC1_ASID 0xad8
|
||||
#define MC_SMMU_TSECB1_ASID 0xadc
|
||||
#define MC_SMMU_NVDEC1_ASID 0xae0
|
||||
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
|
||||
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
|
||||
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
|
||||
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
|
||||
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
|
||||
#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0
|
||||
#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4
|
||||
#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8
|
||||
#define MC_PCFIFO_CLIENT_CONFIG3 0xddc
|
||||
#define MC_PCFIFO_CLIENT_CONFIG4 0xde0
|
||||
#define MC_EMEM_CFG 0x50
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#define MC_EMEM_ADR_CFG_DEV0 0x58
|
||||
#define MC_EMEM_ADR_CFG_DEV1 0x5c
|
||||
#define MC_EMEM_ADR_CFG_CHANNEL_MASK 0x60
|
||||
#define MC_EMEM_ADR_CFG_BANK_MASK_0 0x64
|
||||
#define MC_EMEM_ADR_CFG_BANK_MASK_1 0x68
|
||||
#define MC_EMEM_ADR_CFG_BANK_MASK_2 0x6c
|
||||
#define MC_SECURITY_CFG0 0x70
|
||||
#define MC_SECURITY_CFG1 0x74
|
||||
#define MC_SECURITY_CFG3 0x9bc
|
||||
#define MC_SECURITY_RSV 0x7c
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
||||
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
||||
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
||||
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
||||
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
||||
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
||||
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
||||
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
||||
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
||||
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
||||
#define MC_EMEM_ARB_TIMING_W2W 0xbc
|
||||
#define MC_EMEM_ARB_TIMING_R2W 0xc0
|
||||
#define MC_EMEM_ARB_TIMING_W2R 0xc4
|
||||
#define MC_EMEM_ARB_TIMING_RFCPB 0x6c0
|
||||
#define MC_EMEM_ARB_TIMING_CCDMW 0x6c4
|
||||
#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6f0
|
||||
#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6f4
|
||||
#define MC_EMEM_ARB_DA_TURNS 0xd0
|
||||
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
||||
#define MC_EMEM_ARB_MISC0 0xd8
|
||||
#define MC_EMEM_ARB_MISC1 0xdc
|
||||
#define MC_EMEM_ARB_MISC2 0xc8
|
||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||
#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
|
||||
#define MC_EMEM_ARB_NISO_THROTTLE 0x6b0
|
||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
||||
#define MC_EMEM_ARB_RSV 0xec
|
||||
#define MC_CLKEN_OVERRIDE 0xf4
|
||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
||||
#define MC_TIMING_CONTROL 0xfc
|
||||
#define MC_STAT_CONTROL 0x100
|
||||
#define MC_STAT_STATUS 0x104
|
||||
#define MC_STAT_EMC_CLOCK_LIMIT 0x108
|
||||
#define MC_STAT_EMC_CLOCK_LIMIT_MSBS 0x10c
|
||||
#define MC_STAT_EMC_CLOCKS 0x110
|
||||
#define MC_STAT_EMC_CLOCKS_MSBS 0x114
|
||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO 0x118
|
||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO 0x158
|
||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI 0x11c
|
||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI 0x15c
|
||||
#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER 0xa20
|
||||
#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER 0xa24
|
||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO 0x198
|
||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO 0x1a8
|
||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI 0x19c
|
||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI 0x1ac
|
||||
#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER 0xa28
|
||||
#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER 0xa2c
|
||||
#define MC_STAT_EMC_FILTER_SET0_ASID 0x1a0
|
||||
#define MC_STAT_EMC_FILTER_SET1_ASID 0x1b0
|
||||
#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT 0x120
|
||||
#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT 0x160
|
||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_0 0x128
|
||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_0 0x168
|
||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_1 0x12c
|
||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_1 0x16c
|
||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_2 0x130
|
||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_2 0x170
|
||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_3 0x134
|
||||
#define MC_STAT_EMC_FILTER_SET0_CLIENT_4 0xb88
|
||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_3 0x174
|
||||
#define MC_STAT_EMC_FILTER_SET1_CLIENT_4 0xb8c
|
||||
#define MC_STAT_EMC_SET0_COUNT 0x138
|
||||
#define MC_STAT_EMC_SET0_COUNT_MSBS 0x13c
|
||||
#define MC_STAT_EMC_SET1_COUNT 0x178
|
||||
#define MC_STAT_EMC_SET1_COUNT_MSBS 0x17c
|
||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM 0x140
|
||||
#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS 0x144
|
||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM 0x180
|
||||
#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS 0x184
|
||||
#define MC_STAT_EMC_SET0_HISTO_COUNT 0x148
|
||||
#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS 0x14c
|
||||
#define MC_STAT_EMC_SET1_HISTO_COUNT 0x188
|
||||
#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS 0x18c
|
||||
#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED 0x150
|
||||
#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED 0x190
|
||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT 0x1b8
|
||||
#define MC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS 0x1bc
|
||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT 0x1c8
|
||||
#define MC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS 0x1cc
|
||||
#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT 0x1c0
|
||||
#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT 0x1d0
|
||||
#define MC_CLIENT_HOTRESET_CTRL 0x200
|
||||
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
|
||||
#define MC_CLIENT_HOTRESET_STATUS 0x204
|
||||
#define MC_CLIENT_HOTRESET_STATUS_1 0x974
|
||||
#define MC_EMEM_ARB_ISOCHRONOUS_0 0x208
|
||||
#define MC_EMEM_ARB_ISOCHRONOUS_1 0x20c
|
||||
#define MC_EMEM_ARB_ISOCHRONOUS_2 0x210
|
||||
#define MC_EMEM_ARB_ISOCHRONOUS_3 0x214
|
||||
#define MC_EMEM_ARB_ISOCHRONOUS_4 0xb94
|
||||
#define MC_EMEM_ARB_HYSTERESIS_0 0x218
|
||||
#define MC_EMEM_ARB_HYSTERESIS_1 0x21c
|
||||
#define MC_EMEM_ARB_HYSTERESIS_2 0x220
|
||||
#define MC_EMEM_ARB_HYSTERESIS_3 0x224
|
||||
#define MC_EMEM_ARB_HYSTERESIS_4 0xb84
|
||||
#define MC_EMEM_ARB_DHYSTERESIS_0 0xbb0
|
||||
#define MC_EMEM_ARB_DHYSTERESIS_1 0xbb4
|
||||
#define MC_EMEM_ARB_DHYSTERESIS_2 0xbb8
|
||||
#define MC_EMEM_ARB_DHYSTERESIS_3 0xbbc
|
||||
#define MC_EMEM_ARB_DHYSTERESIS_4 0xbc0
|
||||
#define MC_EMEM_ARB_DHYST_CTRL 0xbcc
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xbd0
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xbd4
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xbd8
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xbdc
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xbe0
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xbe4
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xbe8
|
||||
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xbec
|
||||
#define MC_RESERVED_RSV 0x3fc
|
||||
#define MC_DISB_EXTRA_SNAP_LEVELS 0x408
|
||||
#define MC_APB_EXTRA_SNAP_LEVELS 0x2a4
|
||||
#define MC_AHB_EXTRA_SNAP_LEVELS 0x2a0
|
||||
#define MC_USBD_EXTRA_SNAP_LEVELS 0xa18
|
||||
#define MC_ISP_EXTRA_SNAP_LEVELS 0xa08
|
||||
#define MC_AUD_EXTRA_SNAP_LEVELS 0xa10
|
||||
#define MC_MSE_EXTRA_SNAP_LEVELS 0x40c
|
||||
#define MC_GK2_EXTRA_SNAP_LEVELS 0xa40
|
||||
#define MC_A9AVPPC_EXTRA_SNAP_LEVELS 0x414
|
||||
#define MC_FTOP_EXTRA_SNAP_LEVELS 0x2bc
|
||||
#define MC_JPG_EXTRA_SNAP_LEVELS 0xa3c
|
||||
#define MC_HOST_EXTRA_SNAP_LEVELS 0xa14
|
||||
#define MC_SAX_EXTRA_SNAP_LEVELS 0x2c0
|
||||
#define MC_DIS_EXTRA_SNAP_LEVELS 0x2ac
|
||||
#define MC_VICPC_EXTRA_SNAP_LEVELS 0xa1c
|
||||
#define MC_HDAPC_EXTRA_SNAP_LEVELS 0xa48
|
||||
#define MC_AVP_EXTRA_SNAP_LEVELS 0x2a8
|
||||
#define MC_USBX_EXTRA_SNAP_LEVELS 0x404
|
||||
#define MC_PCX_EXTRA_SNAP_LEVELS 0x2b8
|
||||
#define MC_SD_EXTRA_SNAP_LEVELS 0xa04
|
||||
#define MC_DFD_EXTRA_SNAP_LEVELS 0xa4c
|
||||
#define MC_VE_EXTRA_SNAP_LEVELS 0x2d8
|
||||
#define MC_GK_EXTRA_SNAP_LEVELS 0xa00
|
||||
#define MC_VE2_EXTRA_SNAP_LEVELS 0x410
|
||||
#define MC_SDM_EXTRA_SNAP_LEVELS 0xa44
|
||||
#define MC_VIDEO_PROTECT_BOM 0x648
|
||||
#define MC_VIDEO_PROTECT_SIZE_MB 0x64c
|
||||
#define MC_VIDEO_PROTECT_BOM_ADR_HI 0x978
|
||||
#define MC_VIDEO_PROTECT_REG_CTRL 0x650
|
||||
#define MC_ERR_VPR_STATUS 0x654
|
||||
#define MC_ERR_VPR_ADR 0x658
|
||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE 0x418
|
||||
#define MC_VIDEO_PROTECT_VPR_OVERRIDE1 0x590
|
||||
#define MC_IRAM_BOM 0x65c
|
||||
#define MC_IRAM_TOM 0x660
|
||||
#define MC_IRAM_ADR_HI 0x980
|
||||
#define MC_IRAM_REG_CTRL 0x964
|
||||
#define MC_EMEM_CFG_ACCESS_CTRL 0x664
|
||||
#define MC_TZ_SECURITY_CTRL 0x668
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3 0x66c
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO 0x6b4
|
||||
#define MC_EMEM_ARB_RING0_THROTTLE_MASK 0x6bc
|
||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK 0x6b8
|
||||
#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1 0xb80
|
||||
#define MC_SEC_CARVEOUT_BOM 0x670
|
||||
#define MC_SEC_CARVEOUT_SIZE_MB 0x674
|
||||
#define MC_SEC_CARVEOUT_ADR_HI 0x9d4
|
||||
#define MC_SEC_CARVEOUT_REG_CTRL 0x678
|
||||
#define MC_ERR_SEC_STATUS 0x67c
|
||||
#define MC_ERR_SEC_ADR 0x680
|
||||
#define MC_PC_IDLE_CLOCK_GATE_CONFIG 0x684
|
||||
#define MC_STUTTER_CONTROL 0x688
|
||||
#define MC_RESERVED_RSV_1 0x958
|
||||
#define MC_DVFS_PIPE_SELECT 0x95c
|
||||
#define MC_AHB_PTSA_MIN 0x4e0
|
||||
#define MC_AUD_PTSA_MIN 0x54c
|
||||
#define MC_MLL_MPCORER_PTSA_RATE 0x44c
|
||||
#define MC_RING2_PTSA_RATE 0x440
|
||||
#define MC_USBD_PTSA_RATE 0x530
|
||||
#define MC_USBX_PTSA_MIN 0x528
|
||||
#define MC_USBD_PTSA_MIN 0x534
|
||||
#define MC_APB_PTSA_MAX 0x4f0
|
||||
#define MC_JPG_PTSA_RATE 0x584
|
||||
#define MC_DIS_PTSA_MIN 0x420
|
||||
#define MC_AVP_PTSA_MAX 0x4fc
|
||||
#define MC_AVP_PTSA_RATE 0x4f4
|
||||
#define MC_RING1_PTSA_MIN 0x480
|
||||
#define MC_DIS_PTSA_MAX 0x424
|
||||
#define MC_SD_PTSA_MAX 0x4d8
|
||||
#define MC_MSE_PTSA_RATE 0x4c4
|
||||
#define MC_VICPC_PTSA_MIN 0x558
|
||||
#define MC_PCX_PTSA_MAX 0x4b4
|
||||
#define MC_ISP_PTSA_RATE 0x4a0
|
||||
#define MC_A9AVPPC_PTSA_MIN 0x48c
|
||||
#define MC_RING2_PTSA_MAX 0x448
|
||||
#define MC_AUD_PTSA_RATE 0x548
|
||||
#define MC_HOST_PTSA_MIN 0x51c
|
||||
#define MC_MLL_MPCORER_PTSA_MAX 0x454
|
||||
#define MC_SD_PTSA_MIN 0x4d4
|
||||
#define MC_RING1_PTSA_RATE 0x47c
|
||||
#define MC_JPG_PTSA_MIN 0x588
|
||||
#define MC_HDAPC_PTSA_MIN 0x62c
|
||||
#define MC_AVP_PTSA_MIN 0x4f8
|
||||
#define MC_JPG_PTSA_MAX 0x58c
|
||||
#define MC_VE_PTSA_MAX 0x43c
|
||||
#define MC_DFD_PTSA_MAX 0x63c
|
||||
#define MC_VICPC_PTSA_RATE 0x554
|
||||
#define MC_GK_PTSA_MAX 0x544
|
||||
#define MC_VICPC_PTSA_MAX 0x55c
|
||||
#define MC_SDM_PTSA_MAX 0x624
|
||||
#define MC_SAX_PTSA_RATE 0x4b8
|
||||
#define MC_PCX_PTSA_MIN 0x4b0
|
||||
#define MC_APB_PTSA_MIN 0x4ec
|
||||
#define MC_GK2_PTSA_MIN 0x614
|
||||
#define MC_PCX_PTSA_RATE 0x4ac
|
||||
#define MC_RING1_PTSA_MAX 0x484
|
||||
#define MC_HDAPC_PTSA_RATE 0x628
|
||||
#define MC_MLL_MPCORER_PTSA_MIN 0x450
|
||||
#define MC_GK2_PTSA_MAX 0x618
|
||||
#define MC_AUD_PTSA_MAX 0x550
|
||||
#define MC_GK2_PTSA_RATE 0x610
|
||||
#define MC_ISP_PTSA_MAX 0x4a8
|
||||
#define MC_DISB_PTSA_RATE 0x428
|
||||
#define MC_VE2_PTSA_MAX 0x49c
|
||||
#define MC_DFD_PTSA_MIN 0x638
|
||||
#define MC_FTOP_PTSA_RATE 0x50c
|
||||
#define MC_A9AVPPC_PTSA_RATE 0x488
|
||||
#define MC_VE2_PTSA_MIN 0x498
|
||||
#define MC_USBX_PTSA_MAX 0x52c
|
||||
#define MC_DIS_PTSA_RATE 0x41c
|
||||
#define MC_USBD_PTSA_MAX 0x538
|
||||
#define MC_A9AVPPC_PTSA_MAX 0x490
|
||||
#define MC_USBX_PTSA_RATE 0x524
|
||||
#define MC_FTOP_PTSA_MAX 0x514
|
||||
#define MC_HDAPC_PTSA_MAX 0x630
|
||||
#define MC_SD_PTSA_RATE 0x4d0
|
||||
#define MC_DFD_PTSA_RATE 0x634
|
||||
#define MC_FTOP_PTSA_MIN 0x510
|
||||
#define MC_SDM_PTSA_RATE 0x61c
|
||||
#define MC_AHB_PTSA_RATE 0x4dc
|
||||
#define MC_SMMU_SMMU_PTSA_MAX 0x460
|
||||
#define MC_RING2_PTSA_MIN 0x444
|
||||
#define MC_SDM_PTSA_MIN 0x620
|
||||
#define MC_APB_PTSA_RATE 0x4e8
|
||||
#define MC_MSE_PTSA_MIN 0x4c8
|
||||
#define MC_HOST_PTSA_RATE 0x518
|
||||
#define MC_VE_PTSA_RATE 0x434
|
||||
#define MC_AHB_PTSA_MAX 0x4e4
|
||||
#define MC_SAX_PTSA_MIN 0x4bc
|
||||
#define MC_SMMU_SMMU_PTSA_MIN 0x45c
|
||||
#define MC_ISP_PTSA_MIN 0x4a4
|
||||
#define MC_HOST_PTSA_MAX 0x520
|
||||
#define MC_SAX_PTSA_MAX 0x4c0
|
||||
#define MC_VE_PTSA_MIN 0x438
|
||||
#define MC_GK_PTSA_MIN 0x540
|
||||
#define MC_MSE_PTSA_MAX 0x4cc
|
||||
#define MC_DISB_PTSA_MAX 0x430
|
||||
#define MC_DISB_PTSA_MIN 0x42c
|
||||
#define MC_SMMU_SMMU_PTSA_RATE 0x458
|
||||
#define MC_VE2_PTSA_RATE 0x494
|
||||
#define MC_GK_PTSA_RATE 0x53c
|
||||
#define MC_PTSA_GRANT_DECREMENT 0x960
|
||||
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2e4
|
||||
#define MC_LATENCY_ALLOWANCE_AXIAP_0 0x3a0
|
||||
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2B_0 0x384
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3bc
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3b8
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
|
||||
#define MC_LATENCY_ALLOWANCE_SE_0 0x3e0
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
|
||||
#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8
|
||||
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
|
||||
#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8
|
||||
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3d8
|
||||
#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc
|
||||
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
|
||||
#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB 0x694
|
||||
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
|
||||
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37c
|
||||
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
|
||||
#define MC_LATENCY_ALLOWANCE_TSECB_0 0x3f0
|
||||
#define MC_LATENCY_ALLOWANCE_AFI_0 0x2e0
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B 0x698
|
||||
#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec
|
||||
#define MC_LATENCY_ALLOWANCE_APE_0 0x3dc
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C 0x6a0
|
||||
#define MC_LATENCY_ALLOWANCE_A9AVP_0 0x3a4
|
||||
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3e8
|
||||
#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4
|
||||
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3c0
|
||||
#define MC_LATENCY_ALLOWANCE_NVJPG_0 0x3e4
|
||||
#define MC_LATENCY_ALLOWANCE_PTC_0 0x34c
|
||||
#define MC_LATENCY_ALLOWANCE_ETR_0 0x3ec
|
||||
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
|
||||
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB 0x69c
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB 0x6a4
|
||||
#define MC_LATENCY_ALLOWANCE_SATA_0 0x350
|
||||
#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A 0x690
|
||||
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
|
||||
#define MC_LATENCY_ALLOWANCE_DC_3 0x3c8
|
||||
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3ac
|
||||
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3c4
|
||||
#define MC_LATENCY_ALLOWANCE_ISP2B_1 0x388
|
||||
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
|
||||
#define MC_LATENCY_ALLOWANCE_HDA_0 0x318
|
||||
#define MC_MIN_LENGTH_APE_0 0xb34
|
||||
#define MC_MIN_LENGTH_DCB_2 0x8a8
|
||||
#define MC_MIN_LENGTH_A9AVP_0 0x950
|
||||
#define MC_MIN_LENGTH_TSEC_0 0x93c
|
||||
#define MC_MIN_LENGTH_DC_1 0x898
|
||||
#define MC_MIN_LENGTH_AXIAP_0 0x94c
|
||||
#define MC_MIN_LENGTH_ISP2B_0 0x930
|
||||
#define MC_MIN_LENGTH_VI2_0 0x944
|
||||
#define MC_MIN_LENGTH_DCB_0 0x8a0
|
||||
#define MC_MIN_LENGTH_DCB_1 0x8a4
|
||||
#define MC_MIN_LENGTH_PPCS_1 0x8f4
|
||||
#define MC_MIN_LENGTH_NVJPG_0 0xb3c
|
||||
#define MC_MIN_LENGTH_HDA_0 0x8c4
|
||||
#define MC_MIN_LENGTH_NVENC_0 0x8d4
|
||||
#define MC_MIN_LENGTH_SDMMC_0 0xb18
|
||||
#define MC_MIN_LENGTH_ISP2B_1 0x934
|
||||
#define MC_MIN_LENGTH_HC_1 0x8c0
|
||||
#define MC_MIN_LENGTH_DC_3 0xb20
|
||||
#define MC_MIN_LENGTH_AVPC_0 0x890
|
||||
#define MC_MIN_LENGTH_VIC_0 0x940
|
||||
#define MC_MIN_LENGTH_ISP2_0 0x91c
|
||||
#define MC_MIN_LENGTH_HC_0 0x8bc
|
||||
#define MC_MIN_LENGTH_SE_0 0xb38
|
||||
#define MC_MIN_LENGTH_NVDEC_0 0xb30
|
||||
#define MC_MIN_LENGTH_SATA_0 0x8fc
|
||||
#define MC_MIN_LENGTH_DC_0 0x894
|
||||
#define MC_MIN_LENGTH_XUSB_1 0x92c
|
||||
#define MC_MIN_LENGTH_DC_2 0x89c
|
||||
#define MC_MIN_LENGTH_SDMMCAA_0 0xb14
|
||||
#define MC_MIN_LENGTH_GPU_0 0xb04
|
||||
#define MC_MIN_LENGTH_ETR_0 0xb44
|
||||
#define MC_MIN_LENGTH_AFI_0 0x88c
|
||||
#define MC_MIN_LENGTH_PPCS_0 0x8f0
|
||||
#define MC_MIN_LENGTH_ISP2_1 0x920
|
||||
#define MC_MIN_LENGTH_XUSB_0 0x928
|
||||
#define MC_MIN_LENGTH_MPCORE_0 0x8cc
|
||||
#define MC_MIN_LENGTH_TSECB_0 0xb48
|
||||
#define MC_MIN_LENGTH_SDMMCA_0 0xb10
|
||||
#define MC_MIN_LENGTH_GPU2_0 0xb40
|
||||
#define MC_MIN_LENGTH_SDMMCAB_0 0xb1c
|
||||
#define MC_MIN_LENGTH_PTC_0 0x8f8
|
||||
#define MC_EMEM_ARB_OVERRIDE_1 0x968
|
||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0 0x984
|
||||
#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1 0x988
|
||||
#define MC_EMEM_ARB_STATS_0 0x990
|
||||
#define MC_EMEM_ARB_STATS_1 0x994
|
||||
#define MC_MTS_CARVEOUT_BOM 0x9a0
|
||||
#define MC_MTS_CARVEOUT_SIZE_MB 0x9a4
|
||||
#define MC_MTS_CARVEOUT_ADR_HI 0x9a8
|
||||
#define MC_MTS_CARVEOUT_REG_CTRL 0x9ac
|
||||
#define MC_ERR_MTS_STATUS 0x9b0
|
||||
#define MC_ERR_MTS_ADR 0x9b4
|
||||
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
|
||||
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xd74
|
||||
#define MC_SECURITY_CARVEOUT4_CFG0 0xcf8
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 0xd10
|
||||
#define MC_SECURITY_CARVEOUT4_SIZE_128KB 0xd04
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 0xc28
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xc30
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xc8c
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xd1c
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xd70
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xc2c
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xd7c
|
||||
#define MC_SECURITY_CARVEOUT3_SIZE_128KB 0xcb4
|
||||
#define MC_SECURITY_CARVEOUT2_CFG0 0xc58
|
||||
#define MC_SECURITY_CARVEOUT1_CFG0 0xc08
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xc84
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 0xc68
|
||||
#define MC_SECURITY_CARVEOUT3_BOM 0xcac
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 0xc70
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xd78
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xc7c
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 0xd18
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 0xcbc
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xc38
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xc34
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 0xcc0
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 0xd60
|
||||
#define MC_SECURITY_CARVEOUT3_CFG0 0xca8
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 0xcb8
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xc88
|
||||
#define MC_SECURITY_CARVEOUT2_SIZE_128KB 0xc64
|
||||
#define MC_SECURITY_CARVEOUT5_BOM_HI 0xd50
|
||||
#define MC_SECURITY_CARVEOUT1_SIZE_128KB 0xc14
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 0xd14
|
||||
#define MC_SECURITY_CARVEOUT1_BOM 0xc0c
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xd2c
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 0xd68
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 0xcc8
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 0xd58
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xd24
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 0xcc4
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 0xc78
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 0xc1c
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 0xc18
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xd28
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 0xd5c
|
||||
#define MC_SECURITY_CARVEOUT3_BOM_HI 0xcb0
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xcd8
|
||||
#define MC_SECURITY_CARVEOUT2_BOM_HI 0xc60
|
||||
#define MC_SECURITY_CARVEOUT4_BOM_HI 0xd00
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 0xd64
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xcdc
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xc80
|
||||
#define MC_SECURITY_CARVEOUT5_SIZE_128KB 0xd54
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xd20
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xcd4
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 0xd0c
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 0xc74
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xccc
|
||||
#define MC_SECURITY_CARVEOUT4_BOM 0xcfc
|
||||
#define MC_SECURITY_CARVEOUT5_CFG0 0xd48
|
||||
#define MC_SECURITY_CARVEOUT2_BOM 0xc5c
|
||||
#define MC_SECURITY_CARVEOUT5_BOM 0xd4c
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 0xc24
|
||||
#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xd6c
|
||||
#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xcd0
|
||||
#define MC_SECURITY_CARVEOUT1_BOM_HI 0xc10
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 0xc20
|
||||
#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xc3c
|
||||
#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 0xc6c
|
||||
#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 0xd08
|
||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
||||
#define MC_DA_CONFIG0 0x9dc
|
||||
@@ -17,386 +17,9 @@
|
||||
#include "kern_debug_log_impl.hpp"
|
||||
|
||||
namespace ams::kern {
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-Os")
|
||||
|
||||
namespace {
|
||||
|
||||
/* Useful definitions for our VSNPrintf implementation. */
|
||||
enum FormatSpecifierFlag : u32 {
|
||||
FormatSpecifierFlag_None = 0,
|
||||
FormatSpecifierFlag_EmptySign = (1 << 0),
|
||||
FormatSpecifierFlag_ForceSign = (1 << 1),
|
||||
FormatSpecifierFlag_Hash = (1 << 2),
|
||||
FormatSpecifierFlag_LeftJustify = (1 << 3),
|
||||
FormatSpecifierFlag_ZeroPad = (1 << 4),
|
||||
FormatSpecifierFlag_Char = (1 << 5),
|
||||
FormatSpecifierFlag_Short = (1 << 6),
|
||||
FormatSpecifierFlag_Long = (1 << 7),
|
||||
FormatSpecifierFlag_LongLong = (1 << 8),
|
||||
FormatSpecifierFlag_Uppercase = (1 << 9),
|
||||
FormatSpecifierFlag_HasPrecision = (1 << 10),
|
||||
};
|
||||
|
||||
using FormatSpecifierFlagStorage = std::underlying_type<FormatSpecifierFlag>::type;
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsDigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u32 ParseU32(const char *&str) {
|
||||
u32 value = 0;
|
||||
do {
|
||||
value = (value * 10) + static_cast<u32>(*(str++) - '0');
|
||||
} while (IsDigit(*str));
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE size_t Strnlen(const char *str, size_t max) {
|
||||
const char *cur = str;
|
||||
while (*cur && max--) {
|
||||
cur++;
|
||||
}
|
||||
return static_cast<size_t>(cur - str);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void VSNPrintfImpl(char * const dst, const size_t dst_size, const char *format, ::std::va_list vl) {
|
||||
size_t dst_index = 0;
|
||||
|
||||
auto WriteCharacter = [dst, dst_size, &dst_index](char c) ALWAYS_INLINE_LAMBDA {
|
||||
if (dst_index < dst_size) {
|
||||
dst[dst_index++] = c;
|
||||
}
|
||||
};
|
||||
|
||||
/* Loop over every character in the string, looking for format specifiers. */
|
||||
while (*format) {
|
||||
if (const char c = *(format++); c != '%') {
|
||||
WriteCharacter(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have to parse a format specifier. */
|
||||
/* Start by parsing flags. */
|
||||
FormatSpecifierFlagStorage flags = FormatSpecifierFlag_None;
|
||||
auto SetFlag = [&flags](FormatSpecifierFlag f) ALWAYS_INLINE_LAMBDA { flags |= f; };
|
||||
auto ClearFlag = [&flags](FormatSpecifierFlag f) ALWAYS_INLINE_LAMBDA { flags &= ~f; };
|
||||
auto HasFlag = [&flags](FormatSpecifierFlag f) ALWAYS_INLINE_LAMBDA { return (flags & f) != 0; };
|
||||
{
|
||||
bool parsed_flags = false;
|
||||
while (!parsed_flags) {
|
||||
switch (*format) {
|
||||
case ' ': SetFlag(FormatSpecifierFlag_EmptySign); format++; break;
|
||||
case '+': SetFlag(FormatSpecifierFlag_ForceSign); format++; break;
|
||||
case '#': SetFlag(FormatSpecifierFlag_Hash); format++; break;
|
||||
case '-': SetFlag(FormatSpecifierFlag_LeftJustify); format++; break;
|
||||
case '0': SetFlag(FormatSpecifierFlag_ZeroPad); format++; break;
|
||||
default:
|
||||
parsed_flags = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Next, parse width. */
|
||||
u32 width = 0;
|
||||
if (IsDigit(*format)) {
|
||||
/* Integer width. */
|
||||
width = ParseU32(format);
|
||||
} else if (*format == '*') {
|
||||
/* Dynamic width. */
|
||||
const int _width = va_arg(vl, int);
|
||||
if (_width >= 0) {
|
||||
width = static_cast<u32>(_width);
|
||||
} else {
|
||||
SetFlag(FormatSpecifierFlag_LeftJustify);
|
||||
width = static_cast<u32>(-_width);
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
/* Next, parse precision if present. */
|
||||
u32 precision = 0;
|
||||
if (*format == '.') {
|
||||
SetFlag(FormatSpecifierFlag_HasPrecision);
|
||||
format++;
|
||||
|
||||
if (IsDigit(*format)) {
|
||||
/* Integer precision. */
|
||||
precision = ParseU32(format);
|
||||
} else if (*format == '*') {
|
||||
/* Dynamic precision. */
|
||||
const int _precision = va_arg(vl, int);
|
||||
if (_precision > 0) {
|
||||
precision = static_cast<u32>(_precision);
|
||||
}
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse length. */
|
||||
constexpr bool SizeIsLong = sizeof(size_t) == sizeof(long);
|
||||
constexpr bool IntMaxIsLong = sizeof(intmax_t) == sizeof(long);
|
||||
constexpr bool PtrDiffIsLong = sizeof(ptrdiff_t) == sizeof(long);
|
||||
switch (*format) {
|
||||
case 'z':
|
||||
SetFlag(SizeIsLong ? FormatSpecifierFlag_Long : FormatSpecifierFlag_LongLong);
|
||||
format++;
|
||||
break;
|
||||
case 'j':
|
||||
SetFlag(IntMaxIsLong ? FormatSpecifierFlag_Long : FormatSpecifierFlag_LongLong);
|
||||
format++;
|
||||
break;
|
||||
case 't':
|
||||
SetFlag(PtrDiffIsLong ? FormatSpecifierFlag_Long : FormatSpecifierFlag_LongLong);
|
||||
format++;
|
||||
break;
|
||||
case 'h':
|
||||
SetFlag(FormatSpecifierFlag_Short);
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
SetFlag(FormatSpecifierFlag_Char);
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
SetFlag(FormatSpecifierFlag_Long);
|
||||
format++;
|
||||
if (*format == 'l') {
|
||||
SetFlag(FormatSpecifierFlag_LongLong);
|
||||
format++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const char specifier = *(format++);
|
||||
switch (specifier) {
|
||||
case 'p':
|
||||
if constexpr (sizeof(uintptr_t) == sizeof(long long)) {
|
||||
SetFlag(FormatSpecifierFlag_LongLong);
|
||||
} else {
|
||||
SetFlag(FormatSpecifierFlag_Long);
|
||||
}
|
||||
SetFlag(FormatSpecifierFlag_Hash);
|
||||
[[fallthrough]];
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'b':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
/* Determine the base to print with. */
|
||||
u32 base;
|
||||
switch (specifier) {
|
||||
case 'b':
|
||||
base = 2;
|
||||
break;
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
case 'X':
|
||||
SetFlag(FormatSpecifierFlag_Uppercase);
|
||||
[[fallthrough]];
|
||||
case 'p':
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
default:
|
||||
base = 10;
|
||||
ClearFlag(FormatSpecifierFlag_Hash);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Precision implies no zero-padding. */
|
||||
if (HasFlag(FormatSpecifierFlag_HasPrecision)) {
|
||||
ClearFlag(FormatSpecifierFlag_ZeroPad);
|
||||
}
|
||||
|
||||
/* Unsigned types don't get signs. */
|
||||
const bool is_unsigned = base != 10 || specifier == 'u';
|
||||
if (is_unsigned) {
|
||||
ClearFlag(FormatSpecifierFlag_EmptySign);
|
||||
ClearFlag(FormatSpecifierFlag_ForceSign);
|
||||
}
|
||||
|
||||
auto PrintInteger = [&](bool negative, uintmax_t value) {
|
||||
constexpr size_t BufferSize = 64; /* Binary digits for 64-bit numbers may use 64 digits. */
|
||||
char buf[BufferSize];
|
||||
size_t len = 0;
|
||||
|
||||
/* No hash flag for zero. */
|
||||
if (value == 0) {
|
||||
ClearFlag(FormatSpecifierFlag_Hash);
|
||||
}
|
||||
|
||||
if (!HasFlag(FormatSpecifierFlag_HasPrecision) || value != 0) {
|
||||
do {
|
||||
const char digit = static_cast<char>(value % base);
|
||||
buf[len++] = (digit < 10) ? ('0' + digit) : ((HasFlag(FormatSpecifierFlag_Uppercase) ? 'A' : 'a') + digit - 10);
|
||||
value /= base;
|
||||
} while (value);
|
||||
}
|
||||
|
||||
/* Determine our prefix length. */
|
||||
size_t prefix_len = 0;
|
||||
const bool has_sign = negative || HasFlag(FormatSpecifierFlag_ForceSign) || HasFlag(FormatSpecifierFlag_EmptySign);
|
||||
if (has_sign) {
|
||||
prefix_len++;
|
||||
}
|
||||
if (HasFlag(FormatSpecifierFlag_Hash)) {
|
||||
prefix_len += (base != 8) ? 2 : 1;
|
||||
}
|
||||
|
||||
/* Determine zero-padding count. */
|
||||
size_t num_zeroes = (len < precision) ? precision - len : 0;
|
||||
if (!HasFlag(FormatSpecifierFlag_LeftJustify) && HasFlag(FormatSpecifierFlag_ZeroPad)) {
|
||||
num_zeroes = (len + prefix_len < width) ? width - len - prefix_len : 0;
|
||||
}
|
||||
|
||||
/* Print out left padding. */
|
||||
if (!HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
for (size_t i = len + prefix_len + num_zeroes; i < static_cast<size_t>(width); i++) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out sign. */
|
||||
if (negative) {
|
||||
WriteCharacter('-');
|
||||
} else if (HasFlag(FormatSpecifierFlag_ForceSign)) {
|
||||
WriteCharacter('+');
|
||||
} else if (HasFlag(FormatSpecifierFlag_EmptySign)) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
|
||||
/* Print out base prefix. */
|
||||
if (HasFlag(FormatSpecifierFlag_Hash)) {
|
||||
WriteCharacter('0');
|
||||
if (base == 2) {
|
||||
WriteCharacter('b');
|
||||
} else if (base == 16) {
|
||||
WriteCharacter('x');
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out zeroes. */
|
||||
for (size_t i = 0; i < num_zeroes; i++) {
|
||||
WriteCharacter('0');
|
||||
}
|
||||
|
||||
/* Print out digits. */
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
WriteCharacter(buf[len - 1 - i]);
|
||||
}
|
||||
|
||||
/* Print out right padding. */
|
||||
if (HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
for (size_t i = len + prefix_len + num_zeroes; i < static_cast<size_t>(width); i++) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Output the integer. */
|
||||
if (is_unsigned) {
|
||||
uintmax_t n = 0;
|
||||
if (HasFlag(FormatSpecifierFlag_LongLong)) {
|
||||
n = static_cast<unsigned long long>(va_arg(vl, unsigned long long));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Long)) {
|
||||
n = static_cast<unsigned long>(va_arg(vl, unsigned long));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Char)) {
|
||||
n = static_cast<unsigned char>(va_arg(vl, unsigned int));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Short)) {
|
||||
n = static_cast<unsigned short>(va_arg(vl, unsigned int));
|
||||
} else {
|
||||
n = static_cast<unsigned int>(va_arg(vl, unsigned int));
|
||||
}
|
||||
if (specifier == 'p' && n == 0) {
|
||||
WriteCharacter('(');
|
||||
WriteCharacter('n');
|
||||
WriteCharacter('i');
|
||||
WriteCharacter('l');
|
||||
WriteCharacter(')');
|
||||
} else {
|
||||
PrintInteger(false, n);
|
||||
}
|
||||
} else {
|
||||
intmax_t n = 0;
|
||||
if (HasFlag(FormatSpecifierFlag_LongLong)) {
|
||||
n = static_cast<signed long long>(va_arg(vl, signed long long));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Long)) {
|
||||
n = static_cast<signed long>(va_arg(vl, signed long));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Char)) {
|
||||
n = static_cast<signed char>(va_arg(vl, signed int));
|
||||
} else if (HasFlag(FormatSpecifierFlag_Short)) {
|
||||
n = static_cast<signed short>(va_arg(vl, signed int));
|
||||
} else {
|
||||
n = static_cast<signed int>(va_arg(vl, signed int));
|
||||
}
|
||||
const bool negative = n < 0;
|
||||
const uintmax_t u = (negative) ? static_cast<uintmax_t>(-n) : static_cast<uintmax_t>(n);
|
||||
PrintInteger(negative, u);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
size_t len = 1;
|
||||
if (!HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
while (len++ < width) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
WriteCharacter(static_cast<char>(va_arg(vl, int)));
|
||||
if (HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
while (len++ < width) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
const char *str = va_arg(vl, char *);
|
||||
if (str == nullptr) {
|
||||
str = "(null)";
|
||||
}
|
||||
|
||||
size_t len = Strnlen(str, precision > 0 ? precision : std::numeric_limits<size_t>::max());
|
||||
if (HasFlag(FormatSpecifierFlag_HasPrecision)) {
|
||||
len = (len < precision) ? len : precision;
|
||||
}
|
||||
if (!HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
while (len++ < width) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
while (*str && (!HasFlag(FormatSpecifierFlag_HasPrecision) || (precision--) != 0)) {
|
||||
WriteCharacter(*(str++));
|
||||
}
|
||||
if (HasFlag(FormatSpecifierFlag_LeftJustify)) {
|
||||
while (len++ < width) {
|
||||
WriteCharacter(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
default:
|
||||
WriteCharacter(specifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure null termination. */
|
||||
WriteCharacter('\0');
|
||||
dst[dst_size - 1] = '\0';
|
||||
}
|
||||
|
||||
KSpinLock g_debug_log_lock;
|
||||
bool g_initialized_impl;
|
||||
|
||||
@@ -452,9 +75,6 @@ namespace ams::kern {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
void KDebugLog::Initialize() {
|
||||
if (KTargetSystem::IsDebugLoggingEnabled()) {
|
||||
KScopedInterruptDisable di;
|
||||
@@ -486,7 +106,7 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
void KDebugLog::VSNPrintf(char *dst, const size_t dst_size, const char *format, ::std::va_list vl) {
|
||||
VSNPrintfImpl(dst, dst_size, format, vl);
|
||||
::ams::util::TVSNPrintf(dst, dst_size, format, vl);
|
||||
}
|
||||
|
||||
Result KDebugLog::PrintUserString(ams::kern::svc::KUserPointer<const char *> user_str, size_t len) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in common atmosphere configuration
|
||||
#---------------------------------------------------------------------------------
|
||||
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
include $(CURRENT_DIRECTORY)/../config/common.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# pull in switch rules
|
||||
@@ -15,7 +17,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/stratosphere.hpp
|
||||
PRECOMPILED_HEADERS := $(CURRENT_DIRECTORY)/include/stratosphere.hpp
|
||||
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2
|
||||
@@ -66,7 +68,7 @@ endif
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
|
||||
export GCH_FILES := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
@@ -103,12 +105,12 @@ dist: dist-src dist-bin
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr release lib *.bz2 include/stratosphere.hpp.gch
|
||||
@rm -fr release lib *.bz2 $(GCH_FILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
|
||||
DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES:.gch=.d),$(notdir $(hdr)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <stratosphere/erpt.hpp>
|
||||
#include <stratosphere/err.hpp>
|
||||
#include <stratosphere/fatal.hpp>
|
||||
#include <stratosphere/gpio.hpp>
|
||||
#include <stratosphere/hid.hpp>
|
||||
#include <stratosphere/hos.hpp>
|
||||
#include <stratosphere/kvdb.hpp>
|
||||
@@ -60,7 +61,6 @@
|
||||
#include <stratosphere/pgl.hpp>
|
||||
#include <stratosphere/psc.hpp>
|
||||
#include <stratosphere/pm.hpp>
|
||||
#include <stratosphere/reg.hpp>
|
||||
#include <stratosphere/ro.hpp>
|
||||
#include <stratosphere/settings.hpp>
|
||||
#include <stratosphere/sf.hpp>
|
||||
|
||||
@@ -39,19 +39,21 @@ namespace ams::impl {
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pm, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, pm, ProcessTrack);
|
||||
|
||||
|
||||
/* NCM. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, MainWaitThreads);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, ContentManagerServerIpcSession);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ncm, LocationResolverServerIpcSession);
|
||||
|
||||
/* FS. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader);
|
||||
AMS_DEFINE_SYSTEM_THREAD(11, sdmmc, DeviceDetector);
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess);
|
||||
AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader);
|
||||
|
||||
/* Boot. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, boot, Main);
|
||||
|
||||
@@ -19,16 +19,13 @@
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size);
|
||||
|
||||
u32 ReadRegister(uintptr_t phys_addr);
|
||||
void WriteRegister(uintptr_t phys_addr, u32 value);
|
||||
u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask);
|
||||
u32 ReadRegister(dd::PhysicalAddress phys_addr);
|
||||
void WriteRegister(dd::PhysicalAddress phys_addr, u32 value);
|
||||
u32 ReadWriteRegister(dd::PhysicalAddress phys_addr, u32 value, u32 mask);
|
||||
|
||||
/* Convenience Helper. */
|
||||
|
||||
inline uintptr_t GetIoMapping(uintptr_t phys_addr, size_t size) {
|
||||
const uintptr_t io_mapping = QueryIoMapping(phys_addr, size);
|
||||
inline uintptr_t GetIoMapping(dd::PhysicalAddress phys_addr, size_t size) {
|
||||
const uintptr_t io_mapping = dd::QueryIoMapping(phys_addr, size);
|
||||
AMS_ABORT_UNLESS(io_mapping);
|
||||
return io_mapping;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License
|
||||
* 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
|
||||
@@ -13,6 +13,7 @@
|
||||
* 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
|
||||
|
||||
#define EVP_COP_RESET_VECTOR 0x200
|
||||
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
namespace ams::ddsf {
|
||||
|
||||
enum AccessMode {
|
||||
AccessMode_None = (0u << 0),
|
||||
AccessMode_Read = (1u << 0),
|
||||
AccessMode_Write = (1u << 1),
|
||||
|
||||
AccessMode_ReadWrite = AccessMode_Read | AccessMode_Write,
|
||||
};
|
||||
|
||||
}
|
||||
22
libraries/libstratosphere/include/stratosphere/gpio.hpp
Normal file
22
libraries/libstratosphere/include/stratosphere/gpio.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere/gpio/gpio_types.hpp>
|
||||
#include <stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp>
|
||||
#include <stratosphere/gpio/sf/gpio_sf_i_manager.hpp>
|
||||
#include <stratosphere/gpio/gpio_api.hpp>
|
||||
#include <stratosphere/gpio/gpio_pad_api.hpp>
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License
|
||||
* 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
|
||||
@@ -14,8 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
|
||||
#define APBDEV_PMC_DPD_ENABLE 0x024
|
||||
#define APBDEV_PMC_SCRATCH0 0x050
|
||||
#define APBDEV_PMC_SCRATCH4 0x060
|
||||
#define APBDEV_PMC_SCRATCH39 0x138
|
||||
namespace ams::gpio {
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
#include <stratosphere/gpio/gpio_select_pad_name.hpp>
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
struct GpioPadSession {
|
||||
void *_session;
|
||||
os::SystemEventType *_event;
|
||||
};
|
||||
|
||||
Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code);
|
||||
void CloseSession(GpioPadSession *session);
|
||||
|
||||
Direction GetDirection(GpioPadSession *session);
|
||||
void SetDirection(GpioPadSession *session, Direction direction);
|
||||
|
||||
GpioValue GetValue(GpioPadSession *session);
|
||||
void SetValue(GpioPadSession *session, GpioValue value);
|
||||
|
||||
InterruptMode GetInterruptMode(GpioPadSession *session);
|
||||
void SetInterruptMode(GpioPadSession *session, InterruptMode mode);
|
||||
|
||||
bool GetInterruptEnable(GpioPadSession *session);
|
||||
void SetInterruptEnable(GpioPadSession *session, bool en);
|
||||
|
||||
InterruptStatus GetInterruptStatus(GpioPadSession *session);
|
||||
void ClearInterruptStatus(GpioPadSession *session);
|
||||
|
||||
int GetDebounceTime(GpioPadSession *session);
|
||||
void SetDebounceTime(GpioPadSession *session, int ms);
|
||||
|
||||
bool GetDebounceEnabled(GpioPadSession *session);
|
||||
void SetDebounceEnabled(GpioPadSession *session, bool en);
|
||||
|
||||
Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session);
|
||||
void UnbindInterrupt(GpioPadSession *session);
|
||||
|
||||
Result IsWakeEventActive(bool *out_is_active, ams::DeviceCode device_code);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
enum GpioPadName : u32 {
|
||||
GpioPadName_CodecLdoEnTemp = 1,
|
||||
GpioPadName_ButtonVolUp = 25,
|
||||
GpioPadName_ButtonVolDn = 26,
|
||||
GpioPadName_SdCd = 56,
|
||||
};
|
||||
|
||||
/* TODO: Better place for this? */
|
||||
constexpr inline const DeviceCode DeviceCode_CodecLdoEnTemp = 0x33000002;
|
||||
constexpr inline const DeviceCode DeviceCode_ButtonVolUp = 0x35000002;
|
||||
constexpr inline const DeviceCode DeviceCode_ButtonVolDn = 0x35000003;
|
||||
constexpr inline const DeviceCode DeviceCode_SdCd = 0x3C000002;
|
||||
|
||||
constexpr inline GpioPadName ConvertToGpioPadName(DeviceCode dc) {
|
||||
switch (dc.GetInternalValue()) {
|
||||
case DeviceCode_CodecLdoEnTemp.GetInternalValue(): return GpioPadName_CodecLdoEnTemp;
|
||||
case DeviceCode_ButtonVolUp .GetInternalValue(): return GpioPadName_ButtonVolUp;
|
||||
case DeviceCode_ButtonVolDn .GetInternalValue(): return GpioPadName_ButtonVolDn;
|
||||
case DeviceCode_SdCd .GetInternalValue(): return GpioPadName_SdCd;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline DeviceCode ConvertToDeviceCode(GpioPadName gpn) {
|
||||
switch (gpn) {
|
||||
case GpioPadName_CodecLdoEnTemp: return DeviceCode_CodecLdoEnTemp;
|
||||
case GpioPadName_ButtonVolUp: return DeviceCode_ButtonVolUp;
|
||||
case GpioPadName_ButtonVolDn: return DeviceCode_ButtonVolDn;
|
||||
case GpioPadName_SdCd: return DeviceCode_SdCd;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
#include <stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp>
|
||||
#else
|
||||
/* Error? */
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
enum InterruptMode : u32 {
|
||||
InterruptMode_LowLevel = 0,
|
||||
InterruptMode_HighLevel = 1,
|
||||
InterruptMode_RisingEdge = 2,
|
||||
InterruptMode_FallingEdge = 3,
|
||||
InterruptMode_AnyEdge = 4,
|
||||
};
|
||||
|
||||
enum Direction : u32 {
|
||||
Direction_Input = 0,
|
||||
Direction_Output = 1,
|
||||
};
|
||||
|
||||
enum GpioValue : u32 {
|
||||
GpioValue_Low = 0,
|
||||
GpioValue_High = 1,
|
||||
};
|
||||
|
||||
enum InterruptStatus : u32 {
|
||||
InterruptStatus_Inactive = 0,
|
||||
InterruptStatus_Active = 1,
|
||||
};
|
||||
|
||||
using WakeBitFlag = util::BitFlagSet<128>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
#include <stratosphere/gpio/gpio_select_pad_name.hpp>
|
||||
#include <stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp>
|
||||
|
||||
namespace ams::gpio::sf {
|
||||
|
||||
#define AMS_GPIO_I_MANAGER_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenSessionForDev, (ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, s32 pad_descriptor) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, OpenSession, (ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, OpenSessionForTest, (ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, IsWakeEventActive, (ams::sf::Out<bool> out, gpio::GpioPadName pad_name), hos::Version_Min, hos::Version_6_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetWakeEventActiveFlagSet, (ams::sf::Out<gpio::WakeBitFlag> out), hos::Version_Min, hos::Version_6_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 5, Result, SetWakeEventActiveFlagSetForDebug, (gpio::GpioPadName pad_name, bool is_enabled), hos::Version_Min, hos::Version_6_2_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, SetWakePinDebugMode, (s32 mode) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenSession2, (ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, DeviceCode device_code, ddsf::AccessMode access_mode), hos::Version_5_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 8, Result, IsWakeEventActive2, (ams::sf::Out<bool> out, DeviceCode device_code), hos::Version_5_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 9, Result, SetWakeEventActiveFlagSetForDebug2, (DeviceCode device_code, bool is_enabled), hos::Version_5_0_0 ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, SetRetryValues, (u32 arg0, u32 arg1), hos::Version_6_0_0 )
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(IManager, AMS_GPIO_I_MANAGER_INTERFACE_INFO)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/gpio/gpio_types.hpp>
|
||||
|
||||
namespace ams::gpio::sf {
|
||||
|
||||
#define AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, SetDirection, (gpio::Direction direction) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, GetDirection, (ams::sf::Out<gpio::Direction> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, SetInterruptMode, (gpio::InterruptMode mode) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, GetInterruptMode, (ams::sf::Out<gpio::InterruptMode> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, SetInterruptEnable, (bool enable) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 5, Result, GetInterruptEnable, (ams::sf::Out<bool> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, GetInterruptStatus, (ams::sf::Out<gpio::InterruptStatus> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 7, Result, ClearInterruptStatus, () ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 8, Result, SetValue, (gpio::GpioValue value) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 9, Result, GetValue, (ams::sf::Out<gpio::GpioValue> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, BindInterrupt, (ams::sf::OutCopyHandle out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 11, Result, UnbindInterrupt, () ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 12, Result, SetDebounceEnabled, (bool enable) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 13, Result, GetDebounceEnabled, (ams::sf::Out<bool> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 14, Result, SetDebounceTime, (s32 ms) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 15, Result, GetDebounceTime, (ams::sf::Out<s32> out) ) \
|
||||
AMS_SF_METHOD_INFO(C, H, 16, Result, SetValueForSleepState, (gpio::GpioValue value), hos::Version_4_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 16, Result, GetValueForSleepState, (ams::sf::Out<gpio::GpioValue> out), hos::Version_6_0_0)
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(IPadSession, AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO)
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
namespace ams::reg {
|
||||
|
||||
inline void Write(volatile u32 *reg, u32 val) {
|
||||
*reg = val;
|
||||
}
|
||||
|
||||
inline void Write(uintptr_t reg, u32 val) {
|
||||
Write(reinterpret_cast<volatile u32 *>(reg), val);
|
||||
}
|
||||
|
||||
inline u32 Read(volatile u32 *reg) {
|
||||
return *reg;
|
||||
}
|
||||
|
||||
inline u32 Read(uintptr_t reg) {
|
||||
return Read(reinterpret_cast<volatile u32 *>(reg));
|
||||
}
|
||||
|
||||
inline void SetBits(volatile u32 *reg, u32 mask) {
|
||||
*reg = *reg | mask;
|
||||
}
|
||||
|
||||
inline void SetBits(uintptr_t reg, u32 mask) {
|
||||
SetBits(reinterpret_cast<volatile u32 *>(reg), mask);
|
||||
}
|
||||
|
||||
inline void ClearBits(volatile u32 *reg, u32 mask) {
|
||||
*reg = *reg & ~mask;
|
||||
}
|
||||
|
||||
inline void ClearBits(uintptr_t reg, u32 mask) {
|
||||
ClearBits(reinterpret_cast<volatile u32 *>(reg), mask);
|
||||
}
|
||||
|
||||
inline void MaskBits(volatile u32 *reg, u32 mask) {
|
||||
*reg = *reg & mask;
|
||||
}
|
||||
|
||||
inline void MaskBits(uintptr_t reg, u32 mask) {
|
||||
MaskBits(reinterpret_cast<volatile u32 *>(reg), mask);
|
||||
}
|
||||
|
||||
inline void ReadWrite(volatile u32 *reg, u32 val, u32 mask) {
|
||||
*reg = (*reg & (~mask)) | (val & mask);
|
||||
}
|
||||
|
||||
inline void ReadWrite(uintptr_t reg, u32 val, u32 mask) {
|
||||
ReadWrite(reinterpret_cast<volatile u32 *>(reg), val, mask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -167,20 +167,19 @@ namespace ams::boot2 {
|
||||
}
|
||||
}
|
||||
|
||||
bool GetGpioPadLow(GpioPadName pad) {
|
||||
GpioPadSession button;
|
||||
if (R_FAILED(gpioOpenSession(&button, pad))) {
|
||||
bool GetGpioPadLow(DeviceCode device_code) {
|
||||
gpio::GpioPadSession button;
|
||||
if (R_FAILED(gpio::OpenSession(std::addressof(button), device_code))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Ensure we close even on early return. */
|
||||
ON_SCOPE_EXIT { gpioPadClose(&button); };
|
||||
ON_SCOPE_EXIT { gpio::CloseSession(std::addressof(button)); };
|
||||
|
||||
/* Set direction input. */
|
||||
gpioPadSetDirection(&button, GpioDirection_Input);
|
||||
gpio::SetDirection(std::addressof(button), gpio::Direction_Input);
|
||||
|
||||
GpioValue val;
|
||||
return R_SUCCEEDED(gpioPadGetValue(&button, &val)) && val == GpioValue_Low;
|
||||
return gpio::GetValue(std::addressof(button)) == gpio::GpioValue_Low;
|
||||
}
|
||||
|
||||
bool IsForceMaintenance() {
|
||||
@@ -197,7 +196,7 @@ namespace ams::boot2 {
|
||||
|
||||
/* Contact GPIO, read plus/minus buttons. */
|
||||
{
|
||||
return GetGpioPadLow(GpioPadName_ButtonVolUp) && GetGpioPadLow(GpioPadName_ButtonVolDown);
|
||||
return GetGpioPadLow(gpio::DeviceCode_ButtonVolUp) && GetGpioPadLow(gpio::DeviceCode_ButtonVolDn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size) {
|
||||
u64 virtual_addr;
|
||||
const u64 aligned_addr = util::AlignDown(phys_addr, os::MemoryPageSize);
|
||||
const size_t offset = phys_addr - aligned_addr;
|
||||
const u64 aligned_size = size + offset;
|
||||
if (hos::GetVersion() >= hos::Version_10_0_0) {
|
||||
u64 region_size;
|
||||
R_TRY_CATCH(svcQueryIoMapping(&virtual_addr, ®ion_size, aligned_addr, aligned_size)) {
|
||||
/* Official software handles this by returning 0. */
|
||||
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
AMS_ASSERT(region_size >= aligned_size);
|
||||
} else {
|
||||
R_TRY_CATCH(svcLegacyQueryIoMapping(&virtual_addr, aligned_addr, aligned_size)) {
|
||||
/* Official software handles this by returning 0. */
|
||||
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
}
|
||||
|
||||
return static_cast<uintptr_t>(virtual_addr + offset);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline u32 ReadWriteRegisterImpl(uintptr_t phys_addr, u32 value, u32 mask) {
|
||||
u32 out_value;
|
||||
R_ABORT_UNLESS(svcReadWriteRegister(&out_value, phys_addr, mask, value));
|
||||
return out_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 ReadRegister(uintptr_t phys_addr) {
|
||||
return ReadWriteRegisterImpl(phys_addr, 0, 0);
|
||||
}
|
||||
|
||||
void WriteRegister(uintptr_t phys_addr, u32 value) {
|
||||
ReadWriteRegisterImpl(phys_addr, value, ~u32());
|
||||
}
|
||||
|
||||
u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask) {
|
||||
return ReadWriteRegisterImpl(phys_addr, value, mask);
|
||||
}
|
||||
|
||||
}
|
||||
197
libraries/libstratosphere/source/gpio/gpio_client_api.cpp
Normal file
197
libraries/libstratosphere/source/gpio/gpio_client_api.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
#include "gpio_remote_manager_impl.hpp"
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
namespace {
|
||||
|
||||
/* TODO: Manager object. */
|
||||
constinit os::SdkMutex g_init_mutex;
|
||||
constinit int g_initialize_count = 0;
|
||||
std::shared_ptr<sf::IManager> g_manager;
|
||||
|
||||
using InternalSession = std::shared_ptr<gpio::sf::IPadSession>;
|
||||
|
||||
InternalSession &GetInterface(GpioPadSession *session) {
|
||||
AMS_ASSERT(session->_session != nullptr);
|
||||
return *static_cast<InternalSession *>(session->_session);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
std::scoped_lock lk(g_init_mutex);
|
||||
|
||||
if ((g_initialize_count++) == 0) {
|
||||
R_ABORT_UNLESS(::gpioInitialize());
|
||||
g_manager = ams::sf::MakeShared<sf::IManager, RemoteManagerImpl>();
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
std::scoped_lock lk(g_init_mutex);
|
||||
|
||||
AMS_ASSERT(g_initialize_count > 0);
|
||||
|
||||
if ((--g_initialize_count) == 0) {
|
||||
g_manager.reset();
|
||||
::gpioExit();
|
||||
}
|
||||
}
|
||||
|
||||
Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code) {
|
||||
/* Allocate the session. */
|
||||
InternalSession *internal_session = new (std::nothrow) InternalSession;
|
||||
AMS_ABORT_UNLESS(internal_session != nullptr);
|
||||
auto session_guard = SCOPE_GUARD { delete internal_session; };
|
||||
|
||||
/* Get the session. */
|
||||
{
|
||||
ams::sf::cmif::ServiceObjectHolder object_holder;
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0) {
|
||||
R_TRY(g_manager->OpenSession2(std::addressof(object_holder), device_code, ddsf::AccessMode_ReadWrite));
|
||||
} else {
|
||||
R_TRY(g_manager->OpenSession(std::addressof(object_holder), ConvertToGpioPadName(device_code)));
|
||||
}
|
||||
*internal_session = object_holder.GetServiceObject<sf::IPadSession>();
|
||||
}
|
||||
|
||||
/* Set output. */
|
||||
out_session->_session = internal_session;
|
||||
out_session->_event = nullptr;
|
||||
|
||||
/* We succeeded. */
|
||||
session_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void CloseSession(GpioPadSession *session) {
|
||||
AMS_ASSERT(session != nullptr);
|
||||
|
||||
/* Unbind the interrupt, if it's still bound. */
|
||||
if (session->_event != nullptr) {
|
||||
gpio::UnbindInterrupt(session);
|
||||
}
|
||||
|
||||
/* Close the session. */
|
||||
delete std::addressof(GetInterface(session));
|
||||
session->_session = nullptr;
|
||||
}
|
||||
|
||||
Result IsWakeEventActive(bool *out_is_active, ams::DeviceCode device_code) {
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0) {
|
||||
R_TRY(g_manager->IsWakeEventActive2(out_is_active, device_code));
|
||||
} else {
|
||||
R_TRY(g_manager->IsWakeEventActive(out_is_active, ConvertToGpioPadName(device_code)));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Direction GetDirection(GpioPadSession *session) {
|
||||
Direction out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetDirection(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetDirection(GpioPadSession *session, Direction direction) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetDirection(direction));
|
||||
}
|
||||
|
||||
GpioValue GetValue(GpioPadSession *session) {
|
||||
GpioValue out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetValue(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetValue(GpioPadSession *session, GpioValue value) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetValue(value));
|
||||
}
|
||||
|
||||
InterruptMode GetInterruptMode(GpioPadSession *session) {
|
||||
InterruptMode out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetInterruptMode(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetInterruptMode(GpioPadSession *session, InterruptMode mode) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetInterruptMode(mode));
|
||||
}
|
||||
|
||||
bool GetInterruptEnable(GpioPadSession *session) {
|
||||
bool out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetInterruptEnable(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetInterruptEnable(GpioPadSession *session, bool en) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetInterruptEnable(en));
|
||||
}
|
||||
|
||||
InterruptStatus GetInterruptStatus(GpioPadSession *session) {
|
||||
InterruptStatus out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetInterruptStatus(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void ClearInterruptStatus(GpioPadSession *session) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->ClearInterruptStatus());
|
||||
}
|
||||
|
||||
int GetDebounceTime(GpioPadSession *session) {
|
||||
int out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetDebounceTime(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetDebounceTime(GpioPadSession *session, int ms) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetDebounceTime(ms));
|
||||
}
|
||||
|
||||
bool GetDebounceEnabled(GpioPadSession *session) {
|
||||
bool out;
|
||||
R_ABORT_UNLESS(GetInterface(session)->GetDebounceEnabled(std::addressof(out)));
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetDebounceEnabled(GpioPadSession *session, bool en) {
|
||||
R_ABORT_UNLESS(GetInterface(session)->SetDebounceEnabled(en));
|
||||
}
|
||||
|
||||
Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session) {
|
||||
AMS_ASSERT(session->_event == nullptr);
|
||||
|
||||
ams::sf::CopyHandle handle;
|
||||
R_TRY(GetInterface(session)->BindInterrupt(std::addressof(handle)));
|
||||
|
||||
os::AttachReadableHandleToSystemEvent(event, handle.GetValue(), true, os::EventClearMode_ManualClear);
|
||||
|
||||
session->_event = event;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void UnbindInterrupt(GpioPadSession *session) {
|
||||
AMS_ASSERT(session->_event != nullptr);
|
||||
|
||||
R_ABORT_UNLESS(GetInterface(session)->UnbindInterrupt());
|
||||
|
||||
os::DestroySystemEvent(session->_event);
|
||||
session->_event = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
#include "gpio_remote_pad_session_impl.hpp"
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
class RemoteManagerImpl {
|
||||
public:
|
||||
RemoteManagerImpl() { /* ... */ }
|
||||
|
||||
~RemoteManagerImpl() { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result OpenSessionForDev(ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, s32 pad_descriptor) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result OpenSession(ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name) {
|
||||
::GpioPadSession p;
|
||||
R_TRY(::gpioOpenSession(std::addressof(p), static_cast<::GpioPadName>(static_cast<u32>(pad_name))));
|
||||
|
||||
out.SetValue(ams::sf::MakeShared<gpio::sf::IPadSession, RemotePadSessionImpl>(p));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenSessionForTest(ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result IsWakeEventActive(ams::sf::Out<bool> out, gpio::GpioPadName pad_name) {
|
||||
return ::gpioIsWakeEventActive2(out.GetPointer(), static_cast<::GpioPadName>(static_cast<u32>(pad_name)));
|
||||
}
|
||||
|
||||
Result GetWakeEventActiveFlagSet(ams::sf::Out<gpio::WakeBitFlag> out) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result SetWakeEventActiveFlagSetForDebug(gpio::GpioPadName pad_name, bool is_enabled) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result SetWakePinDebugMode(s32 mode) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result OpenSession2(ams::sf::Out<std::shared_ptr<gpio::sf::IPadSession>> out, DeviceCode device_code, ddsf::AccessMode access_mode) {
|
||||
::GpioPadSession p;
|
||||
R_TRY(::gpioOpenSession2(std::addressof(p), device_code.GetInternalValue(), access_mode));
|
||||
|
||||
out.SetValue(ams::sf::MakeShared<gpio::sf::IPadSession, RemotePadSessionImpl>(p));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result IsWakeEventActive2(ams::sf::Out<bool> out, DeviceCode device_code) {
|
||||
return ::gpioIsWakeEventActive2(out.GetPointer(), device_code.GetInternalValue());
|
||||
}
|
||||
|
||||
Result SetWakeEventActiveFlagSetForDebug2(DeviceCode device_code, bool is_enabled) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result SetRetryValues(u32 arg0, u32 arg1) {
|
||||
/* TODO: libnx bindings */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
};
|
||||
static_assert(gpio::sf::IsIManager<RemoteManagerImpl>);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::gpio {
|
||||
|
||||
class RemotePadSessionImpl {
|
||||
private:
|
||||
::GpioPadSession srv;
|
||||
public:
|
||||
RemotePadSessionImpl(::GpioPadSession &p) : srv(p) { /* ... */ }
|
||||
|
||||
~RemotePadSessionImpl() { ::gpioPadClose(std::addressof(this->srv)); }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result SetDirection(gpio::Direction direction) {
|
||||
return ::gpioPadSetDirection(std::addressof(this->srv), static_cast<::GpioDirection>(static_cast<u32>(direction)));
|
||||
}
|
||||
|
||||
Result GetDirection(ams::sf::Out<gpio::Direction> out) {
|
||||
static_assert(sizeof(gpio::Direction) == sizeof(::GpioDirection));
|
||||
return ::gpioPadGetDirection(std::addressof(this->srv), reinterpret_cast<::GpioDirection *>(out.GetPointer()));
|
||||
}
|
||||
|
||||
Result SetInterruptMode(gpio::InterruptMode mode) {
|
||||
return ::gpioPadSetInterruptMode(std::addressof(this->srv), static_cast<::GpioInterruptMode>(static_cast<u32>(mode)));
|
||||
}
|
||||
|
||||
Result GetInterruptMode(ams::sf::Out<gpio::InterruptMode> out) {
|
||||
static_assert(sizeof(gpio::InterruptMode) == sizeof(::GpioInterruptMode));
|
||||
return ::gpioPadGetInterruptMode(std::addressof(this->srv), reinterpret_cast<::GpioInterruptMode *>(out.GetPointer()));
|
||||
}
|
||||
|
||||
Result SetInterruptEnable(bool enable) {
|
||||
return ::gpioPadSetInterruptEnable(std::addressof(this->srv), enable);
|
||||
}
|
||||
|
||||
Result GetInterruptEnable(ams::sf::Out<bool> out) {
|
||||
return ::gpioPadGetInterruptEnable(std::addressof(this->srv), out.GetPointer());
|
||||
}
|
||||
|
||||
Result GetInterruptStatus(ams::sf::Out<gpio::InterruptStatus> out) {
|
||||
static_assert(sizeof(gpio::InterruptStatus) == sizeof(::GpioInterruptStatus));
|
||||
return ::gpioPadGetInterruptStatus(std::addressof(this->srv), reinterpret_cast<::GpioInterruptStatus *>(out.GetPointer()));
|
||||
}
|
||||
|
||||
Result ClearInterruptStatus() {
|
||||
return ::gpioPadClearInterruptStatus(std::addressof(this->srv));
|
||||
}
|
||||
|
||||
Result SetValue(gpio::GpioValue value) {
|
||||
return ::gpioPadSetValue(std::addressof(this->srv), static_cast<::GpioValue>(static_cast<u32>(value)));
|
||||
}
|
||||
|
||||
Result GetValue(ams::sf::Out<gpio::GpioValue> out) {
|
||||
static_assert(sizeof(gpio::GpioValue) == sizeof(::GpioValue));
|
||||
return ::gpioPadGetValue(std::addressof(this->srv), reinterpret_cast<::GpioValue *>(out.GetPointer()));
|
||||
}
|
||||
|
||||
Result BindInterrupt(ams::sf::OutCopyHandle out) {
|
||||
::Event ev;
|
||||
R_TRY(::gpioPadBindInterrupt(std::addressof(this->srv), std::addressof(ev)));
|
||||
out.SetValue(ev.revent);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result UnbindInterrupt() {
|
||||
return ::gpioPadUnbindInterrupt(std::addressof(this->srv));
|
||||
}
|
||||
|
||||
Result SetDebounceEnabled(bool enable) {
|
||||
return ::gpioPadSetDebounceEnabled(std::addressof(this->srv), enable);
|
||||
}
|
||||
|
||||
Result GetDebounceEnabled(ams::sf::Out<bool> out) {
|
||||
return ::gpioPadGetDebounceEnabled(std::addressof(this->srv), out.GetPointer());
|
||||
}
|
||||
|
||||
Result SetDebounceTime(s32 ms) {
|
||||
return ::gpioPadSetDebounceTime(std::addressof(this->srv), ms);
|
||||
}
|
||||
|
||||
Result GetDebounceTime(ams::sf::Out<s32> out) {
|
||||
return ::gpioPadGetDebounceTime(std::addressof(this->srv), out.GetPointer());
|
||||
}
|
||||
|
||||
Result SetValueForSleepState(gpio::GpioValue value) {
|
||||
/* TODO: libnx bindings. */
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result GetValueForSleepState(ams::sf::Out<gpio::GpioValue> out) {
|
||||
/* TODO: libnx bindings. */
|
||||
AMS_ABORT();
|
||||
}
|
||||
};
|
||||
static_assert(gpio::sf::IsIPadSession<RemotePadSessionImpl>);
|
||||
|
||||
}
|
||||
@@ -20,12 +20,22 @@
|
||||
#include <vapours/literals.hpp>
|
||||
|
||||
#include <vapours/allocator.hpp>
|
||||
#include <vapours/device_code.hpp>
|
||||
#include <vapours/timespan.hpp>
|
||||
#include <vapours/span.hpp>
|
||||
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
#include <vapours/tegra.hpp>
|
||||
#endif
|
||||
|
||||
#include <vapours/crypto.hpp>
|
||||
#include <vapours/svc.hpp>
|
||||
|
||||
#include <vapours/ams/ams_fatal_error_context.hpp>
|
||||
|
||||
#include <vapours/dd.hpp>
|
||||
#include <vapours/sdmmc.hpp>
|
||||
24
libraries/libvapours/include/vapours/dd.hpp
Normal file
24
libraries/libvapours/include/vapours/dd.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
|
||||
#include <vapours/dd/dd_common_types.hpp>
|
||||
#include <vapours/dd/dd_io_mapping.hpp>
|
||||
#include <vapours/dd/dd_cache.hpp>
|
||||
25
libraries/libvapours/include/vapours/dd/dd_cache.hpp
Normal file
25
libraries/libvapours/include/vapours/dd/dd_cache.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/dd/dd_common_types.hpp>
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
void InvalidateDataCache(void *addr, size_t size);
|
||||
void StoreDataCache(void *addr, size_t size);
|
||||
void FlushDataCache(void *addr, size_t size);
|
||||
|
||||
}
|
||||
29
libraries/libvapours/include/vapours/dd/dd_common_types.hpp
Normal file
29
libraries/libvapours/include/vapours/dd/dd_common_types.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
using PhysicalAddress = u64;
|
||||
using DeviceVirtualAddress = u64;
|
||||
|
||||
static_assert(std::same_as<PhysicalAddress, ams::svc::PhysicalAddress>);
|
||||
|
||||
}
|
||||
26
libraries/libvapours/include/vapours/dd/dd_io_mapping.hpp
Normal file
26
libraries/libvapours/include/vapours/dd/dd_io_mapping.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/dd/dd_common_types.hpp>
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
uintptr_t QueryIoMapping(dd::PhysicalAddress phys_addr, size_t size);
|
||||
|
||||
u32 ReadIoRegister(dd::PhysicalAddress phys_addr);
|
||||
void WriteIoRegister(dd::PhysicalAddress phys_addr, u32 value);
|
||||
|
||||
}
|
||||
49
libraries/libvapours/include/vapours/device_code.hpp
Normal file
49
libraries/libvapours/include/vapours/device_code.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
|
||||
namespace ams {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using DeviceCodeType = u32;
|
||||
|
||||
}
|
||||
|
||||
/* TODO: Better understand device code components. */
|
||||
class DeviceCode {
|
||||
private:
|
||||
impl::DeviceCodeType inner_value;
|
||||
public:
|
||||
constexpr DeviceCode(impl::DeviceCodeType v) : inner_value(v) { /* ... */ }
|
||||
|
||||
constexpr impl::DeviceCodeType GetInternalValue() const { return this->inner_value; }
|
||||
|
||||
constexpr bool operator==(const DeviceCode &rhs) const {
|
||||
return this->GetInternalValue() == rhs.GetInternalValue();
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const DeviceCode &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline const DeviceCode InvalidDeviceCode(0);
|
||||
|
||||
}
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
namespace ams::reg {
|
||||
|
||||
template<typename T>
|
||||
concept UnsignedNonConstIntegral = std::unsigned_integral<T> && !std::is_const<T>::value;
|
||||
|
||||
using BitsValue = std::tuple<u16, u16, u32>;
|
||||
using BitsMask = std::tuple<u16, u16>;
|
||||
|
||||
@@ -48,100 +51,137 @@ namespace ams::reg {
|
||||
return (EncodeValue(values) | ...);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Write(volatile u32 *reg, u32 val) { *reg = val; }
|
||||
ALWAYS_INLINE void Write(volatile u32 ®, u32 val) { reg = val; }
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
constexpr ALWAYS_INLINE u32 EncodeMask(const Masks... masks) {
|
||||
return (EncodeMask(masks) | ...);
|
||||
}
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void Write(volatile IntType *reg, std::type_identity_t<IntType> val) { *reg = val; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void Write(volatile IntType ®, std::type_identity_t<IntType> val) { reg = val; }
|
||||
|
||||
ALWAYS_INLINE void Write(uintptr_t reg, u32 val) { Write(reinterpret_cast<volatile u32 *>(reg), val); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void Write(volatile u32 *reg, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); }
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void Write(volatile IntType *reg, const Values... values) { return Write(reg, static_cast<IntType>((EncodeValue(values) | ...))); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void Write(volatile u32 ®, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); }
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void Write(volatile IntType ®, const Values... values) { return Write(reg, static_cast<IntType>((EncodeValue(values) | ...))); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void Write(uintptr_t reg, const Values... values) { return Write(reg, (EncodeValue(values) | ...)); }
|
||||
|
||||
ALWAYS_INLINE u32 Read(volatile u32 *reg) { return *reg; }
|
||||
ALWAYS_INLINE u32 Read(volatile u32 ®) { return reg; }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType Read(volatile IntType *reg) { return *reg; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType Read(volatile IntType ®) { return reg; }
|
||||
|
||||
ALWAYS_INLINE u32 Read(uintptr_t reg) { return Read(reinterpret_cast<volatile u32 *>(reg)); }
|
||||
|
||||
ALWAYS_INLINE u32 Read(volatile u32 *reg, u32 mask) { return *reg & mask; }
|
||||
ALWAYS_INLINE u32 Read(volatile u32 ®, u32 mask) { return reg & mask; }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType Read(volatile IntType *reg, std::type_identity_t<IntType> mask) { return *reg & mask; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType Read(volatile IntType ®, std::type_identity_t<IntType> mask) { return reg & mask; }
|
||||
|
||||
ALWAYS_INLINE u32 Read(uintptr_t reg, u32 mask) { return Read(reinterpret_cast<volatile u32 *>(reg), mask); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE u32 Read(volatile u32 *reg, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE IntType Read(volatile IntType *reg, const Masks... masks) { return Read(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE IntType Read(volatile IntType ®, const Masks... masks) { return Read(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE u32 Read(volatile u32 ®, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); }
|
||||
ALWAYS_INLINE u32 Read(uintptr_t reg, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE u32 Read(uintptr_t reg, const Masks... masks) { return Read(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE bool HasValue(volatile IntType *reg, const Values... values) { return Read(reg, static_cast<IntType>((EncodeMask(values) | ...))) == static_cast<IntType>(Encode(values...)); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE bool HasValue(volatile u32 *reg, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE bool HasValue(volatile u32 ®, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); }
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE bool HasValue(volatile IntType ®, const Values... values) { return Read(reg, static_cast<IntType>((EncodeMask(values) | ...))) == static_cast<IntType>(Encode(values...)); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE bool HasValue(uintptr_t reg, const Values... values) { return Read(reg, (EncodeMask(values) | ...)) == Encode(values...); }
|
||||
|
||||
ALWAYS_INLINE u32 GetValue(volatile u32 *reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
ALWAYS_INLINE u32 GetValue(volatile u32 ®, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
ALWAYS_INLINE u32 GetValue(uintptr_t reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType GetValue(volatile IntType *reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE IntType GetValue(volatile IntType ®, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
|
||||
ALWAYS_INLINE u32 GetValue(uintptr_t reg, const BitsMask mask) { return Read(reg, mask) >> GetOffset(mask); }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void ReadWrite(volatile IntType *reg, std::type_identity_t<IntType> val, std::type_identity_t<IntType> mask) { *reg = (*reg & (~mask)) | (val & mask); }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void ReadWrite(volatile IntType ®, std::type_identity_t<IntType> val, std::type_identity_t<IntType> mask) { reg = ( reg & (~mask)) | (val & mask); }
|
||||
|
||||
ALWAYS_INLINE void ReadWrite(volatile u32 *reg, u32 val, u32 mask) { *reg = (*reg & (~mask)) | (val & mask); }
|
||||
ALWAYS_INLINE void ReadWrite(volatile u32 ®, u32 val, u32 mask) { reg = ( reg & (~mask)) | (val & mask); }
|
||||
ALWAYS_INLINE void ReadWrite(uintptr_t reg, u32 val, u32 mask) { ReadWrite(reinterpret_cast<volatile u32 *>(reg), val, mask); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void ReadWrite(volatile u32 *reg, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); }
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void ReadWrite(volatile IntType *reg, const Values... values) { return ReadWrite(reg, static_cast<IntType>((EncodeValue(values) | ...)), static_cast<IntType>((EncodeMask(values) | ...))); }
|
||||
|
||||
template<typename IntType, typename... Values> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void ReadWrite(volatile IntType ®, const Values... values) { return ReadWrite(reg, static_cast<IntType>((EncodeValue(values) | ...)), static_cast<IntType>((EncodeMask(values) | ...))); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void ReadWrite(volatile u32 ®, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); }
|
||||
ALWAYS_INLINE void ReadWrite(uintptr_t reg, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); }
|
||||
|
||||
template<typename... Values> requires ((sizeof...(Values) > 0) && (std::is_same<Values, BitsValue>::value && ...))
|
||||
ALWAYS_INLINE void ReadWrite(uintptr_t reg, const Values... values) { return ReadWrite(reg, (EncodeValue(values) | ...), (EncodeMask(values) | ...)); }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void SetBits(volatile IntType *reg, std::type_identity_t<IntType> mask) { *reg = *reg | mask; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void SetBits(volatile IntType ®, std::type_identity_t<IntType> mask) { reg = reg | mask; }
|
||||
|
||||
ALWAYS_INLINE void SetBits(volatile u32 *reg, u32 mask) { *reg = *reg | mask; }
|
||||
ALWAYS_INLINE void SetBits(volatile u32 ®, u32 mask) { reg = reg | mask; }
|
||||
ALWAYS_INLINE void SetBits(uintptr_t reg, u32 mask) { SetBits(reinterpret_cast<volatile u32 *>(reg), mask); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void SetBits(volatile u32 *reg, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void SetBits(volatile IntType *reg, const Masks... masks) { return SetBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void SetBits(volatile IntType ®, const Masks... masks) { return SetBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void SetBits(volatile u32 ®, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); }
|
||||
ALWAYS_INLINE void SetBits(uintptr_t reg, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void SetBits(uintptr_t reg, const Masks... masks) { return SetBits(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void ClearBits(volatile IntType *reg, std::type_identity_t<IntType> mask) { *reg = *reg & ~mask; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void ClearBits(volatile IntType ®, std::type_identity_t<IntType> mask) { reg = reg & ~mask; }
|
||||
|
||||
ALWAYS_INLINE void ClearBits(volatile u32 *reg, u32 mask) { *reg = *reg & ~mask; }
|
||||
ALWAYS_INLINE void ClearBits(volatile u32 ®, u32 mask) { reg = reg & ~mask; }
|
||||
ALWAYS_INLINE void ClearBits(uintptr_t reg, u32 mask) { ClearBits(reinterpret_cast<volatile u32 *>(reg), mask); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void ClearBits(volatile u32 *reg, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void ClearBits(volatile IntType *reg, const Masks... masks) { return ClearBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void ClearBits(volatile IntType ®, const Masks... masks) { return ClearBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void ClearBits(volatile u32 ®, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); }
|
||||
ALWAYS_INLINE void ClearBits(uintptr_t reg, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void ClearBits(uintptr_t reg, const Masks... masks) { return ClearBits(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void MaskBits(volatile IntType *reg, std::type_identity_t<IntType> mask) { *reg = *reg & mask; }
|
||||
|
||||
template<typename IntType> requires UnsignedNonConstIntegral<IntType>
|
||||
ALWAYS_INLINE void MaskBits(volatile IntType ®, std::type_identity_t<IntType> mask) { reg = reg & mask; }
|
||||
|
||||
ALWAYS_INLINE void MaskBits(volatile u32 *reg, u32 mask) { *reg = *reg & mask; }
|
||||
ALWAYS_INLINE void MaskBits(volatile u32 ®, u32 mask) { reg = reg & mask; }
|
||||
ALWAYS_INLINE void MaskBits(uintptr_t reg, u32 mask) { MaskBits(reinterpret_cast<volatile u32 *>(reg), mask); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void MaskBits(volatile u32 *reg, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); }
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void MaskBits(volatile IntType *reg, const Masks... masks) { return MaskBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename IntType, typename... Masks> requires UnsignedNonConstIntegral<IntType> && ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void MaskBits(volatile IntType ®, const Masks... masks) { return MaskBits(reg, static_cast<IntType>((EncodeMask(masks) | ...))); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void MaskBits(volatile u32 ®, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); }
|
||||
|
||||
template<typename... Masks> requires ((sizeof...(Masks) > 0) && (std::is_same<Masks, BitsMask>::value && ...))
|
||||
ALWAYS_INLINE void MaskBits(uintptr_t reg, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); }
|
||||
ALWAYS_INLINE void MaskBits(uintptr_t reg, const Masks... masks) { return MaskBits(reg, (EncodeMask(masks) | ...)); }
|
||||
|
||||
#define REG_BITS_MASK(OFFSET, WIDTH) ::ams::reg::BitsMask{OFFSET, WIDTH}
|
||||
#define REG_BITS_VALUE(OFFSET, WIDTH, VALUE) ::ams::reg::BitsValue{OFFSET, WIDTH, VALUE}
|
||||
@@ -41,10 +41,12 @@
|
||||
#include <vapours/results/nim_results.hpp>
|
||||
#include <vapours/results/ns_results.hpp>
|
||||
#include <vapours/results/os_results.hpp>
|
||||
#include <vapours/results/pcv_results.hpp>
|
||||
#include <vapours/results/pgl_results.hpp>
|
||||
#include <vapours/results/pm_results.hpp>
|
||||
#include <vapours/results/psc_results.hpp>
|
||||
#include <vapours/results/ro_results.hpp>
|
||||
#include <vapours/results/sdmmc_results.hpp>
|
||||
#include <vapours/results/settings_results.hpp>
|
||||
#include <vapours/results/sf_results.hpp>
|
||||
#include <vapours/results/sm_results.hpp>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License
|
||||
* 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
|
||||
@@ -13,9 +13,14 @@
|
||||
* 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
|
||||
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x004
|
||||
#define FLOW_CTLR_CC4_HVC_CONTROL 0x060
|
||||
#define FLOW_CTLR_CC4_RETENTION_CONTROL 0x064
|
||||
#define FLOW_CTLR_CC4_HVC_RETRY 0x08C
|
||||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
namespace ams::pcv {
|
||||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(133);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(IllegalRequest, 16);
|
||||
|
||||
}
|
||||
105
libraries/libvapours/include/vapours/results/sdmmc_results.hpp
Normal file
105
libraries/libvapours/include/vapours/results/sdmmc_results.hpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/results/results_common.hpp>
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(24);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(NoDevice, 1);
|
||||
R_DEFINE_ERROR_RESULT(NotActivated, 2);
|
||||
R_DEFINE_ERROR_RESULT(DeviceRemoved, 3);
|
||||
R_DEFINE_ERROR_RESULT(NotAwakened, 4);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(CommunicationError, 32, 126);
|
||||
R_DEFINE_ERROR_RANGE(CommunicationNotAttained, 33, 46);
|
||||
R_DEFINE_ERROR_RESULT(ResponseIndexError, 34);
|
||||
R_DEFINE_ERROR_RESULT(ResponseEndBitError, 35);
|
||||
R_DEFINE_ERROR_RESULT(ResponseCrcError, 36);
|
||||
R_DEFINE_ERROR_RESULT(ResponseTimeoutError, 37);
|
||||
R_DEFINE_ERROR_RESULT(DataEndBitError, 38);
|
||||
R_DEFINE_ERROR_RESULT(DataCrcError, 39);
|
||||
R_DEFINE_ERROR_RESULT(DataTimeoutError, 40);
|
||||
R_DEFINE_ERROR_RESULT(AutoCommandResponseIndexError, 41);
|
||||
R_DEFINE_ERROR_RESULT(AutoCommandResponseEndBitError, 42);
|
||||
R_DEFINE_ERROR_RESULT(AutoCommandResponseCrcError, 43);
|
||||
R_DEFINE_ERROR_RESULT(AutoCommandResponseTimeoutError, 44);
|
||||
R_DEFINE_ERROR_RESULT(CommandCompleteSoftwareTimeout, 45);
|
||||
R_DEFINE_ERROR_RESULT(TransferCompleteSoftwareTimeout, 46);
|
||||
R_DEFINE_ERROR_RANGE(DeviceStatusHasError, 48, 70);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusAddressOutOfRange, 49);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusAddressMisaligned, 50);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusBlockLenError, 51);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusEraseSeqError, 52);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusEraseParam, 53);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusWpViolation, 54);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusLockUnlockFailed, 55);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusComCrcError, 56);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusIllegalCommand, 57);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusDeviceEccFailed, 58);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusCcError, 59);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusError, 60);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusCidCsdOverwrite, 61);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusWpEraseSkip, 62);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusEraseReset, 63);
|
||||
R_DEFINE_ERROR_RESULT(DeviceStatusSwitchError, 64);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedDeviceState, 72);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedDeviceCsdValue, 73);
|
||||
R_DEFINE_ERROR_RESULT(AbortTransactionSoftwareTimeout, 74);
|
||||
R_DEFINE_ERROR_RESULT(CommandInhibitCmdSoftwareTimeout, 75);
|
||||
R_DEFINE_ERROR_RESULT(CommandInhibitDatSoftwareTimeout, 76);
|
||||
R_DEFINE_ERROR_RESULT(BusySoftwareTimeout, 77);
|
||||
R_DEFINE_ERROR_RESULT(IssueTuningCommandSoftwareTimeout, 78);
|
||||
R_DEFINE_ERROR_RESULT(TuningFailed, 79);
|
||||
R_DEFINE_ERROR_RESULT(MmcInitializationSoftwareTimeout, 80);
|
||||
R_DEFINE_ERROR_RESULT(MmcNotSupportExtendedCsd, 81);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedMmcExtendedCsdValue, 82);
|
||||
R_DEFINE_ERROR_RESULT(MmcEraseSoftwareTimeout, 83);
|
||||
R_DEFINE_ERROR_RESULT(SdCardValidationError, 84);
|
||||
R_DEFINE_ERROR_RESULT(SdCardInitializationSoftwareTimeout, 85);
|
||||
R_DEFINE_ERROR_RESULT(SdCardGetValidRcaSoftwareTimeout, 86);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedSdCardAcmdDisabled, 87);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNotSupportSwitchFunctionStatus, 88);
|
||||
R_DEFINE_ERROR_RESULT(UnexpectedSdCardSwitchFunctionStatus, 89);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNotSupportAccessMode, 90);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNot4BitBusWidthAtUhsIMode, 91);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNotSupportSdr104AndSdr50, 92);
|
||||
R_DEFINE_ERROR_RESULT(SdCardCannotSwitchAccessMode, 93);
|
||||
R_DEFINE_ERROR_RESULT(SdCardFailedSwitchAccessMode, 94);
|
||||
R_DEFINE_ERROR_RESULT(SdCardUnacceptableCurrentConsumption, 95);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNotReadyToVoltageSwitch, 96);
|
||||
R_DEFINE_ERROR_RESULT(SdCardNotCompleteVoltageSwitch, 97);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(HostControllerUnexpected, 128, 158);
|
||||
R_DEFINE_ERROR_RESULT(InternalClockStableSoftwareTimeout, 129);
|
||||
R_DEFINE_ERROR_RESULT(SdHostStandardUnknownAutoCmdError, 130);
|
||||
R_DEFINE_ERROR_RESULT(SdHostStandardUnknownError, 131);
|
||||
R_DEFINE_ERROR_RESULT(SdmmcDllCalibrationSoftwareTimeout, 132);
|
||||
R_DEFINE_ERROR_RESULT(SdmmcDllApplicationSoftwareTimeout, 133);
|
||||
R_DEFINE_ERROR_RESULT(SdHostStandardFailSwitchTo1_8V, 134);
|
||||
R_DEFINE_ERROR_RESULT(DriveStrengthCalibrationNotCompleted, 135);
|
||||
R_DEFINE_ERROR_RESULT(DriveStrengthCalibrationSoftwareTimeout, 136);
|
||||
R_DEFINE_ERROR_RESULT(SdmmcCompShortToGnd, 137);
|
||||
R_DEFINE_ERROR_RESULT(SdmmcCompOpen, 138);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(InternalError, 160, 190);
|
||||
R_DEFINE_ERROR_RESULT(NoWaitedInterrupt, 161);
|
||||
R_DEFINE_ERROR_RESULT(WaitInterruptSoftwareTimeout, 162);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(NotImplemented, 201);
|
||||
}
|
||||
28
libraries/libvapours/include/vapours/sdmmc.hpp
Normal file
28
libraries/libvapours/include/vapours/sdmmc.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/svc.hpp>
|
||||
|
||||
#include <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_common.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_mmc.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_sd_card.hpp>
|
||||
#include <vapours/sdmmc/sdmmc_gc_asic.hpp>
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/svc.hpp>
|
||||
#include <vapours/dd.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
|
||||
//#define AMS_SDMMC_THREAD_SAFE
|
||||
//#define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS
|
||||
//#define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL
|
||||
//#define AMS_SDMMC_USE_DEVICE_DETECTOR
|
||||
//#define AMS_SDMMC_USE_LOGGER
|
||||
//#define AMS_SDMMC_USE_OS_EVENTS
|
||||
//#define AMS_SDMMC_USE_OS_TIMER
|
||||
#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
//#define AMS_SDMMC_ENABLE_MMC_HS400
|
||||
//#define AMS_SDMMC_ENABLE_SD_UHS_I
|
||||
//#define AMS_SDMMC_SET_PLLC4_BASE
|
||||
//#define AMS_SDMMC_USE_SD_CARD_DETECTOR
|
||||
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
|
||||
//#define AMS_SDMMC_THREAD_SAFE
|
||||
//#define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS
|
||||
//#define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL
|
||||
//#define AMS_SDMMC_USE_DEVICE_DETECTOR
|
||||
//#define AMS_SDMMC_USE_LOGGER
|
||||
//#define AMS_SDMMC_USE_OS_EVENTS
|
||||
//#define AMS_SDMMC_USE_OS_TIMER
|
||||
#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
//#define AMS_SDMMC_ENABLE_MMC_HS400
|
||||
//#define AMS_SDMMC_ENABLE_SD_UHS_I
|
||||
//#define AMS_SDMMC_SET_PLLC4_BASE
|
||||
//#define AMS_SDMMC_USE_SD_CARD_DETECTOR
|
||||
|
||||
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
|
||||
#define AMS_SDMMC_THREAD_SAFE
|
||||
#define AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS
|
||||
#define AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL
|
||||
#define AMS_SDMMC_USE_DEVICE_DETECTOR
|
||||
#define AMS_SDMMC_USE_LOGGER
|
||||
#define AMS_SDMMC_USE_OS_EVENTS
|
||||
#define AMS_SDMMC_USE_OS_TIMER
|
||||
//#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
#define AMS_SDMMC_ENABLE_MMC_HS400
|
||||
#define AMS_SDMMC_ENABLE_SD_UHS_I
|
||||
#define AMS_SDMMC_SET_PLLC4_BASE
|
||||
#define AMS_SDMMC_USE_SD_CARD_DETECTOR
|
||||
|
||||
#else
|
||||
#error "Unknown execution context for ams::sdmmc!"
|
||||
#endif
|
||||
114
libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp
Normal file
114
libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
enum BusPower {
|
||||
BusPower_Off = 0,
|
||||
BusPower_1_8V = 1,
|
||||
BusPower_3_3V = 2,
|
||||
};
|
||||
|
||||
enum BusWidth {
|
||||
BusWidth_1Bit = 0,
|
||||
BusWidth_4Bit = 1,
|
||||
BusWidth_8Bit = 2,
|
||||
};
|
||||
|
||||
enum SpeedMode {
|
||||
SpeedMode_MmcIdentification = 0,
|
||||
SpeedMode_MmcLegacySpeed = 1,
|
||||
SpeedMode_MmcHighSpeed = 2,
|
||||
SpeedMode_MmcHs200 = 3,
|
||||
SpeedMode_MmcHs400 = 4,
|
||||
SpeedMode_SdCardIdentification = 5,
|
||||
SpeedMode_SdCardDefaultSpeed = 6,
|
||||
SpeedMode_SdCardHighSpeed = 7,
|
||||
SpeedMode_SdCardSdr12 = 8,
|
||||
SpeedMode_SdCardSdr25 = 9,
|
||||
SpeedMode_SdCardSdr50 = 10,
|
||||
SpeedMode_SdCardSdr104 = 11,
|
||||
SpeedMode_SdCardDdr50 = 12,
|
||||
SpeedMode_GcAsicFpgaSpeed = 13,
|
||||
SpeedMode_GcAsicSpeed = 14,
|
||||
};
|
||||
|
||||
enum Port {
|
||||
Port_Mmc0 = 0,
|
||||
Port_SdCard0 = 1,
|
||||
Port_GcAsic0 = 2,
|
||||
};
|
||||
|
||||
struct ErrorInfo {
|
||||
u32 num_activation_failures;
|
||||
u32 num_activation_error_corrections;
|
||||
u32 num_read_write_failures;
|
||||
u32 num_read_write_error_corrections;
|
||||
};
|
||||
|
||||
struct DataTransfer {
|
||||
void *buffer;
|
||||
size_t buffer_size;
|
||||
size_t block_size;
|
||||
u32 num_blocks;
|
||||
bool is_read;
|
||||
};
|
||||
|
||||
using DeviceDetectionEventCallback = void (*)(void *);
|
||||
|
||||
constexpr inline size_t SectorSize = 0x200;
|
||||
|
||||
constexpr inline size_t DeviceCidSize = 0x10;
|
||||
constexpr inline size_t DeviceCsdSize = 0x10;
|
||||
|
||||
constexpr inline size_t BufferDeviceVirtualAddressAlignment = alignof(ams::dd::DeviceVirtualAddress);
|
||||
static_assert(BufferDeviceVirtualAddressAlignment >= 8);
|
||||
|
||||
void Initialize(Port port);
|
||||
void Finalize(Port port);
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
void SwitchToPcvClockResetControl();
|
||||
#endif
|
||||
|
||||
#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS)
|
||||
void RegisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address);
|
||||
void UnregisterDeviceVirtualAddress(Port port, uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address);
|
||||
#endif
|
||||
|
||||
void ChangeCheckTransferInterval(Port port, u32 ms);
|
||||
void SetDefaultCheckTransferInterval(Port port);
|
||||
|
||||
Result Activate(Port port);
|
||||
void Deactivate(Port port);
|
||||
|
||||
Result Read(void *dst, size_t dst_size, Port port, u32 sector_index, u32 num_sectors);
|
||||
Result Write(Port port, u32 sector_index, u32 num_sectors, const void *src, size_t src_size);
|
||||
|
||||
Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width, Port port);
|
||||
|
||||
Result GetDeviceSpeedMode(SpeedMode *out, Port port);
|
||||
Result GetDeviceMemoryCapacity(u32 *out_num_sectors, Port port);
|
||||
Result GetDeviceStatus(u32 *out_device_status, Port port);
|
||||
Result GetDeviceCid(void *out, size_t out_size, Port port);
|
||||
Result GetDeviceCsd(void *out, size_t out_size, Port port);
|
||||
|
||||
void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size, Port port);
|
||||
|
||||
}
|
||||
34
libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp
Normal file
34
libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
constexpr inline size_t GcAsicOperationSize = 0x40;
|
||||
|
||||
void PutGcAsicToSleep(Port port);
|
||||
Result AwakenGcAsic(Port port);
|
||||
Result WriteGcAsicOperation(Port port, const void *op_buf, size_t op_buf_size);
|
||||
Result FinishGcAsicOperation(Port port);
|
||||
Result AbortGcAsicOperation(Port port);
|
||||
Result SleepGcAsic(Port port);
|
||||
Result UpdateGcAsicKey(Port port);
|
||||
|
||||
void SignalGcRemovedEvent(Port port);
|
||||
void ClearGcRemovedEvent(Port port);
|
||||
|
||||
}
|
||||
43
libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp
Normal file
43
libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
enum MmcPartition {
|
||||
MmcPartition_UserData = 0,
|
||||
MmcPartition_BootPartition1 = 1,
|
||||
MmcPartition_BootPartition2 = 2,
|
||||
MmcPartition_Unknown = 3,
|
||||
};
|
||||
|
||||
constexpr inline size_t MmcExtendedCsdSize = 0x200;
|
||||
constexpr inline size_t MmcWorkBufferSize = MmcExtendedCsdSize;
|
||||
|
||||
void SetMmcWorkBuffer(Port port, void *buffer, size_t buffer_size);
|
||||
void PutMmcToSleep(Port port);
|
||||
void AwakenMmc(Port port);
|
||||
Result SelectMmcPartition(Port port, MmcPartition mmc_partition);
|
||||
Result EraseMmc(Port port);
|
||||
Result GetMmcBootPartitionCapacity(u32 *out_num_sectors, Port port);
|
||||
Result GetMmcExtendedCsd(void *out_buffer, size_t buffer_size, Port port);
|
||||
|
||||
Result CheckMmcConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width, Port port);
|
||||
|
||||
}
|
||||
53
libraries/libvapours/include/vapours/sdmmc/sdmmc_sd_card.hpp
Normal file
53
libraries/libvapours/include/vapours/sdmmc/sdmmc_sd_card.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/sdmmc/sdmmc_build_config.hpp>
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
enum SdCardSwitchFunction {
|
||||
SdCardSwitchFunction_CheckSupportedFunction = 0,
|
||||
SdCardSwitchFunction_CheckDefault = 1,
|
||||
SdCardSwitchFunction_CheckHighSpeed = 2,
|
||||
SdCardSwitchFunction_CheckSdr50 = 3,
|
||||
SdCardSwitchFunction_CheckSdr104 = 4,
|
||||
SdCardSwitchFunction_CheckDdr50 = 5,
|
||||
};
|
||||
|
||||
constexpr inline size_t SdCardScrSize = 0x08;
|
||||
constexpr inline size_t SdCardSwitchFunctionStatusSize = 0x40;
|
||||
constexpr inline size_t SdCardSdStatusSize = 0x40;
|
||||
|
||||
constexpr inline size_t SdCardWorkBufferSize = SdCardSdStatusSize;
|
||||
|
||||
void SetSdCardWorkBuffer(Port port, void *buffer, size_t buffer_size);
|
||||
void PutSdCardToSleep(Port port);
|
||||
void AwakenSdCard(Port port);
|
||||
Result GetSdCardProtectedAreaCapacity(u32 *out_num_sectors, Port port);
|
||||
Result GetSdCardScr(void *dst, size_t dst_size, Port port);
|
||||
Result GetSdCardSwitchFunctionStatus(void *dst, size_t dst_size, Port port, SdCardSwitchFunction switch_function);
|
||||
Result GetSdCardCurrentConsumption(u16 *out_current_consumption, Port port, SpeedMode speed_mode);
|
||||
Result GetSdCardSdStatus(void *dst, size_t dst_size, Port port);
|
||||
|
||||
Result CheckSdCardConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width, Port port);
|
||||
|
||||
bool IsSdCardInserted(Port port);
|
||||
bool IsSdCardRemoved(Port port);
|
||||
|
||||
void RegisterSdCardDetectionEventCallback(Port port, DeviceDetectionEventCallback callback, void *arg);
|
||||
void UnregisterSdCardDetectionEventCallback(Port port);
|
||||
|
||||
}
|
||||
39
libraries/libvapours/include/vapours/tegra.hpp
Normal file
39
libraries/libvapours/include/vapours/tegra.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#include <vapours/tegra/tegra_ahb_arbc.hpp>
|
||||
#include <vapours/tegra/tegra_apb_misc.hpp>
|
||||
#include <vapours/tegra/tegra_avp_cache.hpp>
|
||||
#include <vapours/tegra/tegra_clkrst.hpp>
|
||||
#include <vapours/tegra/tegra_emc.hpp>
|
||||
#include <vapours/tegra/tegra_evp.hpp>
|
||||
#include <vapours/tegra/tegra_flow_ctlr.hpp>
|
||||
#include <vapours/tegra/tegra_ictlr.hpp>
|
||||
#include <vapours/tegra/tegra_mc.hpp>
|
||||
#include <vapours/tegra/tegra_mselect.hpp>
|
||||
#include <vapours/tegra/tegra_pinmux.hpp>
|
||||
#include <vapours/tegra/tegra_pg_up.hpp>
|
||||
#include <vapours/tegra/tegra_pmc.hpp>
|
||||
#include <vapours/tegra/tegra_sb.hpp>
|
||||
#include <vapours/tegra/tegra_sysctr0.hpp>
|
||||
#include <vapours/tegra/tegra_timer.hpp>
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define AHB_ARBC(x) (0x6000c000 + x)
|
||||
|
||||
@@ -14,11 +14,24 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define APB_MISC_PP_CONFIG_CTL (0x024)
|
||||
#define APB_MISC_PP_CONFIG_CTL (0x024)
|
||||
|
||||
#define APB_MISC_GP_ASDBGREG (0x810)
|
||||
#define APB_MISC_GP_ASDBGREG (0x810)
|
||||
|
||||
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL (0xA98)
|
||||
|
||||
#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL (0xA9C)
|
||||
#define APB_MISC_GP_SDMMC2_PAD_CFGPADCTRL (0xA9C)
|
||||
|
||||
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL (0xAB4)
|
||||
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL (0xABC)
|
||||
|
||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 (0xc00)
|
||||
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 (0xc00)
|
||||
@@ -41,6 +54,29 @@ DEFINE_APB_MISC_REG_BIT_ENUM(PP_CONFIG_CTL_TBE, 7, DISABLE, ENABLE);
|
||||
|
||||
DEFINE_APB_MISC_REG(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 24, 2);
|
||||
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_PAD_CAL_DRVDN, 12, 7);
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_PAD_CAL_DRVUP, 20, 7);
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_CLK_CFG_CAL_DRVDN_SLWR, 28, 2);
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_CLK_CFG_CAL_DRVDN_SLWF, 30, 2);
|
||||
|
||||
DEFINE_APB_MISC_REG_BIT_ENUM(GP_EMMC2_PAD_CFGPADCTRL_CFG2TMC_EMMC2_PAD_E_SCH, 0, DISABLE, ENABLE);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC2_PAD_CFGPADCTRL_CFG2TMC_EMMC2_PAD_DRVDN_COMP, 2, 6);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC2_PAD_CFGPADCTRL_CFG2TMC_EMMC2_PAD_DRVUP_COMP, 8, 6);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC2_PAD_CFGPADCTRL_MISC2PMC_EMMC2_ALL_PARK, 14, 13);
|
||||
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC2_PAD_CFGPADCTRL_CFG2TMC_SDMMC2_PAD_CAL_DRVDN, 12, 7);
|
||||
DEFINE_APB_MISC_REG (GP_SDMMC2_PAD_CFGPADCTRL_CFG2TMC_SDMMC2_PAD_CAL_DRVUP, 20, 7);
|
||||
|
||||
|
||||
DEFINE_APB_MISC_REG_BIT_ENUM(GP_EMMC4_PAD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_E_SCH, 0, DISABLE, ENABLE);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC4_PAD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_DRVDN_COMP, 2, 6);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC4_PAD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_DRVUP_COMP, 8, 6);
|
||||
DEFINE_APB_MISC_REG (GP_EMMC4_PAD_CFGPADCTRL_MISC2PMC_EMMC4_ALL_PARK, 14, 13);
|
||||
|
||||
DEFINE_APB_MISC_REG(GP_EMMC4_PAD_PUPD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_CMD_PUPD_PULLU, 1, 1);
|
||||
DEFINE_APB_MISC_REG(GP_EMMC4_PAD_PUPD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_CLK_PUPD_PULLD, 2, 1);
|
||||
DEFINE_APB_MISC_REG(GP_EMMC4_PAD_PUPD_CFGPADCTRL_CFG2TMC_EMMC4_PAD_DQS_PUPD_PULLD, 22, 1);
|
||||
|
||||
#define DEFINE_SLAVE_SECURITY_REG(RINDEX, INDEX, NAME) DEFINE_APB_MISC_REG_BIT_ENUM(SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG##RINDEX##_##NAME##_SECURITY_EN, INDEX, DISABLE, ENABLE)
|
||||
|
||||
DEFINE_SLAVE_SECURITY_REG(0, 29, STM);
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define AVP_CACHE_ADDRESS(x) (0x50040000 + x)
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
/* Clock source enums. */
|
||||
#define CLK_RST_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (CLK_RST_CONTROLLER, NAME)
|
||||
@@ -33,13 +38,18 @@
|
||||
|
||||
#define CLK_RST_CONTROLLER_MISC_CLK_ENB (0x048)
|
||||
#define CLK_RST_CONTROLLER_OSC_CTRL (0x050)
|
||||
#define CLK_RST_CONTROLLER_PLLD_BASE (0x0D0)
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC1 (0x0D8)
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC (0x0DC)
|
||||
#define CLK_RST_CONTROLLER_PLLX_BASE (0x0E0)
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC (0x0E4)
|
||||
#define CLK_RST_CONTROLLER_CCLKG_BURST_POLICY (0x368)
|
||||
#define CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER (0x36C)
|
||||
#define CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY (0x370)
|
||||
#define CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER (0x374)
|
||||
#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 (0x388)
|
||||
#define CLK_RST_CONTROLLER_SPARE_REG0 (0x55C)
|
||||
#define CLK_RST_CONTROLLER_PLLC4_BASE (0x5A4)
|
||||
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA (0x0F8)
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB (0x0FC)
|
||||
@@ -74,6 +84,10 @@ DEFINE_CLK_RST_REG(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0, 12);
|
||||
|
||||
DEFINE_CLK_RST_REG_TWO_BIT_ENUM(SPARE_REG0_CLK_M_DIVISOR, 2, CLK_M_DIVISOR1, CLK_M_DIVISOR2, CLK_M_DIVISOR3, CLK_M_DIVISOR4);
|
||||
|
||||
DEFINE_CLK_RST_REG_BIT_ENUM(PLLC4_BASE_PLLC4_IDDQ, 18, OFF, ON);
|
||||
DEFINE_CLK_RST_REG_BIT_ENUM(PLLC4_BASE_PLLC4_LOCK, 27, NOT_LOCK, LOCK_FEQ_AND_PHASE);
|
||||
DEFINE_CLK_RST_REG_BIT_ENUM(PLLC4_BASE_PLLC4_ENABLE, 30, DISABLE, ENABLE);
|
||||
|
||||
/* RST_DEVICES */
|
||||
#define CLK_RST_CONTROLLER_RST_DEVICES_L (0x004)
|
||||
#define CLK_RST_CONTROLLER_RST_DEVICES_H (0x008)
|
||||
@@ -93,15 +107,24 @@ DEFINE_CLK_RST_REG_TWO_BIT_ENUM(SPARE_REG0_CLK_M_DIVISOR, 2, CLK_M_DIVISOR1, CLK
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W (0x364)
|
||||
|
||||
/* CLK_SOURCE */
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 (0x124)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 (0x128)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA (0x178)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB (0x17C)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT (0x3B4)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF (0x62C)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC (0x630)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 (0x124)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 (0x128)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 (0x138)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 (0x150)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 (0x154)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 (0x164)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA (0x178)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB (0x17C)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 (0x1BC)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE (0x1D4)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT (0x3B4)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP (0x620)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF (0x62C)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC (0x630)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL (0x66C)
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM (0x694)
|
||||
|
||||
/* RST_DEV_*_SET */
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_L_SET (0x300)
|
||||
@@ -163,6 +186,19 @@ DEFINE_CLK_RST_REG(CLK_SOURCE_I2C1_I2C1_CLK_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_I2C5_I2C5_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2);
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_I2C5_I2C5_CLK_DIVISOR, 0, 8);
|
||||
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMC1_SDMMC1_CLK_SRC, 29, PLLP_OUT0, PLLA_OUT, PLLC_OUT0, PLLC4_OUT2, PLLM_OUT0, PLLE_OUT0, CLK_M, PLLC4_OUT0);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMC2_SDMMC2_CLK_SRC, 29, PLLP_OUT0, PLLC4_OUT2_LJ, PLLC4_OUT0_LJ, PLLC4_OUT2, PLLC4_OUT1, PLLC4_OUT1_LJ, CLK_M, PLLC4_OUT0);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMC4_SDMMC4_CLK_SRC, 29, PLLP_OUT0, PLLC4_OUT2_LJ, PLLC4_OUT0_LJ, PLLC4_OUT2, PLLC4_OUT1, PLLC4_OUT1_LJ, CLK_M, PLLC4_OUT0);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMC3_SDMMC3_CLK_SRC, 29, PLLP_OUT0, PLLA_OUT, PLLC_OUT0, PLLC4_OUT2, PLLC4_OUT1, PLLE_OUT0, CLK_M, PLLC4_OUT0);
|
||||
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMCX_SDMMCX_CLK_SRC, 29, PLLP_OUT0, _RSVD1_, _RSVD2_, PLLC4_OUT2, _RSVD4_, _RSVD5_, CLK_M, PLLC4_OUT0);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_SDMMC24_SDMMC24_CLK_SRC, 29, PLLP_OUT0, PLLC4_OUT2_LJ, PLLC4_OUT0_LJ, PLLC4_OUT2, PLLC4_OUT1, PLLC4_OUT1_LJ, CLK_M, PLLC4_OUT0);
|
||||
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_SDMMC1_SDMMC1_CLK_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_SDMMC2_SDMMC2_CLK_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_SDMMC4_SDMMC4_CLK_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_SDMMC3_SDMMC3_CLK_DIVISOR, 0, 8);
|
||||
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTA_UARTA_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTB_UARTB_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTC_UARTC_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2);
|
||||
@@ -178,6 +214,9 @@ DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_DVFS_REF_DVFS_REF_CLK_SRC, 29, PLLP
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_DVFS_SOC_DVFS_SOC_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_DVFS_SOC_DVFS_SOC_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, RESERVED4, PLLC4_OUT1, CLK_M, PLLC4_OUT2);
|
||||
|
||||
DEFINE_CLK_RST_REG(CLK_SOURCE_LEGACY_TM_CLK_DIVISOR, 0, 8);
|
||||
DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_LEGACY_TM_CLK_SRC, 29, PLLP_OUT3, PLLC_OUT0, PLLC2_OUT0, CLK_M, PLLP_OUT0, PLLC4_OUT0, PLLC4_OUT1, PLLC4_OUT2);
|
||||
|
||||
DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_SET_SET_COP_RST, 1, DISABLE, ENABLE);
|
||||
|
||||
DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_CLR_CLR_COP_RST, 1, DISABLE, ENABLE);
|
||||
@@ -198,6 +237,9 @@ DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, 29, DISABLE, ENA
|
||||
HANDLER(L, RTC, 0, 4) \
|
||||
HANDLER(L, TMR, 0, 5) \
|
||||
HANDLER(L, GPIO, 0, 8) \
|
||||
HANDLER(L, SDMMC2, 0, 9) \
|
||||
HANDLER(L, SDMMC1, 0, 14) \
|
||||
HANDLER(L, SDMMC4, 0, 15) \
|
||||
HANDLER(L, USBD, 0, 22) \
|
||||
HANDLER(L, CACHE2, 0, 31) \
|
||||
HANDLER(H, MEM, 1, 0) \
|
||||
@@ -209,6 +251,7 @@ DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, 29, DISABLE, ENA
|
||||
HANDLER(H, I2C5, 1, 15) \
|
||||
HANDLER(H, EMC, 1, 25) \
|
||||
HANDLER(H, USB2, 1, 26) \
|
||||
HANDLER(U, SDMMC3, 2, 5) \
|
||||
HANDLER(U, CSITE, 2, 9) \
|
||||
HANDLER(U, IRAMA, 2, 20) \
|
||||
HANDLER(U, IRAMB, 2, 21) \
|
||||
@@ -238,6 +281,7 @@ DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, 29, DISABLE, ENA
|
||||
HANDLER(X, GPU, 5, 24) \
|
||||
HANDLER(X, DBGAPB, 5, 25) \
|
||||
HANDLER(X, PLLG_REF, 5, 29) \
|
||||
HANDLER(Y, LEGACY_TM, 6, 1) \
|
||||
HANDLER(Y, MC_CCPA, 6, 8) \
|
||||
HANDLER(Y, MC_CDPA, 6, 9) \
|
||||
HANDLER(Y, PLLP_OUT_CPU, 6, 31)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define EMC_ADDRESS(x) (0x7001B000 + x)
|
||||
#define EMC0_ADDRESS(x) (0x7001E000 + x)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define EVP_CPU_RESET_VECTOR (0x100)
|
||||
|
||||
@@ -14,12 +14,21 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define FLOW_CTLR_RAM_REPAIR (0x040)
|
||||
#define FLOW_CTLR_FLOW_DBG_QUAL (0x050)
|
||||
#define FLOW_CTLR_CC4_HVC_CONTROL (0x060)
|
||||
#define FLOW_CTLR_CC4_RETENTION_CONTROL (0x064)
|
||||
#define FLOW_CTLR_CC4_HVC_RETRY (0x08C)
|
||||
#define FLOW_CTLR_L2FLUSH_CONTROL (0x094)
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL (0x098)
|
||||
|
||||
#define FLOW_CTLR_RAM_REPAIR (0x040)
|
||||
#define FLOW_CTLR_FLOW_DBG_QUAL (0x050)
|
||||
#define FLOW_CTLR_L2FLUSH_CONTROL (0x094)
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL (0x098)
|
||||
|
||||
#define FLOW_CTLR_CPU0_CSR (0x008)
|
||||
#define FLOW_CTLR_CPU1_CSR (0x018)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define PRI_ICTLR(n) (0x60004000 + n)
|
||||
#define SEC_ICTLR(n) (0x60004100 + n)
|
||||
@@ -14,8 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <exosphere/reg.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define MC_INTSTATUS (0x000)
|
||||
#define MC_INTMASK (0x004)
|
||||
@@ -25,7 +29,7 @@
|
||||
#define MC_SMMU_PTB_ASID (0x01C)
|
||||
#define MC_SMMU_PTB_DATA (0x020)
|
||||
#define MC_SMMU_TLB_FLUSH (0x030)
|
||||
#define MC_SMMU_PTC_FLUSH (0x034)
|
||||
#define MC_SMMU_PTC_FLUSH_0 (0x034)
|
||||
#define MC_EMEM_CFG (0x050)
|
||||
#define MC_EMEM_ADR_CFG (0x054)
|
||||
#define MC_EMEM_ARB_CFG (0x090)
|
||||
@@ -56,7 +60,7 @@
|
||||
#define MC_SMMU_HC_ASID (0x250)
|
||||
#define MC_SMMU_HDA_ASID (0x254)
|
||||
#define MC_SMMU_ISP2_ASID (0x258)
|
||||
#define MC_SMMU_NVENC_ASID (0x264)
|
||||
#define MC_SMMU_MSENC_NVENC_ASID (0x264)
|
||||
#define MC_SMMU_NV_ASID (0x268)
|
||||
#define MC_SMMU_NV2_ASID (0x26C)
|
||||
#define MC_SMMU_PPCS_ASID (0x270)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define MSELECT(x) (0x50060000 + x)
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define PG_UP(x) (0x60000000 + x)
|
||||
|
||||
@@ -14,7 +14,21 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define PINMUX_AUX_SDMMC1_CLK (0x3000)
|
||||
#define PINMUX_AUX_SDMMC1_CMD (0x3004)
|
||||
#define PINMUX_AUX_SDMMC1_DAT3 (0x3008)
|
||||
#define PINMUX_AUX_SDMMC1_DAT2 (0x300C)
|
||||
#define PINMUX_AUX_SDMMC1_DAT1 (0x3010)
|
||||
#define PINMUX_AUX_SDMMC1_DAT0 (0x3014)
|
||||
|
||||
#define PINMUX_AUX_DMIC3_CLK (0x30B4)
|
||||
|
||||
#define PINMUX_AUX_GEN1_I2C_SCL (0x30BC)
|
||||
#define PINMUX_AUX_GEN1_I2C_SDA (0x30C0)
|
||||
@@ -34,6 +48,11 @@
|
||||
#define PINMUX_AUX_UART3_RTS (0x310C)
|
||||
#define PINMUX_AUX_UART3_CTS (0x3110)
|
||||
#define PINMUX_AUX_DVFS_PWM (0x3184)
|
||||
#define PINMUX_AUX_NFC_EN (0x31D0)
|
||||
#define PINMUX_AUX_NFC_INT (0x31D4)
|
||||
#define PINMUX_AUX_LCD_BL_PWM (0x31FC)
|
||||
#define PINMUX_AUX_LCD_BL_EN (0x3200)
|
||||
#define PINMUX_AUX_LCD_RST (0x3204)
|
||||
#define PINMUX_AUX_GPIO_PA6 (0x3244)
|
||||
|
||||
#define PINMUX_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (PINMUX, NAME)
|
||||
@@ -56,6 +75,16 @@ DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_LPDR, 8, DISABLE, ENABLE);
|
||||
DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_OD, 11, DISABLE, ENABLE);
|
||||
DEFINE_PINMUX_REG_BIT_ENUM(AUX_E_SCHMT, 12, DISABLE, ENABLE);
|
||||
|
||||
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_CLK_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_CMD_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_DAT3_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_DAT2_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_DAT1_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_SDMMC1_DAT0_PM, 0, SDMMC1, RSVD1, RSVD2, RSVD3);
|
||||
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_DMIC3_CLK_PM, 0, DMIC3, I2S5A, RSVD2, RSVD3);
|
||||
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_GEN1_I2C_PM, 0, I2C1, RSVD1, RSVD2, RSVD3);
|
||||
DEFINE_PINMUX_REG_TWO_BIT_ENUM(AUX_PWR_I2C_PM, 0, I2CPMU, RSVD1, RSVD2, RSVD3);
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <exosphere/reg.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define APBDEV_PMC_CNTRL (0x000)
|
||||
#define APBDEV_PMC_WAKE_MASK (0x00C)
|
||||
@@ -34,6 +38,7 @@
|
||||
#define APBDEV_PMC_PWR_DET (0x048)
|
||||
#define APBDEV_PMC_SCRATCH0 (0x050)
|
||||
#define APBDEV_PMC_SCRATCH1 (0x054)
|
||||
#define APBDEV_PMC_SCRATCH4 (0x060)
|
||||
#define APBDEV_PMC_SCRATCH12 (0x080)
|
||||
#define APBDEV_PMC_SCRATCH13 (0x084)
|
||||
#define APBDEV_PMC_SCRATCH18 (0x098)
|
||||
@@ -45,6 +50,7 @@
|
||||
#define APBDEV_PMC_SCRATCH31 (0x118)
|
||||
#define APBDEV_PMC_SCRATCH32 (0x11C)
|
||||
#define APBDEV_PMC_SCRATCH33 (0x120)
|
||||
#define APBDEV_PMC_SCRATCH39 (0x138)
|
||||
#define APBDEV_PMC_SCRATCH40 (0x13C)
|
||||
#define APBDEV_PMC_WAKE2_MASK (0x160)
|
||||
#define APBDEV_PMC_WAKE2_LVL (0x164)
|
||||
@@ -198,6 +204,10 @@ DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE2, 29, OFF, ON);
|
||||
|
||||
DEFINE_PMC_REG(PWRGATE_STATUS_CE123, 9, 3);
|
||||
|
||||
DEFINE_PMC_REG_BIT_ENUM(NO_IOPOWER_SDMMC1, 12, DISABLE, ENABLE);
|
||||
DEFINE_PMC_REG_BIT_ENUM(PWR_DET_SDMMC1, 12, DISABLE, ENABLE);
|
||||
DEFINE_PMC_REG_BIT_ENUM(PWR_DET_VAL_SDMMC1, 12, DISABLE, ENABLE);
|
||||
|
||||
DEFINE_PMC_REG(SET_SW_CLAMP_CRAIL, 0, 1);
|
||||
|
||||
DEFINE_PMC_REG_TWO_BIT_ENUM(IO_DPD_REQ_CODE, 30, IDLE, DPD_OFF, DPD_ON, RESERVED3);
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define SB_CSR (0x200)
|
||||
#define SB_PFCFG (0x208)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define SYSCTR0_CNTCR (0x000)
|
||||
#define SYSCTR0_CNTCV0 (0x008)
|
||||
@@ -14,7 +14,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/literals.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/reg.hpp>
|
||||
|
||||
#define TIMERUS_USEC_CFG (0x014)
|
||||
#define TIMER_SHARED_TIMER_SECURE_CFG (0x1A4)
|
||||
@@ -34,8 +34,10 @@
|
||||
#include <vapours/util/util_intrusive_list.hpp>
|
||||
#include <vapours/util/util_intrusive_red_black_tree.hpp>
|
||||
#include <vapours/util/util_tinymt.hpp>
|
||||
#include <vapours/util/util_timer.hpp>
|
||||
#include <vapours/util/util_uuid.hpp>
|
||||
#include <vapours/util/util_bounded_map.hpp>
|
||||
#include <vapours/util/util_overlap.hpp>
|
||||
#include <vapours/util/util_string_util.hpp>
|
||||
#include <vapours/util/util_variadic.hpp>
|
||||
#include <vapours/util/util_format_string.hpp>
|
||||
|
||||
@@ -73,4 +73,9 @@ namespace ams::util {
|
||||
return IsAligned(reinterpret_cast<uintptr_t>(value), alignment);
|
||||
}
|
||||
|
||||
}
|
||||
template<typename T, typename U> requires std::integral<T> && std::integral<U>
|
||||
constexpr ALWAYS_INLINE T DivideUp(T x, U y) {
|
||||
return (x + (y - 1)) / y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
|
||||
namespace ams::util {
|
||||
|
||||
int SNPrintf(char *dst, size_t dst_size, const char *fmt, ...);
|
||||
int VSNPrintf(char *dst, size_t dst_size, const char *fmt, std::va_list vl);
|
||||
|
||||
int TSNPrintf(char *dst, size_t dst_size, const char *fmt, ...);
|
||||
int TVSNPrintf(char *dst, size_t dst_size, const char *fmt, std::va_list vl);
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License
|
||||
* 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
|
||||
@@ -13,8 +13,14 @@
|
||||
* 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
|
||||
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300
|
||||
#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
|
||||
namespace ams::util {
|
||||
|
||||
u32 GetMicroSeconds();
|
||||
void WaitMicroSeconds(int us);
|
||||
|
||||
}
|
||||
41
libraries/libvapours/source/dd/dd_cache.cpp
Normal file
41
libraries/libvapours/source/dd/dd_cache.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "impl/dd_select_cache_impl.hpp"
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
void InvalidateDataCache(void *addr, size_t size) {
|
||||
return impl::InvalidateDataCacheImpl(addr, size);
|
||||
}
|
||||
|
||||
void StoreDataCache(void *addr, size_t size) {
|
||||
return impl::StoreDataCacheImpl(addr, size);
|
||||
}
|
||||
|
||||
void FlushDataCache(void *addr, size_t size) {
|
||||
return impl::FlushDataCacheImpl(addr, size);
|
||||
}
|
||||
|
||||
}
|
||||
101
libraries/libvapours/source/dd/dd_io_mapping.cpp
Normal file
101
libraries/libvapours/source/dd/dd_io_mapping.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
|
||||
namespace ams::dd {
|
||||
|
||||
uintptr_t QueryIoMapping(dd::PhysicalAddress phys_addr, size_t size) {
|
||||
#if defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
/* TODO: Secure Monitor translation? */
|
||||
AMS_UNUSED(size);
|
||||
return static_cast<uintptr_t>(phys_addr);
|
||||
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||
/* TODO: BPMP translation? */
|
||||
AMS_UNUSED(size);
|
||||
return static_cast<uintptr_t>(phys_addr);
|
||||
#else
|
||||
#error "Unknown architecture for ams::dd::QueryIoMapping (EXOSPHERE)!"
|
||||
#endif
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
/* TODO: Kernel address translation? */
|
||||
AMS_UNUSED(size);
|
||||
return static_cast<uintptr_t>(phys_addr);
|
||||
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
|
||||
svc::Address virt_addr = 0;
|
||||
const dd::PhysicalAddress aligned_addr = util::AlignDown(phys_addr, os::MemoryPageSize);
|
||||
const size_t offset = phys_addr - aligned_addr;
|
||||
const size_t aligned_size = size + offset;
|
||||
|
||||
if (hos::GetVersion() >= hos::Version_10_0_0) {
|
||||
svc::Size region_size = 0;
|
||||
R_TRY_CATCH(svc::QueryIoMapping(&virt_addr, ®ion_size, aligned_addr, aligned_size)) {
|
||||
/* Official software handles this by returning 0. */
|
||||
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
AMS_ASSERT(region_size >= aligned_size);
|
||||
} else {
|
||||
R_TRY_CATCH(svc::LegacyQueryIoMapping(&virt_addr, aligned_addr, aligned_size)) {
|
||||
/* Official software handles this by returning 0. */
|
||||
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
}
|
||||
|
||||
return static_cast<uintptr_t>(virt_addr) + offset;
|
||||
|
||||
#else
|
||||
#error "Unknown execution context for ams::dd::QueryIoMapping!"
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 ReadIoRegister(dd::PhysicalAddress phys_addr) {
|
||||
#if defined(ATMOSPHERE_IS_EXOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
return reg::Read(dd::QueryIoMapping(phys_addr, sizeof(u32)));
|
||||
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
|
||||
u32 val;
|
||||
R_ABORT_UNLESS(svc::ReadWriteRegister(std::addressof(val), phys_addr, 0, 0));
|
||||
return val;
|
||||
|
||||
#else
|
||||
#error "Unknown execution context for ams::dd::ReadIoRegister!"
|
||||
#endif
|
||||
}
|
||||
|
||||
void WriteIoRegister(dd::PhysicalAddress phys_addr, u32 value) {
|
||||
#if defined(ATMOSPHERE_IS_EXOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
reg::Write(dd::QueryIoMapping(phys_addr, sizeof(u32)), value);
|
||||
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
|
||||
u32 out_val;
|
||||
R_ABORT_UNLESS(svc::ReadWriteRegister(std::addressof(out_val), phys_addr, 0xFFFFFFFF, value));
|
||||
AMS_UNUSED(out_val);
|
||||
|
||||
#else
|
||||
#error "Unknown execution context for ams::dd::WriteIoRegister!"
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
|
||||
namespace ams::dd::impl {
|
||||
|
||||
void StoreDataCacheImpl(void *addr, size_t size) {
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
/* On aarch64, we can use cache maintenance instructions. */
|
||||
|
||||
/* Get cache line size. */
|
||||
uintptr_t ctr_el0 = 0;
|
||||
__asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0));
|
||||
const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF);
|
||||
|
||||
/* Invalidate the cache. */
|
||||
const uintptr_t start_addr = reinterpret_cast<uintptr_t>(addr) & ~(cache_line_size - 1);
|
||||
const uintptr_t end_addr = reinterpret_cast<uintptr_t>(addr) + size;
|
||||
for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) {
|
||||
__asm__ __volatile__("dc cvac, %[cur]" : : [cur]"r"(cur));
|
||||
}
|
||||
|
||||
/* Add a memory barrier. */
|
||||
__asm__ __volatile__("dsb sy" ::: "memory");
|
||||
#else
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
/* Invoke the relevant svc. */
|
||||
const auto result = svc::StoreProcessDataCache(svc::PseudoHandle::CurrentProcess, reinterpret_cast<uintptr_t>(addr), size);
|
||||
R_ASSERT(result);
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE) && defined(__BPMP__)
|
||||
/* Do nothing. */
|
||||
AMS_UNUSED(addr, size);
|
||||
#else
|
||||
#error "Unknown execution context for ams::dd::impl::StoreDataCacheImpl"
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlushDataCacheImpl(void *addr, size_t size) {
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
/* On aarch64, we can use cache maintenance instructions. */
|
||||
|
||||
/* Get cache line size. */
|
||||
uintptr_t ctr_el0 = 0;
|
||||
__asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0));
|
||||
const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF);
|
||||
|
||||
/* Invalidate the cache. */
|
||||
const uintptr_t start_addr = reinterpret_cast<uintptr_t>(addr) & ~(cache_line_size - 1);
|
||||
const uintptr_t end_addr = reinterpret_cast<uintptr_t>(addr) + size;
|
||||
for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) {
|
||||
__asm__ __volatile__("dc civac, %[cur]" : : [cur]"r"(cur));
|
||||
}
|
||||
|
||||
/* Add a memory barrier. */
|
||||
__asm__ __volatile__("dsb sy" ::: "memory");
|
||||
#else
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
/* Invoke the relevant svc. */
|
||||
const auto result = svc::FlushProcessDataCache(svc::PseudoHandle::CurrentProcess, reinterpret_cast<uintptr_t>(addr), size);
|
||||
R_ASSERT(result);
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE) && defined(__BPMP__)
|
||||
/* Do nothing. */
|
||||
AMS_UNUSED(addr, size);
|
||||
#else
|
||||
#error "Unknown execution context for ams::dd::impl::FlushDataCacheImpl"
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void InvalidateDataCacheImpl(void *addr, size_t size) {
|
||||
/* Just perform a flush, which is clean + invalidate. */
|
||||
return FlushDataCacheImpl(addr, size);
|
||||
}
|
||||
|
||||
}
|
||||
22
libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp
Normal file
22
libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include "dd_cache_impl.os.horizon.hpp"
|
||||
#else
|
||||
#error "Unknown OS for ams::dd::CacheImpl"
|
||||
#endif
|
||||
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "sdmmc_base_device_accessor.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
#if defined(AMS_SDMMC_THREAD_SAFE)
|
||||
|
||||
#define AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX() std::scoped_lock lk(this->base_device->device_mutex)
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX()
|
||||
|
||||
#endif
|
||||
|
||||
void BaseDevice::GetLegacyCapacityParameters(u8 *out_c_size_mult, u8 *out_read_bl_len) const {
|
||||
AMS_ABORT_UNLESS(out_c_size_mult != nullptr);
|
||||
AMS_ABORT_UNLESS(out_read_bl_len != nullptr);
|
||||
|
||||
/* Extract C_SIZE_MULT and READ_BL_LEN from the CSD. */
|
||||
*out_c_size_mult = static_cast<u8>((this->csd[2] >> 7) & 0x7);
|
||||
*out_read_bl_len = static_cast<u8>((this->csd[4] >> 8) & 0xF);
|
||||
}
|
||||
|
||||
Result BaseDevice::SetLegacyMemoryCapacity() {
|
||||
/* Get csize from the csd. */
|
||||
const u32 c_size = ((this->csd[3] >> 6) & 0x3FF) | ((this->csd[4] & 0x3) << 10);
|
||||
|
||||
/* Get c_size_mult and read_bl_len. */
|
||||
u8 c_size_mult, read_bl_len;
|
||||
this->GetLegacyCapacityParameters(std::addressof(c_size_mult), std::addressof(read_bl_len));
|
||||
|
||||
/* Validate the parameters. */
|
||||
R_UNLESS((read_bl_len + c_size_mult + 2) >= 9, sdmmc::ResultUnexpectedDeviceCsdValue());
|
||||
|
||||
/* Set memory capacity. */
|
||||
this->memory_capacity = (c_size + 1) << ((read_bl_len + c_size_mult + 2) - 9);
|
||||
this->is_valid_memory_capacity = true;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDevice::CheckDeviceStatus(u32 r1_resp) const {
|
||||
/* Check if there are any errors at all. */
|
||||
R_SUCCEED_IF((r1_resp & DeviceStatus_ErrorMask) == 0);
|
||||
|
||||
/* Check errors individually. */
|
||||
#define AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(__ERROR__) R_UNLESS((r1_resp & DeviceStatus_##__ERROR__) == 0, sdmmc::ResultDeviceStatus##__ERROR__())
|
||||
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(ComCrcError);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(DeviceEccFailed);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(CcError);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(Error);
|
||||
|
||||
if (this->GetDeviceType() == DeviceType_Mmc) {
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(SwitchError);
|
||||
}
|
||||
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(AddressMisaligned);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(BlockLenError);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(EraseSeqError);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(EraseParam);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(WpViolation);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(LockUnlockFailed);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(CidCsdOverwrite);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(WpEraseSkip);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(WpEraseSkip);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(EraseReset);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(IllegalCommand);
|
||||
AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR(AddressOutOfRange);
|
||||
|
||||
#undef AMS_SDMMC_CHECK_DEVICE_STATUS_ERROR
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
DeviceState BaseDevice::GetDeviceState(u32 r1_resp) const {
|
||||
return static_cast<DeviceState>((r1_resp & DeviceStatus_CurrentStateMask) >> DeviceStatus_CurrentStateShift);
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandAndCheckR1(u32 *out_response, u32 command_index, u32 command_arg, bool is_busy, DeviceState expected_state, u32 status_ignore_mask) const {
|
||||
/* Issue the command. */
|
||||
constexpr ResponseType CommandResponseType = ResponseType_R1;
|
||||
Command command(command_index, command_arg, CommandResponseType, is_busy);
|
||||
R_TRY(this->host_controller->IssueCommand(std::addressof(command)));
|
||||
|
||||
/* Get the response. */
|
||||
AMS_ABORT_UNLESS(out_response != nullptr);
|
||||
this->host_controller->GetLastResponse(out_response, sizeof(u32), CommandResponseType);
|
||||
|
||||
/* Mask out the ignored status bits. */
|
||||
if (status_ignore_mask != 0) {
|
||||
*out_response &= ~status_ignore_mask;
|
||||
}
|
||||
|
||||
/* Check the r1 response for errors. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
R_TRY(this->base_device->CheckDeviceStatus(*out_response));
|
||||
|
||||
/* Check the device state. */
|
||||
if (expected_state != DeviceState_Unknown) {
|
||||
R_UNLESS(this->base_device->GetDeviceState(*out_response) == expected_state, sdmmc::ResultUnexpectedDeviceState());
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandGoIdleState() const {
|
||||
/* Issue the command. */
|
||||
Command command(CommandIndex_GoIdleState, 0, ResponseType_R0, false);
|
||||
return this->host_controller->IssueCommand(std::addressof(command));
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandAllSendCid(void *dst, size_t dst_size) const {
|
||||
/* Issue the command. */
|
||||
constexpr ResponseType CommandResponseType = ResponseType_R2;
|
||||
Command command(CommandIndex_AllSendCid, 0, CommandResponseType, false);
|
||||
R_TRY(this->host_controller->IssueCommand(std::addressof(command)));
|
||||
|
||||
/* Copy the data out. */
|
||||
AMS_ABORT_UNLESS(dst != nullptr);
|
||||
AMS_ABORT_UNLESS(util::IsAligned(reinterpret_cast<uintptr_t>(dst), alignof(u32)));
|
||||
AMS_ABORT_UNLESS(dst_size >= DeviceCidSize);
|
||||
this->host_controller->GetLastResponse(static_cast<u32 *>(dst), DeviceCidSize, CommandResponseType);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandSelectCard() const {
|
||||
/* Get the command argument. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
const u32 arg = static_cast<u32>(this->base_device->GetRca()) << 16;
|
||||
|
||||
/* Issue the command. */
|
||||
return this->IssueCommandAndCheckR1(CommandIndex_SelectCard, arg, true, DeviceState_Unknown);
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandSendCsd(void *dst, size_t dst_size) const {
|
||||
/* Get the command argument. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
const u32 arg = static_cast<u32>(this->base_device->GetRca()) << 16;
|
||||
|
||||
/* Issue the command. */
|
||||
constexpr ResponseType CommandResponseType = ResponseType_R2;
|
||||
Command command(CommandIndex_SendCsd, arg, CommandResponseType, false);
|
||||
R_TRY(this->host_controller->IssueCommand(std::addressof(command)));
|
||||
|
||||
/* Copy the data out. */
|
||||
AMS_ABORT_UNLESS(dst != nullptr);
|
||||
AMS_ABORT_UNLESS(util::IsAligned(reinterpret_cast<uintptr_t>(dst), alignof(u32)));
|
||||
AMS_ABORT_UNLESS(dst_size >= DeviceCsdSize);
|
||||
this->host_controller->GetLastResponse(static_cast<u32 *>(dst), DeviceCsdSize, CommandResponseType);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandSendStatus(u32 *out_device_status, u32 status_ignore_mask) const {
|
||||
/* Get the command argument. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
const u32 arg = static_cast<u32>(this->base_device->GetRca()) << 16;
|
||||
|
||||
/* Issue the command. */
|
||||
return this->IssueCommandAndCheckR1(out_device_status, CommandIndex_SendStatus, arg, false, DeviceState_Tran, status_ignore_mask);
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandSetBlockLenToSectorSize() const {
|
||||
/* Issue the command. */
|
||||
return this->IssueCommandAndCheckR1(CommandIndex_SetBlockLen, SectorSize, false, DeviceState_Tran);
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::IssueCommandMultipleBlock(u32 *out_num_transferred_blocks, u32 sector_index, u32 num_sectors, void *buf, bool is_read) const {
|
||||
/* Get the argument. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
const u32 arg = this->base_device->IsHighCapacity() ? sector_index : sector_index * SectorSize;
|
||||
|
||||
/* Get the command index and transfer direction. */
|
||||
const u32 command_index = is_read ? CommandIndex_ReadMultipleBlock : CommandIndex_WriteMultipleBlock;
|
||||
const auto xfer_direction = is_read ? TransferDirection_ReadFromDevice : TransferDirection_WriteToDevice;
|
||||
|
||||
/* Issue the command. */
|
||||
constexpr ResponseType CommandResponseType = ResponseType_R1;
|
||||
Command command(command_index, arg, CommandResponseType, false);
|
||||
TransferData xfer_data(buf, SectorSize, num_sectors, xfer_direction, true, true);
|
||||
Result result = this->host_controller->IssueCommand(std::addressof(command), std::addressof(xfer_data), out_num_transferred_blocks);
|
||||
|
||||
/* Handle the failure case. */
|
||||
if (R_FAILED(result)) {
|
||||
/* Check if we were removed. */
|
||||
R_TRY(this->CheckRemoved());
|
||||
|
||||
/* By default, we'll want to return the result we just got. */
|
||||
Result result_to_return = result;
|
||||
|
||||
/* Stop transmission. */
|
||||
u32 resp = 0;
|
||||
result = this->host_controller->IssueStopTransmissionCommand(std::addressof(resp));
|
||||
if (R_SUCCEEDED(result)) {
|
||||
result = this->base_device->CheckDeviceStatus(resp & (~DeviceStatus_IllegalCommand));
|
||||
if (R_FAILED(result)) {
|
||||
result_to_return = result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we were removed. */
|
||||
R_TRY(this->CheckRemoved());
|
||||
|
||||
/* Get the device status. */
|
||||
u32 device_status = 0;
|
||||
result = this->IssueCommandSendStatus(std::addressof(device_status), DeviceStatus_IllegalCommand);
|
||||
|
||||
/* If there's a device status error we don't already have, we prefer to return it. */
|
||||
if (!sdmmc::ResultDeviceStatusHasError::Includes(result_to_return) && sdmmc::ResultDeviceStatusHasError::Includes(result)) {
|
||||
result_to_return = result;
|
||||
}
|
||||
|
||||
/* Return the result we chose. */
|
||||
return result_to_return;
|
||||
}
|
||||
|
||||
/* Get the responses. */
|
||||
u32 resp, st_resp;
|
||||
this->host_controller->GetLastResponse(std::addressof(resp), sizeof(resp), CommandResponseType);
|
||||
this->host_controller->GetLastStopTransmissionResponse(std::addressof(st_resp), sizeof(st_resp));
|
||||
|
||||
/* Check the device status. */
|
||||
R_TRY(this->base_device->CheckDeviceStatus(resp));
|
||||
|
||||
/* Decide on what errors to ignore. */
|
||||
u32 status_ignore_mask = 0;
|
||||
if (is_read) {
|
||||
AMS_ABORT_UNLESS(out_num_transferred_blocks != nullptr);
|
||||
if ((*out_num_transferred_blocks + sector_index) == this->base_device->GetMemoryCapacity()) {
|
||||
status_ignore_mask = DeviceStatus_AddressOutOfRange;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the device status. */
|
||||
R_TRY(this->base_device->CheckDeviceStatus(st_resp & ~status_ignore_mask));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::ReadWriteSingle(u32 *out_num_transferred_blocks, u32 sector_index, u32 num_sectors, void *buf, bool is_read) const {
|
||||
/* Issue the read/write command. */
|
||||
AMS_ABORT_UNLESS(out_num_transferred_blocks != nullptr);
|
||||
R_TRY(this->IssueCommandMultipleBlock(out_num_transferred_blocks, sector_index, num_sectors, buf, is_read));
|
||||
|
||||
/* Decide on what errors to ignore. */
|
||||
u32 status_ignore_mask = 0;
|
||||
if (is_read) {
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
if ((*out_num_transferred_blocks + sector_index) == this->base_device->GetMemoryCapacity()) {
|
||||
status_ignore_mask = DeviceStatus_AddressOutOfRange;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get and check the status. */
|
||||
u32 device_status;
|
||||
R_TRY(this->IssueCommandSendStatus(std::addressof(device_status), status_ignore_mask));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::ReadWriteMultiple(u32 sector_index, u32 num_sectors, u32 sector_index_alignment, void *buf, size_t buf_size, bool is_read) {
|
||||
/* Verify that we can send the command. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
|
||||
/* If we want to read zero sectors, there's no work for us to do. */
|
||||
R_SUCCEED_IF(num_sectors == 0);
|
||||
|
||||
/* Check that the buffer is big enough for the sectors we're reading. */
|
||||
AMS_ABORT_UNLESS((buf_size / SectorSize) >= num_sectors);
|
||||
|
||||
/* Read sectors repeatedly until we've read all the ones we want. */
|
||||
u32 cur_sector_index = sector_index;
|
||||
u32 remaining_sectors = num_sectors;
|
||||
u8 *cur_buf = static_cast<u8 *>(buf);
|
||||
while (remaining_sectors > 0) {
|
||||
/* Determine how many sectors we can read in this iteration. */
|
||||
u32 cur_sectors = remaining_sectors;
|
||||
if (sector_index_alignment > 0) {
|
||||
AMS_ABORT_UNLESS((cur_sector_index % sector_index_alignment) == 0);
|
||||
|
||||
const u32 max_sectors = this->host_controller->GetMaxTransferNumBlocks();
|
||||
if (remaining_sectors > max_sectors) {
|
||||
cur_sectors = max_sectors - (max_sectors % sector_index_alignment);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to perform the read/write. */
|
||||
u32 num_transferred_blocks = 0;
|
||||
Result result = this->ReadWriteSingle(std::addressof(num_transferred_blocks), cur_sector_index, cur_sectors, cur_buf, is_read);
|
||||
if (R_FAILED(result)) {
|
||||
/* Check if we were removed. */
|
||||
R_TRY(this->CheckRemoved());
|
||||
|
||||
/* Log that we failed to read/write. */
|
||||
this->PushErrorLog(false, "%s %X %X:%X", is_read ? "R" : "W", cur_sector_index, cur_sectors, result.GetValue());
|
||||
|
||||
/* Retry the read/write. */
|
||||
num_transferred_blocks = 0;
|
||||
result = this->ReadWriteSingle(std::addressof(num_transferred_blocks), cur_sector_index, cur_sectors, cur_buf, is_read);
|
||||
if (R_FAILED(result)) {
|
||||
/* Check if we were removed. */
|
||||
R_TRY(this->CheckRemoved());
|
||||
|
||||
/* Log that we failed to read/write. */
|
||||
this->PushErrorLog(false, "%s %X %X:%X", is_read ? "R" : "W", cur_sector_index, cur_sectors, result.GetValue());
|
||||
|
||||
/* Re-startup the connection, to see if that helps. */
|
||||
R_TRY(this->ReStartup());
|
||||
|
||||
/* Retry the read/write a third time. */
|
||||
num_transferred_blocks = 0;
|
||||
result = this->ReadWriteSingle(std::addressof(num_transferred_blocks), cur_sector_index, cur_sectors, cur_buf, is_read);
|
||||
if (R_FAILED(result)) {
|
||||
/* Log that we failed after a re-startup. */
|
||||
this->PushErrorLog(true, "%s %X %X:%X", is_read ? "R" : "W", cur_sector_index, cur_sectors, result.GetValue());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Log that we succeeded after a retry. */
|
||||
this->PushErrorLog(true, "%s %X %X:0", is_read ? "R" : "W", cur_sector_index, cur_sectors);
|
||||
|
||||
/* Increment the number of error corrections we've done. */
|
||||
++this->num_read_write_error_corrections;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update our tracking variables. */
|
||||
AMS_ABORT_UNLESS(remaining_sectors >= num_transferred_blocks);
|
||||
remaining_sectors -= num_transferred_blocks;
|
||||
cur_sector_index += num_transferred_blocks;
|
||||
cur_buf += num_transferred_blocks * SectorSize;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS)
|
||||
void BaseDeviceAccessor::RegisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Register the address. */
|
||||
return this->host_controller->RegisterDeviceVirtualAddress(buffer, buffer_size, buffer_device_virtual_address);
|
||||
}
|
||||
|
||||
void BaseDeviceAccessor::UnregisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Register the address. */
|
||||
return this->host_controller->UnregisterDeviceVirtualAddress(buffer, buffer_size, buffer_device_virtual_address);
|
||||
}
|
||||
#endif
|
||||
|
||||
Result BaseDeviceAccessor::Activate() {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is awake. */
|
||||
R_UNLESS(this->base_device->IsAwake(), sdmmc::ResultNotAwakened());
|
||||
|
||||
/* If the device is already active, we don't need to do anything. */
|
||||
R_SUCCEED_IF(this->base_device->IsActive());
|
||||
|
||||
/* Activate the base device. */
|
||||
auto activate_guard = SCOPE_GUARD { ++this->num_activation_failures; };
|
||||
R_TRY(this->OnActivate());
|
||||
|
||||
/* We successfully activated the device. */
|
||||
activate_guard.Cancel();
|
||||
this->base_device->SetActive();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void BaseDeviceAccessor::Deactivate() {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Deactivate the base device. */
|
||||
if (this->base_device->IsActive()) {
|
||||
this->host_controller->Shutdown();
|
||||
this->base_device->Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::ReadWrite(u32 sector_index, u32 num_sectors, void *buffer, size_t buffer_size, bool is_read) {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Perform the read/write. */
|
||||
auto rw_guard = SCOPE_GUARD { ++this->num_read_write_failures; };
|
||||
R_TRY(this->OnReadWrite(sector_index, num_sectors, buffer, buffer_size, is_read));
|
||||
|
||||
/* We successfully performed the read/write. */
|
||||
rw_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width) {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the current speed mode/bus width. */
|
||||
*out_speed_mode = this->host_controller->GetSpeedMode();
|
||||
*out_bus_width = this->host_controller->GetBusWidth();
|
||||
|
||||
/* Verify that we can get the status. */
|
||||
R_TRY(this->host_controller->GetInternalStatus());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetMemoryCapacity(u32 *out_sectors) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the capacity. */
|
||||
AMS_ABORT_UNLESS(out_sectors != nullptr);
|
||||
*out_sectors = this->base_device->GetMemoryCapacity();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetDeviceStatus(u32 *out) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the status. */
|
||||
R_TRY(this->IssueCommandSendStatus(out, 0));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetOcr(u32 *out) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the ocr. */
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
*out = this->base_device->GetOcr();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetRca(u16 *out) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the rca. */
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
*out = this->base_device->GetRca();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetCid(void *out, size_t size) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the cid. */
|
||||
this->base_device->GetCid(out, size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result BaseDeviceAccessor::GetCsd(void *out, size_t size) const {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Check that the device is accessible. */
|
||||
R_TRY(this->base_device->CheckAccessible());
|
||||
|
||||
/* Get the csd. */
|
||||
this->base_device->GetCsd(out, size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void BaseDeviceAccessor::GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) {
|
||||
/* Lock exclusive access of the base device. */
|
||||
AMS_ABORT_UNLESS(this->base_device != nullptr);
|
||||
AMS_SDMMC_LOCK_BASE_DEVICE_MUTEX();
|
||||
|
||||
/* Set the output error info. */
|
||||
AMS_ABORT_UNLESS(out_error_info != nullptr);
|
||||
out_error_info->num_activation_failures = this->num_activation_failures;
|
||||
out_error_info->num_activation_error_corrections = this->num_activation_error_corrections;
|
||||
out_error_info->num_read_write_failures = this->num_read_write_failures;
|
||||
out_error_info->num_read_write_error_corrections = this->num_read_write_error_corrections;
|
||||
this->ClearErrorInfo();
|
||||
|
||||
/* Check if we should write logs. */
|
||||
if (out_log_size == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we can write logs. */
|
||||
if (out_log_buffer == nullptr || log_buffer_size == 0) {
|
||||
*out_log_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get and clear our logs. */
|
||||
#if defined(AMS_SDMMC_USE_LOGGER)
|
||||
{
|
||||
if (this->error_logger.HasLog()) {
|
||||
this->PushErrorTimeStamp();
|
||||
|
||||
*out_log_size = this->error_logger.GetAndClearLogs(out_log_buffer, log_buffer_size);
|
||||
} else {
|
||||
*out_log_size = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
*out_log_size = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_i_host_controller.hpp"
|
||||
#include "sdmmc_i_device_accessor.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
#if defined(AMS_SDMMC_USE_LOGGER)
|
||||
class Logger {
|
||||
private:
|
||||
static constexpr size_t LogLengthMax = 0x20;
|
||||
static constexpr size_t LogCountMax = 0x10;
|
||||
private:
|
||||
char logs[LogCountMax][LogLengthMax];
|
||||
int log_index;
|
||||
private:
|
||||
void Clear() {
|
||||
for (size_t i = 0; i < LogCountMax; ++i) {
|
||||
this->logs[i][0] = '\0';
|
||||
}
|
||||
this->log_index = 0;
|
||||
}
|
||||
|
||||
size_t Pop(char *dst, size_t dst_size) {
|
||||
/* Decrease log index. */
|
||||
if ((--this->log_index) < 0) {
|
||||
this->log_index = LogCountMax - 1;
|
||||
}
|
||||
|
||||
/* Check if we have a log. */
|
||||
if (this->logs[this->log_index][0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy log to output. */
|
||||
const int len = ::ams::util::Strlcpy(dst, this->logs[this->log_index], dst_size);
|
||||
|
||||
/* Clear the log we copied. */
|
||||
this->logs[this->log_index][0] = '\0';
|
||||
|
||||
return static_cast<size_t>(len);
|
||||
}
|
||||
|
||||
public:
|
||||
Logger() {
|
||||
this->Clear();
|
||||
}
|
||||
|
||||
void Push(const char *fmt, std::va_list vl) {
|
||||
/* Format the log into the current buffer. */
|
||||
::ams::util::TVSNPrintf(this->logs[this->log_index], LogLengthMax, fmt, vl);
|
||||
|
||||
/* Update our log index. */
|
||||
if ((++this->log_index) >= static_cast<int>(LogCountMax)) {
|
||||
this->log_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Push(const char *fmt, ...) {
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
this->Push(fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
bool HasLog() const {
|
||||
const int index = this->log_index > 0 ? this->log_index - 1 : static_cast<int>(LogCountMax - 1);
|
||||
return this->logs[index][0] != '\0';
|
||||
}
|
||||
|
||||
size_t GetAndClearLogs(char *dst, size_t dst_size) {
|
||||
AMS_ABORT_UNLESS(dst != nullptr);
|
||||
AMS_ABORT_UNLESS(dst_size > 0);
|
||||
|
||||
/* Pop logs until we run out of them. */
|
||||
size_t total_len = 0;
|
||||
while (true) {
|
||||
/* Pop the current log. */
|
||||
const size_t cur_len = this->Pop(dst + total_len, dst_size - total_len);
|
||||
if (cur_len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if the log exceeded the buffer size. */
|
||||
if (total_len + cur_len + 1 >= dst_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance the total length. */
|
||||
total_len += cur_len;
|
||||
|
||||
/* Check if there's space for our separator. */
|
||||
if (total_len + 3 >= dst_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst[total_len + 0] = ',';
|
||||
dst[total_len + 1] = ' ';
|
||||
total_len += 2;
|
||||
}
|
||||
|
||||
/* Ensure that the complete log fits in the buffer. */
|
||||
if (total_len >= dst_size) {
|
||||
total_len = dst_size - 1;
|
||||
}
|
||||
|
||||
/* Ensure null termination. */
|
||||
dst[total_len] = '\0';
|
||||
|
||||
/* Clear any remaining logs. */
|
||||
this->Clear();
|
||||
|
||||
/* Return the length of the logs, including null terminator. */
|
||||
return total_len + 1;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
enum DeviceType {
|
||||
DeviceType_Mmc = 0,
|
||||
DeviceType_SdCard = 1,
|
||||
DeviceType_GcAsic = 2,
|
||||
};
|
||||
|
||||
enum DeviceState {
|
||||
DeviceState_Idle = 0,
|
||||
DeviceState_Ready = 1,
|
||||
DeviceState_Ident = 2,
|
||||
DeviceState_Stby = 3,
|
||||
DeviceState_Tran = 4,
|
||||
DeviceState_Data = 5,
|
||||
DeviceState_Rcv = 6,
|
||||
DeviceState_Prg = 7,
|
||||
DeviceState_Dis = 8,
|
||||
DeviceState_Rsvd0 = 9,
|
||||
DeviceState_Rsvd1 = 10,
|
||||
DeviceState_Rsvd2 = 11,
|
||||
DeviceState_Rsvd3 = 12,
|
||||
DeviceState_Rsvd4 = 13,
|
||||
DeviceState_Rsvd5 = 14,
|
||||
DeviceState_RsvdIoMode = 15,
|
||||
DeviceState_Unknown = 16,
|
||||
};
|
||||
|
||||
enum DeviceStatus : u32 {
|
||||
DeviceStatus_AkeSeqError = (1u << 3),
|
||||
DeviceStatus_AppCmd = (1u << 5),
|
||||
DeviceStatus_SwitchError = (1u << 7),
|
||||
DeviceStatus_EraseReset = (1u << 13),
|
||||
DeviceStatus_WpEraseSkip = (1u << 15),
|
||||
DeviceStatus_CidCsdOverwrite = (1u << 16),
|
||||
DeviceStatus_Error = (1u << 19),
|
||||
DeviceStatus_CcError = (1u << 20),
|
||||
DeviceStatus_DeviceEccFailed = (1u << 21),
|
||||
DeviceStatus_IllegalCommand = (1u << 22),
|
||||
DeviceStatus_ComCrcError = (1u << 23),
|
||||
DeviceStatus_LockUnlockFailed = (1u << 24),
|
||||
DeviceStatus_WpViolation = (1u << 26),
|
||||
DeviceStatus_EraseParam = (1u << 27),
|
||||
DeviceStatus_EraseSeqError = (1u << 28),
|
||||
DeviceStatus_BlockLenError = (1u << 29),
|
||||
DeviceStatus_AddressMisaligned = (1u << 30),
|
||||
DeviceStatus_AddressOutOfRange = (1u << 31),
|
||||
|
||||
DeviceStatus_CurrentStateShift = 9,
|
||||
DeviceStatus_CurrentStateMask = (0b1111u << DeviceStatus_CurrentStateShift),
|
||||
|
||||
DeviceStatus_ErrorMask = (DeviceStatus_SwitchError |
|
||||
DeviceStatus_EraseReset |
|
||||
DeviceStatus_WpEraseSkip |
|
||||
DeviceStatus_CidCsdOverwrite |
|
||||
DeviceStatus_Error |
|
||||
DeviceStatus_CcError |
|
||||
DeviceStatus_DeviceEccFailed |
|
||||
DeviceStatus_IllegalCommand |
|
||||
DeviceStatus_ComCrcError |
|
||||
DeviceStatus_LockUnlockFailed |
|
||||
DeviceStatus_WpViolation |
|
||||
DeviceStatus_EraseParam |
|
||||
DeviceStatus_EraseSeqError |
|
||||
DeviceStatus_BlockLenError |
|
||||
DeviceStatus_AddressMisaligned |
|
||||
DeviceStatus_AddressOutOfRange),
|
||||
};
|
||||
|
||||
class BaseDevice {
|
||||
private:
|
||||
u32 ocr;
|
||||
u8 cid[DeviceCidSize];
|
||||
u16 csd[DeviceCsdSize / sizeof(u16)];
|
||||
u32 memory_capacity;
|
||||
bool is_high_capacity;
|
||||
bool is_valid_ocr;
|
||||
bool is_valid_cid;
|
||||
bool is_valid_csd;
|
||||
bool is_valid_high_capacity;
|
||||
bool is_valid_memory_capacity;
|
||||
bool is_active;
|
||||
bool is_awake;
|
||||
public:
|
||||
#if defined(AMS_SDMMC_THREAD_SAFE)
|
||||
mutable os::Mutex device_mutex;
|
||||
public:
|
||||
BaseDevice() : device_mutex(true)
|
||||
#else
|
||||
BaseDevice()
|
||||
#endif
|
||||
{
|
||||
this->is_awake = true;
|
||||
this->ocr = 0;
|
||||
this->memory_capacity = 0;
|
||||
this->is_high_capacity = false;
|
||||
this->OnDeactivate();
|
||||
}
|
||||
|
||||
void OnDeactivate() {
|
||||
this->is_active = false;
|
||||
this->is_valid_ocr = false;
|
||||
this->is_valid_cid = false;
|
||||
this->is_valid_csd = false;
|
||||
this->is_valid_high_capacity = false;
|
||||
this->is_valid_memory_capacity = false;
|
||||
}
|
||||
|
||||
bool IsAwake() const {
|
||||
return this->is_awake;
|
||||
}
|
||||
|
||||
void Awaken() {
|
||||
this->is_awake = true;
|
||||
}
|
||||
|
||||
void PutToSleep() {
|
||||
this->is_awake = false;
|
||||
}
|
||||
|
||||
bool IsActive() const {
|
||||
return this->is_active;
|
||||
}
|
||||
|
||||
void SetActive() {
|
||||
this->is_active = true;
|
||||
}
|
||||
|
||||
virtual void Deactivate() {
|
||||
this->OnDeactivate();
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
virtual os::EventType *GetRemovedEvent() const = 0;
|
||||
#endif
|
||||
|
||||
virtual DeviceType GetDeviceType() const = 0;
|
||||
virtual u16 GetRca() const = 0;
|
||||
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
void InitializeRemovedEvent() {
|
||||
if (os::EventType *removed_event = this->GetRemovedEvent(); removed_event != nullptr) {
|
||||
os::InitializeEvent(removed_event, false, os::EventClearMode_ManualClear);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeRemovedEvent() {
|
||||
if (os::EventType *removed_event = this->GetRemovedEvent(); removed_event != nullptr) {
|
||||
os::FinalizeEvent(removed_event);
|
||||
}
|
||||
}
|
||||
|
||||
void SignalRemovedEvent() {
|
||||
if (os::EventType *removed_event = this->GetRemovedEvent(); removed_event != nullptr) {
|
||||
os::SignalEvent(removed_event);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearRemovedEvent() {
|
||||
if (os::EventType *removed_event = this->GetRemovedEvent(); removed_event != nullptr) {
|
||||
os::ClearEvent(removed_event);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRemoved() const {
|
||||
if (os::EventType *removed_event = this->GetRemovedEvent(); removed_event != nullptr) {
|
||||
return os::TryWaitEvent(removed_event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Result CheckRemoved() const {
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
R_UNLESS(!this->IsRemoved(), sdmmc::ResultDeviceRemoved());
|
||||
#endif
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CheckAccessible() const {
|
||||
/* Check awake. */
|
||||
R_UNLESS(this->IsAwake(), sdmmc::ResultNotAwakened());
|
||||
|
||||
/* Check active. */
|
||||
R_UNLESS(this->IsActive(), sdmmc::ResultNotActivated());
|
||||
|
||||
/* Check removed. */
|
||||
R_TRY(this->CheckRemoved());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void SetHighCapacity(bool en) {
|
||||
this->is_high_capacity = en;
|
||||
this->is_valid_high_capacity = true;
|
||||
}
|
||||
|
||||
bool IsHighCapacity() const {
|
||||
AMS_ABORT_UNLESS(this->is_valid_high_capacity);
|
||||
return this->is_high_capacity;
|
||||
}
|
||||
|
||||
void SetOcr(u32 o) {
|
||||
this->ocr = o;
|
||||
this->is_valid_ocr = true;
|
||||
}
|
||||
|
||||
u32 GetOcr() const {
|
||||
AMS_ABORT_UNLESS(this->is_valid_ocr);
|
||||
return this->ocr;
|
||||
}
|
||||
|
||||
void SetCid(const void *src, size_t src_size) {
|
||||
AMS_ABORT_UNLESS(src != nullptr);
|
||||
AMS_ABORT_UNLESS(src_size >= DeviceCidSize);
|
||||
std::memcpy(this->cid, src, DeviceCidSize);
|
||||
this->is_valid_cid = true;
|
||||
}
|
||||
|
||||
void GetCid(void *dst, size_t dst_size) const {
|
||||
AMS_ABORT_UNLESS(this->is_valid_cid);
|
||||
AMS_ABORT_UNLESS(dst != nullptr);
|
||||
AMS_ABORT_UNLESS(dst_size >= DeviceCidSize);
|
||||
std::memcpy(dst, this->cid, DeviceCidSize);
|
||||
}
|
||||
|
||||
void SetCsd(const void *src, size_t src_size) {
|
||||
AMS_ABORT_UNLESS(src != nullptr);
|
||||
AMS_ABORT_UNLESS(src_size >= DeviceCsdSize);
|
||||
std::memcpy(this->csd, src, DeviceCsdSize);
|
||||
this->is_valid_csd = true;
|
||||
}
|
||||
|
||||
void GetCsd(void *dst, size_t dst_size) const {
|
||||
AMS_ABORT_UNLESS(this->is_valid_csd);
|
||||
AMS_ABORT_UNLESS(dst != nullptr);
|
||||
AMS_ABORT_UNLESS(dst_size >= DeviceCsdSize);
|
||||
std::memcpy(dst, this->csd, DeviceCsdSize);
|
||||
}
|
||||
|
||||
void SetMemoryCapacity(u32 num_sectors) {
|
||||
this->memory_capacity = num_sectors;
|
||||
this->is_valid_memory_capacity = true;
|
||||
}
|
||||
|
||||
u32 GetMemoryCapacity() const {
|
||||
AMS_ABORT_UNLESS(this->is_valid_memory_capacity);
|
||||
return this->memory_capacity;
|
||||
}
|
||||
|
||||
void GetLegacyCapacityParameters(u8 *out_c_size_mult, u8 *out_read_bl_len) const;
|
||||
Result SetLegacyMemoryCapacity();
|
||||
|
||||
Result CheckDeviceStatus(u32 r1_resp) const;
|
||||
DeviceState GetDeviceState(u32 r1_resp) const;
|
||||
};
|
||||
|
||||
class BaseDeviceAccessor : public IDeviceAccessor {
|
||||
private:
|
||||
IHostController *host_controller;
|
||||
BaseDevice *base_device;
|
||||
u32 num_activation_failures;
|
||||
u32 num_activation_error_corrections;
|
||||
u32 num_read_write_failures;
|
||||
u32 num_read_write_error_corrections;
|
||||
#if defined(AMS_SDMMC_USE_LOGGER)
|
||||
Logger error_logger;
|
||||
#endif
|
||||
private:
|
||||
void ClearErrorInfo() {
|
||||
this->num_activation_failures = 0;
|
||||
this->num_activation_error_corrections = 0;
|
||||
this->num_read_write_failures = 0;
|
||||
this->num_read_write_error_corrections = 0;
|
||||
}
|
||||
protected:
|
||||
explicit BaseDeviceAccessor(IHostController *hc) : host_controller(hc), base_device(nullptr) {
|
||||
this->ClearErrorInfo();
|
||||
}
|
||||
|
||||
IHostController *GetHostController() const {
|
||||
return this->host_controller;
|
||||
}
|
||||
|
||||
void SetDevice(BaseDevice *bd) {
|
||||
this->base_device = bd;
|
||||
}
|
||||
|
||||
Result CheckRemoved() const {
|
||||
return this->base_device->CheckRemoved();
|
||||
}
|
||||
|
||||
Result IssueCommandAndCheckR1(u32 *out_response, u32 command_index, u32 command_arg, bool is_busy, DeviceState expected_state, u32 status_ignore_mask) const;
|
||||
|
||||
Result IssueCommandAndCheckR1(u32 command_index, u32 command_arg, bool is_busy, DeviceState expected_state, u32 status_ignore_mask) const {
|
||||
u32 dummy;
|
||||
return this->IssueCommandAndCheckR1(std::addressof(dummy), command_index, command_arg, is_busy, expected_state, status_ignore_mask);
|
||||
}
|
||||
|
||||
Result IssueCommandAndCheckR1(u32 command_index, u32 command_arg, bool is_busy, DeviceState expected_state) const {
|
||||
return this->IssueCommandAndCheckR1(command_index, command_arg, is_busy, expected_state, 0);
|
||||
}
|
||||
|
||||
Result IssueCommandGoIdleState() const;
|
||||
Result IssueCommandAllSendCid(void *dst, size_t dst_size) const;
|
||||
Result IssueCommandSelectCard() const;
|
||||
Result IssueCommandSendCsd(void *dst, size_t dst_size) const;
|
||||
Result IssueCommandSendStatus(u32 *out_device_status, u32 status_ignore_mask) const;
|
||||
|
||||
Result IssueCommandSendStatus(u32 status_ignore_mask) const {
|
||||
u32 dummy;
|
||||
return this->IssueCommandSendStatus(std::addressof(dummy), status_ignore_mask);
|
||||
}
|
||||
|
||||
Result IssueCommandSendStatus() const {
|
||||
return this->IssueCommandSendStatus(0);
|
||||
}
|
||||
|
||||
Result IssueCommandSetBlockLenToSectorSize() const;
|
||||
Result IssueCommandMultipleBlock(u32 *out_num_transferred_blocks, u32 sector_index, u32 num_sectors, void *buf, bool is_read) const;
|
||||
Result ReadWriteSingle(u32 *out_num_transferred_blocks, u32 sector_index, u32 num_sectors, void *buf, bool is_read) const;
|
||||
Result ReadWriteMultiple(u32 sector_index, u32 num_sectors, u32 sector_index_alignment, void *buf, size_t buf_size, bool is_read);
|
||||
|
||||
void IncrementNumActivationErrorCorrections() {
|
||||
++this->num_activation_error_corrections;
|
||||
}
|
||||
|
||||
void PushErrorTimeStamp() {
|
||||
#if defined(AMS_SDMMC_USE_LOGGER)
|
||||
{
|
||||
this->error_logger.Push("%u", static_cast<u32>(os::ConvertToTimeSpan(os::GetSystemTick()).GetSeconds()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushErrorLog(bool with_timestamp, const char *fmt, ...) {
|
||||
#if defined(AMS_SDMMC_USE_LOGGER)
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
this->error_logger.Push(fmt, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (with_timestamp) {
|
||||
this->PushErrorTimeStamp();
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
AMS_UNUSED(with_timestamp, fmt);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual Result OnActivate() = 0;
|
||||
virtual Result OnReadWrite(u32 sector_index, u32 num_sectors, void *buf, size_t buf_size, bool is_read) = 0;
|
||||
virtual Result ReStartup() = 0;
|
||||
public:
|
||||
#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS)
|
||||
virtual void RegisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) override;
|
||||
virtual void UnregisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) override;
|
||||
#endif
|
||||
|
||||
virtual Result Activate() override;
|
||||
virtual void Deactivate() override;
|
||||
|
||||
virtual Result ReadWrite(u32 sector_index, u32 num_sectors, void *buffer, size_t buffer_size, bool is_read) override;
|
||||
virtual Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width) override;
|
||||
|
||||
virtual Result GetMemoryCapacity(u32 *out_sectors) const override;
|
||||
virtual Result GetDeviceStatus(u32 *out) const override;
|
||||
virtual Result GetOcr(u32 *out) const override;
|
||||
virtual Result GetRca(u16 *out) const override;
|
||||
virtual Result GetCid(void *out, size_t size) const override;
|
||||
virtual Result GetCsd(void *out, size_t size) const override;
|
||||
|
||||
virtual void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "sdmmc_clock_reset_controller.hpp"
|
||||
#include "sdmmc_clock_reset_controller.reg.board.nintendo_nx.hpp"
|
||||
#include "sdmmc_clock_reset_controller.pcv.board.nintendo_nx.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit bool g_is_module_initialized[Module_Count] = {};
|
||||
|
||||
#if defined(AMS_SDMMC_THREAD_SAFE)
|
||||
|
||||
constinit os::SdkMutex g_module_mutex;
|
||||
|
||||
#define AMS_SDMMC_LOCK_MODULE_MUTEX() std::scoped_lock lk(g_module_mutex)
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_LOCK_MODULE_MUTEX()
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
constinit bool g_is_pcv_control = false;
|
||||
|
||||
#define AMS_SDMMC_IF_IS_PCV_CONTROL() if (g_is_pcv_control)
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_IF_IS_PCV_CONTROL() if constexpr (false)
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void Initialize(Module module) {
|
||||
/* Acquire exclusive access to module state. */
|
||||
AMS_SDMMC_LOCK_MODULE_MUTEX();
|
||||
|
||||
/* Mark the module as initialized. */
|
||||
g_is_module_initialized[module] = true;
|
||||
|
||||
/* Initialize the module. */
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
ClockResetController::pcv::Initialize(module);
|
||||
} else {
|
||||
ClockResetController::reg::Initialize(module);
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize(Module module) {
|
||||
/* Acquire exclusive access to module state. */
|
||||
AMS_SDMMC_LOCK_MODULE_MUTEX();
|
||||
|
||||
/* Finalize the module. */
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
ClockResetController::pcv::Finalize(module);
|
||||
} else {
|
||||
ClockResetController::reg::Finalize(module);
|
||||
}
|
||||
|
||||
/* Mark the module as finalized. */
|
||||
g_is_module_initialized[module] = false;
|
||||
}
|
||||
|
||||
bool IsAvailable(Module module) {
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
return ClockResetController::pcv::IsAvailable(module);
|
||||
} else {
|
||||
return ClockResetController::reg::IsAvailable(module);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
void SwitchToPcvControl() {
|
||||
/* Acquire exclusive access to module state. */
|
||||
AMS_SDMMC_LOCK_MODULE_MUTEX();
|
||||
|
||||
/* If we're already using pcv control, we don't need to do anything. */
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finalize all modules. */
|
||||
for (int i = 0; i < Module_Count; ++i) {
|
||||
if (g_is_module_initialized[i]) {
|
||||
ClockResetController::reg::Finalize(static_cast<Module>(i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark that we've switched to pcv control. */
|
||||
|
||||
/* Initialize modules using pcv control. */
|
||||
for (int i = 0; i < Module_Count; ++i) {
|
||||
if (g_is_module_initialized[i]) {
|
||||
ClockResetController::pcv::Initialize(static_cast<Module>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency) {
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
return ClockResetController::pcv::SetClockFrequencyKHz(out_actual_frequency, module, target_frequency);
|
||||
} else {
|
||||
return ClockResetController::reg::SetClockFrequencyKHz(out_actual_frequency, module, target_frequency);
|
||||
}
|
||||
}
|
||||
|
||||
void AssertReset(Module module) {
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
return ClockResetController::pcv::AssertReset(module);
|
||||
} else {
|
||||
return ClockResetController::reg::AssertReset(module);
|
||||
}
|
||||
}
|
||||
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz) {
|
||||
AMS_SDMMC_IF_IS_PCV_CONTROL() {
|
||||
return ClockResetController::pcv::ReleaseReset(module, target_frequency_khz);
|
||||
} else {
|
||||
return ClockResetController::reg::ReleaseReset(module, target_frequency_khz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController {
|
||||
|
||||
enum Module {
|
||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
|
||||
Module_Sdmmc1 = 0,
|
||||
Module_Sdmmc2 = 1,
|
||||
Module_Sdmmc3 = 2,
|
||||
Module_Sdmmc4 = 3,
|
||||
#endif
|
||||
|
||||
Module_Count,
|
||||
};
|
||||
|
||||
void Initialize(Module module);
|
||||
void Finalize(Module module);
|
||||
bool IsAvailable(Module module);
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
void SwitchToPcvControl();
|
||||
#endif
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency);
|
||||
void AssertReset(Module module);
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "sdmmc_clock_reset_controller.pcv.board.nintendo_nx.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController::pcv {
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
|
||||
void Initialize(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
void Finalize(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
bool IsAvailable(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency) {
|
||||
AMS_UNUSED(out_actual_frequency, module, target_frequency);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
void AssertReset(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz) {
|
||||
AMS_UNUSED(module, target_frequency_khz);
|
||||
AMS_ABORT("PCV Control not implemented");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void Initialize(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
void Finalize(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
bool IsAvailable(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency) {
|
||||
AMS_UNUSED(out_actual_frequency, module, target_frequency);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
void AssertReset(Module module) {
|
||||
AMS_UNUSED(module);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz) {
|
||||
AMS_UNUSED(module, target_frequency_khz);
|
||||
AMS_ABORT("PCV Control not supported");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_clock_reset_controller.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController::pcv {
|
||||
|
||||
void Initialize(Module module);
|
||||
void Finalize(Module module);
|
||||
bool IsAvailable(Module module);
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency);
|
||||
void AssertReset(Module module);
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "sdmmc_clock_reset_controller.reg.board.nintendo_nx.hpp"
|
||||
#include "sdmmc_timer.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController::reg {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(AMS_SDMMC_THREAD_SAFE)
|
||||
|
||||
constinit os::SdkMutex g_init_mutex;
|
||||
|
||||
#define AMS_SDMMC_LOCK_INIT_MUTEX() std::scoped_lock lk(g_init_mutex)
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_LOCK_INIT_MUTEX()
|
||||
|
||||
#endif
|
||||
|
||||
constinit bool g_is_initialized = false;
|
||||
|
||||
struct ModuleInfo {
|
||||
u32 target_frequency_khz;
|
||||
u32 actual_frequency_khz;
|
||||
};
|
||||
|
||||
constinit ModuleInfo g_module_infos[Module_Count] = {};
|
||||
|
||||
constexpr inline dd::PhysicalAddress ClockResetControllerRegistersPhysicalAddress = UINT64_C(0x60006000);
|
||||
constexpr inline size_t ClockResetControllerRegistersSize = 4_KB;
|
||||
|
||||
constinit uintptr_t g_clkrst_registers_address = 0;
|
||||
|
||||
[[maybe_unused]] void InitializePllc4() {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Check if PLLC4_BASE has the expected value; if it does, we have nothing to do. */
|
||||
constexpr u32 ExpectedPllc4Base = 0x58006804;
|
||||
if (ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE) == ExpectedPllc4Base) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable PLLC4_ENABLE, if it's currently set. */
|
||||
if (ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, CLK_RST_REG_BITS_ENUM(PLLC4_BASE_PLLC4_ENABLE, ENABLE))) {
|
||||
ams::reg::ReadWrite(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, CLK_RST_REG_BITS_ENUM(PLLC4_BASE_PLLC4_ENABLE, DISABLE));
|
||||
}
|
||||
|
||||
/* Operate on the register with PLLC4_ENABLE cleared. */
|
||||
{
|
||||
/* Clear IDDQ, read to be sure it takes, wait 5 us. */
|
||||
ams::reg::ReadWrite(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, CLK_RST_REG_BITS_ENUM(PLLC4_BASE_PLLC4_IDDQ, OFF));
|
||||
ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE);
|
||||
WaitMicroSeconds(5);
|
||||
|
||||
/* Write the expected value sans IDDQ/PLLC4_ENABLE. */
|
||||
constexpr u32 ExpectedPllc4BaseMask = ~ams::reg::EncodeMask(CLK_RST_REG_BITS_MASK(PLLC4_BASE_PLLC4_ENABLE),
|
||||
CLK_RST_REG_BITS_MASK(PLLC4_BASE_PLLC4_IDDQ));
|
||||
ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, ExpectedPllc4Base & ExpectedPllc4BaseMask);
|
||||
}
|
||||
|
||||
/* Write PLLC4_ENABLE, and read to be sure our configuration takes. */
|
||||
ams::reg::ReadWrite(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, CLK_RST_REG_BITS_ENUM(PLLC4_BASE_PLLC4_ENABLE, ENABLE));
|
||||
ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE);
|
||||
|
||||
/* Wait up to 1s for changes to take. */
|
||||
{
|
||||
ManualTimer timer(1000);
|
||||
while (true) {
|
||||
/* Check if we're done. */
|
||||
if (!ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_PLLC4_BASE, CLK_RST_REG_BITS_ENUM(PLLC4_BASE_PLLC4_LOCK, NOT_LOCK))) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check that we haven't timed out. */
|
||||
AMS_ABORT_UNLESS(timer.Update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeLegacyTmClk() {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Configure the legacy tm clock as 12MHz. */
|
||||
ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_LEGACY_TM_CLK_SRC, PLLP_OUT0),
|
||||
CLK_RST_REG_BITS_VALUE(CLK_SOURCE_LEGACY_TM_CLK_DIVISOR, 66));
|
||||
|
||||
/* Enable clock to the legacy tm. */
|
||||
ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_Y_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_CLK_ENB_LEGACY_TM, ENABLE));
|
||||
}
|
||||
|
||||
bool IsResetReleased(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Get the reset bit from RST_DEVICES_* */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_SDMMC1_RST, DISABLE));
|
||||
case Module_Sdmmc2: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_SDMMC2_RST, DISABLE));
|
||||
case Module_Sdmmc3: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_REG_BITS_ENUM(RST_DEVICES_U_SWR_SDMMC3_RST, DISABLE));
|
||||
case Module_Sdmmc4: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_SDMMC4_RST, DISABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void SetReset(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Set reset in RST_DEV_*_SET */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC1_RST, ENABLE));
|
||||
case Module_Sdmmc2: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC2_RST, ENABLE));
|
||||
case Module_Sdmmc3: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_U_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_U_SDMMC3_RST, ENABLE));
|
||||
case Module_Sdmmc4: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC4_RST, ENABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearReset(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Set reset in RST_DEV_*_CLR */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC1_RST, ENABLE));
|
||||
case Module_Sdmmc2: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC2_RST, ENABLE));
|
||||
case Module_Sdmmc3: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_U_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_U_SDMMC3_RST, ENABLE));
|
||||
case Module_Sdmmc4: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SDMMC4_RST, ENABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsClockEnabled(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Get the enable bit from CLK_OUT_ENB_* */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_SDMMC1, ENABLE));
|
||||
case Module_Sdmmc2: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_SDMMC2, ENABLE));
|
||||
case Module_Sdmmc3: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_SDMMC3, ENABLE));
|
||||
case Module_Sdmmc4: return ams::reg::HasValue(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_SDMMC4, ENABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void SetClockEnable(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Set clock enable bit in CLK_ENB_*_SET */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC1, ENABLE));
|
||||
case Module_Sdmmc2: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC2, ENABLE));
|
||||
case Module_Sdmmc3: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_U_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_SDMMC3, ENABLE));
|
||||
case Module_Sdmmc4: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC4, ENABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearClockEnable(Module module) {
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Set clock enable bit in CLK_ENB_*_CLR */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC1, ENABLE));
|
||||
case Module_Sdmmc2: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC2, ENABLE));
|
||||
case Module_Sdmmc3: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_U_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_SDMMC3, ENABLE));
|
||||
case Module_Sdmmc4: return ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_SDMMC4, ENABLE));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void SetClockSourceSdmmc(u32 *out_actual_frequency_khz, Module module, u32 target_frequency_khz) {
|
||||
/* Check that we can write to output. */
|
||||
AMS_ABORT_UNLESS(out_actual_frequency_khz != nullptr);
|
||||
|
||||
/* Determine frequency/divisor. */
|
||||
u32 clk_m = ams::reg::Encode(CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SDMMCX_SDMMCX_CLK_SRC, PLLP_OUT0));
|
||||
u8 n;
|
||||
switch (target_frequency_khz) {
|
||||
case 25'000:
|
||||
*out_actual_frequency_khz = 24'728;
|
||||
n = 31;
|
||||
break;
|
||||
case 26'000:
|
||||
*out_actual_frequency_khz = 25'500;
|
||||
n = 30;
|
||||
break;
|
||||
case 40'800:
|
||||
*out_actual_frequency_khz = 40'800;
|
||||
n = 18;
|
||||
break;
|
||||
case 50'000:
|
||||
*out_actual_frequency_khz = 48'000;
|
||||
n = 15;
|
||||
break;
|
||||
case 52'000:
|
||||
*out_actual_frequency_khz = 51'000;
|
||||
n = 14;
|
||||
break;
|
||||
case 100'000:
|
||||
#if defined(AMS_SDMMC_SET_PLLC4_BASE)
|
||||
*out_actual_frequency_khz = 99'840;
|
||||
n = 2;
|
||||
clk_m = ams::reg::Encode(CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SDMMCX_SDMMCX_CLK_SRC, PLLC4_OUT2));
|
||||
#else
|
||||
*out_actual_frequency_khz = 90'667;
|
||||
n = 7;
|
||||
#endif
|
||||
break;
|
||||
case 200'000:
|
||||
#if defined(AMS_SDMMC_SET_PLLC4_BASE)
|
||||
*out_actual_frequency_khz = 199'680;
|
||||
n = 0;
|
||||
if (module == Module_Sdmmc2 || module == Module_Sdmmc4) {
|
||||
clk_m = ams::reg::Encode(CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SDMMC24_SDMMC24_CLK_SRC, PLLC4_OUT2_LJ));
|
||||
} else {
|
||||
clk_m = ams::reg::Encode(CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SDMMCX_SDMMCX_CLK_SRC, PLLC4_OUT2));
|
||||
}
|
||||
#else
|
||||
*out_actual_frequency_khz = 163'200;
|
||||
n = 3;
|
||||
#endif
|
||||
break;
|
||||
case 208'000:
|
||||
*out_actual_frequency_khz = 204'000;
|
||||
n = 2;
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
/* Set frequencies in module info. */
|
||||
g_module_infos[module].target_frequency_khz = target_frequency_khz;
|
||||
g_module_infos[module].actual_frequency_khz = *out_actual_frequency_khz;
|
||||
|
||||
/* Check that we have registers we can write to. */
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Update the clock source. */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1, clk_m | static_cast<u32>(n)); break;
|
||||
case Module_Sdmmc2: ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2, clk_m | static_cast<u32>(n)); break;
|
||||
case Module_Sdmmc3: ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3, clk_m | static_cast<u32>(n)); break;
|
||||
case Module_Sdmmc4: ams::reg::Write(g_clkrst_registers_address + CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4, clk_m | static_cast<u32>(n)); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureControl(Module module) {
|
||||
/* Read from RST_DEVICES_* to be sure previous configuration takes. */
|
||||
switch (module) {
|
||||
case Module_Sdmmc1: ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L); break;
|
||||
case Module_Sdmmc2: ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L); break;
|
||||
case Module_Sdmmc3: ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_U); break;
|
||||
case Module_Sdmmc4: ams::reg::Read(g_clkrst_registers_address + CLK_RST_CONTROLLER_RST_DEVICES_L); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Initialize(Module module) {
|
||||
/* Initialization isn't module specific. */
|
||||
AMS_UNUSED(module);
|
||||
|
||||
/* Acquire exclusive access to the initialization lock. */
|
||||
AMS_SDMMC_LOCK_INIT_MUTEX();
|
||||
|
||||
/* If we've already initialized, we don't need to do anything. */
|
||||
if (g_is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear module infos. */
|
||||
std::memset(g_module_infos, 0, sizeof(g_module_infos));
|
||||
|
||||
/* Get the registers address. */
|
||||
g_clkrst_registers_address = dd::QueryIoMapping(ClockResetControllerRegistersPhysicalAddress, ClockResetControllerRegistersSize);
|
||||
AMS_ABORT_UNLESS(g_clkrst_registers_address != 0);
|
||||
|
||||
/* Perform register initialization. */
|
||||
#if defined(AMS_SDMMC_SET_PLLC4_BASE)
|
||||
InitializePllc4();
|
||||
#endif
|
||||
InitializeLegacyTmClk();
|
||||
|
||||
/* Mark that we've initialized. */
|
||||
g_is_initialized = true;
|
||||
}
|
||||
|
||||
void Finalize(Module module) {
|
||||
/* Nothing is needed for finalization. */
|
||||
AMS_UNUSED(module);
|
||||
}
|
||||
|
||||
bool IsAvailable(Module module) {
|
||||
return IsResetReleased(module) && IsClockEnabled(module);
|
||||
}
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency_khz, Module module, u32 target_frequency_khz) {
|
||||
/* If we're not changing the clock frequency, we don't need to do anything. */
|
||||
if (target_frequency_khz == g_module_infos[module].target_frequency_khz) {
|
||||
*out_actual_frequency_khz = g_module_infos[module].actual_frequency_khz;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Temporarily disable clock. */
|
||||
const bool clock_enabled = IsClockEnabled(module);
|
||||
if (clock_enabled) {
|
||||
ClearClockEnable(module);
|
||||
}
|
||||
|
||||
/* Set the clock source. */
|
||||
SetClockSourceSdmmc(out_actual_frequency_khz, module, target_frequency_khz);
|
||||
|
||||
/* Re-enable clock, if we should. */
|
||||
if (clock_enabled) {
|
||||
SetClockEnable(module);
|
||||
}
|
||||
|
||||
/* Ensure that our configuration takes. */
|
||||
EnsureControl(module);
|
||||
}
|
||||
|
||||
void AssertReset(Module module) {
|
||||
/* Set reset and disable clock. */
|
||||
SetReset(module);
|
||||
ClearClockEnable(module);
|
||||
|
||||
/* Ensure that our configuration takes. */
|
||||
EnsureControl(module);
|
||||
}
|
||||
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz) {
|
||||
/* Disable clock if it's enabled. */
|
||||
if (IsClockEnabled(module)) {
|
||||
ClearClockEnable(module);
|
||||
}
|
||||
|
||||
/* Set reset. */
|
||||
SetReset(module);
|
||||
|
||||
/* Set the clock source. */
|
||||
u32 actual_source_frequency_khz;
|
||||
SetClockSourceSdmmc(std::addressof(actual_source_frequency_khz), module, target_frequency_khz);
|
||||
|
||||
/* Enable clock. */
|
||||
SetClockEnable(module);
|
||||
|
||||
/* Ensure that our configuration takes. */
|
||||
EnsureControl(module);
|
||||
|
||||
/* Wait 100 clocks. */
|
||||
WaitClocks(100, actual_source_frequency_khz);
|
||||
|
||||
/* Clear reset. */
|
||||
ClearReset(module);
|
||||
|
||||
/* Ensure that our configuration takes. */
|
||||
EnsureControl(module);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_clock_reset_controller.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl::ClockResetController::reg {
|
||||
|
||||
void Initialize(Module module);
|
||||
void Finalize(Module module);
|
||||
bool IsAvailable(Module module);
|
||||
|
||||
void SetClockFrequencyKHz(u32 *out_actual_frequency, Module module, u32 target_frequency);
|
||||
void AssertReset(Module module);
|
||||
void ReleaseReset(Module module, u32 target_frequency_khz);
|
||||
|
||||
}
|
||||
270
libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp
Normal file
270
libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#if defined(AMS_SDMMC_USE_SD_CARD_DETECTOR)
|
||||
#include "sdmmc_device_detector.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
bool DeviceDetector::IsCurrentInserted() {
|
||||
return gpio::GetValue(std::addressof(this->gpio_pad_session)) == this->inserted_gpio_value;
|
||||
}
|
||||
|
||||
void DeviceDetector::HandleDeviceStatus(bool prev_inserted, bool cur_inserted) {
|
||||
if (!prev_inserted && !cur_inserted) {
|
||||
/* Not inserted -> Not inserted, nothing to do. */
|
||||
} else if (!prev_inserted && cur_inserted) {
|
||||
/* Card was inserted. */
|
||||
if (this->callback_info.inserted_callback != nullptr) {
|
||||
this->callback_info.inserted_callback(this->callback_info.inserted_callback_arg);
|
||||
}
|
||||
} else if (prev_inserted && !cur_inserted) {
|
||||
/* Card was removed. */
|
||||
if (this->callback_info.removed_callback != nullptr) {
|
||||
this->callback_info.removed_callback(this->callback_info.removed_callback_arg);
|
||||
}
|
||||
} else /* if (prev_inserted && cur_inserted) */ {
|
||||
/* Card was removed, and then inserted. */
|
||||
if (this->callback_info.removed_callback != nullptr) {
|
||||
this->callback_info.removed_callback(this->callback_info.removed_callback_arg);
|
||||
}
|
||||
|
||||
if (this->callback_info.inserted_callback != nullptr) {
|
||||
this->callback_info.inserted_callback(this->callback_info.inserted_callback_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceDetector::DetectorThread() {
|
||||
/* Initialize the gpio session. */
|
||||
sm::DoWithSession([] { gpio::Initialize(); });
|
||||
gpio::OpenSession(std::addressof(this->gpio_pad_session), this->gpio_device_code);
|
||||
gpio::SetDirection(std::addressof(this->gpio_pad_session), gpio::Direction_Input);
|
||||
gpio::SetDebounceTime(std::addressof(this->gpio_pad_session), this->gpio_debounce_ms);
|
||||
gpio::SetDebounceEnabled(std::addressof(this->gpio_pad_session), true);
|
||||
gpio::SetInterruptMode(std::addressof(this->gpio_pad_session), gpio::InterruptMode_AnyEdge);
|
||||
|
||||
/* Get the gpio session's interrupt event. */
|
||||
os::SystemEventType gpio_event;
|
||||
R_ABORT_UNLESS(gpio::BindInterrupt(std::addressof(gpio_event), std::addressof(this->gpio_pad_session)));
|
||||
|
||||
/* Initialize and link waitable holders. */
|
||||
os::WaitableManagerType wait_manager;
|
||||
os::WaitableHolderType detector_thread_end_holder;
|
||||
os::WaitableHolderType request_sleep_wake_event_holder;
|
||||
os::WaitableHolderType gpio_event_holder;
|
||||
os::InitializeWaitableManager(std::addressof(wait_manager));
|
||||
os::InitializeWaitableHolder(std::addressof(detector_thread_end_holder), std::addressof(this->detector_thread_end_event));
|
||||
os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(detector_thread_end_holder));
|
||||
os::InitializeWaitableHolder(std::addressof(request_sleep_wake_event_holder), std::addressof(this->request_sleep_wake_event));
|
||||
os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(request_sleep_wake_event_holder));
|
||||
os::InitializeWaitableHolder(std::addressof(gpio_event_holder), std::addressof(gpio_event));
|
||||
os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder));
|
||||
|
||||
/* Wait before detecting the initial state of the card. */
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(this->gpio_debounce_ms));
|
||||
bool cur_inserted = this->IsCurrentInserted();
|
||||
this->is_prev_inserted = cur_inserted;
|
||||
|
||||
/* Set state as awake. */
|
||||
this->state = State_Awake;
|
||||
os::SignalEvent(std::addressof(this->ready_device_status_event));
|
||||
|
||||
/* Enable interrupts to be informed of device status. */
|
||||
gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), true);
|
||||
|
||||
/* Wait, servicing our events. */
|
||||
while (true) {
|
||||
/* Get the signaled holder. */
|
||||
os::WaitableHolderType *signaled_holder = os::WaitAny(std::addressof(wait_manager));
|
||||
|
||||
/* Process the holder. */
|
||||
bool insert_change = false;
|
||||
if (signaled_holder == std::addressof(detector_thread_end_holder)) {
|
||||
/* We should kill ourselves. */
|
||||
os::ClearEvent(std::addressof(this->detector_thread_end_event));
|
||||
this->state = State_Finalized;
|
||||
break;
|
||||
} else if (signaled_holder == std::addressof(request_sleep_wake_event_holder)) {
|
||||
/* A request for us to sleep/wake has come in, so we'll acknowledge it. */
|
||||
os::ClearEvent(std::addressof(this->request_sleep_wake_event));
|
||||
this->state = State_Sleep;
|
||||
os::SignalEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
|
||||
/* Temporarily unlink our interrupt event. */
|
||||
os::UnlinkWaitableHolder(std::addressof(gpio_event_holder));
|
||||
|
||||
/* Wait to be signaled. */
|
||||
signaled_holder = os::WaitAny(std::addressof(wait_manager));
|
||||
|
||||
/* Link our interrupt event back in. */
|
||||
os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder));
|
||||
|
||||
/* We're awake again. Either because we should exit, or because we were asked to wake up. */
|
||||
os::ClearEvent(std::addressof(this->request_sleep_wake_event));
|
||||
this->state = State_Awake;
|
||||
os::SignalEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
|
||||
/* If we were asked to exit, do so. */
|
||||
if (signaled_holder == std::addressof(detector_thread_end_holder)) {
|
||||
/* We should kill ourselves. */
|
||||
os::ClearEvent(std::addressof(this->detector_thread_end_event));
|
||||
this->state = State_Finalized;
|
||||
break;
|
||||
} else /* if (signaled_holder == std::addressof(request_sleep_wake_event_holder)) */ {
|
||||
if ((this->force_detection) ||
|
||||
(({ bool active; R_SUCCEEDED(gpio::IsWakeEventActive(std::addressof(active), this->gpio_device_code)) && active; })) ||
|
||||
(os::TryWaitSystemEvent(std::addressof(gpio_event))) ||
|
||||
(this->is_prev_inserted != this->IsCurrentInserted()))
|
||||
{
|
||||
insert_change = true;
|
||||
}
|
||||
}
|
||||
} else /* if (signaled_holder == std::addressof(gpio_event_holder)) */ {
|
||||
/* An event was detected. */
|
||||
insert_change = true;
|
||||
}
|
||||
|
||||
/* Handle an insert change, if one occurred. */
|
||||
if (insert_change) {
|
||||
/* Call the relevant callback, if we have one. */
|
||||
if (this->device_detection_event_callback != nullptr) {
|
||||
this->device_detection_event_callback(this->device_detection_event_callback_arg);
|
||||
}
|
||||
|
||||
/* Clear the interrupt event. */
|
||||
os::ClearSystemEvent(std::addressof(gpio_event));
|
||||
gpio::ClearInterruptStatus(std::addressof(this->gpio_pad_session));
|
||||
gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), true);
|
||||
|
||||
/* Update insertion status. */
|
||||
cur_inserted = this->IsCurrentInserted();
|
||||
this->HandleDeviceStatus(this->is_prev_inserted, cur_inserted);
|
||||
this->is_prev_inserted = cur_inserted;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable interrupts to our gpio event. */
|
||||
gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), false);
|
||||
|
||||
/* Finalize and unlink waitable holders. */
|
||||
os::UnlinkWaitableHolder(std::addressof(gpio_event_holder));
|
||||
os::FinalizeWaitableHolder(std::addressof(gpio_event_holder));
|
||||
os::UnlinkWaitableHolder(std::addressof(request_sleep_wake_event_holder));
|
||||
os::FinalizeWaitableHolder(std::addressof(request_sleep_wake_event_holder));
|
||||
os::UnlinkWaitableHolder(std::addressof(detector_thread_end_holder));
|
||||
os::FinalizeWaitableHolder(std::addressof(detector_thread_end_holder));
|
||||
os::FinalizeWaitableManager(std::addressof(wait_manager));
|
||||
|
||||
/* Finalize the gpio session. */
|
||||
gpio::UnbindInterrupt(std::addressof(this->gpio_pad_session));
|
||||
gpio::CloseSession(std::addressof(this->gpio_pad_session));
|
||||
gpio::Finalize();
|
||||
}
|
||||
|
||||
void DeviceDetector::Initialize(CallbackInfo *ci) {
|
||||
/* Transition our state from finalized to initializing. */
|
||||
AMS_ABORT_UNLESS(this->state == State_Finalized);
|
||||
this->state = State_Initializing;
|
||||
|
||||
/* Set our callback infos. */
|
||||
this->callback_info = *ci;
|
||||
|
||||
/* Initialize our events. */
|
||||
os::InitializeEvent(std::addressof(this->ready_device_status_event), false, os::EventClearMode_ManualClear);
|
||||
os::InitializeEvent(std::addressof(this->request_sleep_wake_event), false, os::EventClearMode_ManualClear);
|
||||
os::InitializeEvent(std::addressof(this->acknowledge_sleep_awake_event), false, os::EventClearMode_ManualClear);
|
||||
os::InitializeEvent(std::addressof(this->detector_thread_end_event), false, os::EventClearMode_ManualClear);
|
||||
|
||||
/* Create and start the detector thread. */
|
||||
os::CreateThread(std::addressof(this->detector_thread), DetectorThreadEntry, this, this->detector_thread_stack, sizeof(this->detector_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(sdmmc, DeviceDetector));
|
||||
os::SetThreadNamePointer(std::addressof(this->detector_thread), AMS_GET_SYSTEM_THREAD_NAME(sdmmc, DeviceDetector));
|
||||
os::StartThread(std::addressof(this->detector_thread));
|
||||
}
|
||||
|
||||
void DeviceDetector::Finalize() {
|
||||
/* Ensure we're not already finalized. */
|
||||
AMS_ABORT_UNLESS(this->state != State_Finalized);
|
||||
|
||||
/* Signal event to end the detector thread. */
|
||||
os::SignalEvent(std::addressof(this->detector_thread_end_event));
|
||||
os::WaitThread(std::addressof(this->detector_thread));
|
||||
|
||||
/* Finalize thread and events. */
|
||||
os::DestroyThread(std::addressof(this->detector_thread));
|
||||
os::FinalizeEvent(std::addressof(this->ready_device_status_event));
|
||||
os::FinalizeEvent(std::addressof(this->request_sleep_wake_event));
|
||||
os::FinalizeEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
os::FinalizeEvent(std::addressof(this->detector_thread_end_event));
|
||||
}
|
||||
|
||||
void DeviceDetector::PutToSleep() {
|
||||
/* Signal request, wait for acknowledgement. */
|
||||
os::SignalEvent(std::addressof(this->request_sleep_wake_event));
|
||||
os::WaitEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
os::ClearEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
}
|
||||
|
||||
void DeviceDetector::Awaken(bool force_det) {
|
||||
/* Signal request, wait for acknowledgement. */
|
||||
this->force_detection = force_det;
|
||||
os::SignalEvent(std::addressof(this->request_sleep_wake_event));
|
||||
os::WaitEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
os::ClearEvent(std::addressof(this->acknowledge_sleep_awake_event));
|
||||
}
|
||||
|
||||
bool DeviceDetector::IsInserted() {
|
||||
bool inserted = false;
|
||||
|
||||
switch (this->state) {
|
||||
case State_Initializing:
|
||||
/* Wait for us to know whether the device is inserted. */
|
||||
os::WaitEvent(std::addressof(this->ready_device_status_event));
|
||||
[[fallthrough]];
|
||||
case State_Awake:
|
||||
/* Get whether the device is currently inserted. */
|
||||
inserted = this->IsCurrentInserted();
|
||||
break;
|
||||
case State_Sleep:
|
||||
case State_Finalized:
|
||||
/* Get whether the device was inserted when we last knew. */
|
||||
inserted = this->is_prev_inserted;
|
||||
break;
|
||||
}
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
void DeviceDetector::RegisterDetectionEventCallback(DeviceDetectionEventCallback cb, void *arg) {
|
||||
this->device_detection_event_callback_arg = arg;
|
||||
this->device_detection_event_callback = cb;
|
||||
}
|
||||
|
||||
void DeviceDetector::UnregisterDetectionEventCallback() {
|
||||
this->device_detection_event_callback = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#if defined(AMS_SDMMC_USE_SD_CARD_DETECTOR)
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
using InsertedCallback = void (*)(void *);
|
||||
using RemovedCallback = void (*)(void *);
|
||||
|
||||
struct CallbackInfo {
|
||||
InsertedCallback inserted_callback;
|
||||
void *inserted_callback_arg;
|
||||
RemovedCallback removed_callback;
|
||||
void *removed_callback_arg;
|
||||
};
|
||||
|
||||
class DeviceDetector {
|
||||
private:
|
||||
enum State {
|
||||
State_Initializing = 0,
|
||||
State_Awake = 1,
|
||||
State_Sleep = 2,
|
||||
State_Finalized = 3,
|
||||
};
|
||||
private:
|
||||
alignas(os::ThreadStackAlignment) u8 detector_thread_stack[8_KB];
|
||||
State state;
|
||||
bool is_prev_inserted;
|
||||
bool force_detection;
|
||||
os::ThreadType detector_thread;
|
||||
os::EventType detector_thread_end_event;
|
||||
os::EventType request_sleep_wake_event;
|
||||
os::EventType acknowledge_sleep_awake_event;
|
||||
os::EventType ready_device_status_event;
|
||||
|
||||
DeviceCode gpio_device_code;
|
||||
gpio::GpioValue inserted_gpio_value;
|
||||
u32 gpio_debounce_ms;
|
||||
gpio::GpioPadSession gpio_pad_session;
|
||||
|
||||
CallbackInfo callback_info;
|
||||
|
||||
DeviceDetectionEventCallback device_detection_event_callback;
|
||||
void *device_detection_event_callback_arg;
|
||||
private:
|
||||
static void DetectorThreadEntry(void *arg) {
|
||||
reinterpret_cast<DeviceDetector *>(arg)->DetectorThread();
|
||||
}
|
||||
|
||||
void DetectorThread();
|
||||
bool IsCurrentInserted();
|
||||
void HandleDeviceStatus(bool prev_inserted, bool cur_inserted);
|
||||
public:
|
||||
explicit DeviceDetector(DeviceCode dc, gpio::GpioValue igv, u32 gd)
|
||||
: gpio_device_code(dc), inserted_gpio_value(igv), gpio_debounce_ms(gd)
|
||||
{
|
||||
this->state = State_Finalized;
|
||||
this->is_prev_inserted = false;
|
||||
this->force_detection = false;
|
||||
this->callback_info = {};
|
||||
this->device_detection_event_callback = nullptr;
|
||||
this->device_detection_event_callback_arg = nullptr;
|
||||
}
|
||||
|
||||
void Initialize(CallbackInfo *ci);
|
||||
void Finalize();
|
||||
|
||||
void PutToSleep();
|
||||
void Awaken(bool force_det);
|
||||
|
||||
u32 GetDebounceMilliSeconds() const {
|
||||
return this->gpio_debounce_ms;
|
||||
}
|
||||
|
||||
bool IsInserted();
|
||||
|
||||
void RegisterDetectionEventCallback(DeviceDetectionEventCallback cb, void *arg);
|
||||
void UnregisterDetectionEventCallback();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "sdmmc_gc_asic_device_accessor.hpp"
|
||||
#include "sdmmc_timer.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
#if defined(AMS_SDMMC_THREAD_SAFE)
|
||||
|
||||
#define AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX() std::scoped_lock lk(this->gc_asic_device.device_mutex)
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX()
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
|
||||
#define AMS_SDMMC_CHECK_GC_ASIC_REMOVED() R_UNLESS(!this->gc_asic_device.IsRemoved(), sdmmc::ResultDeviceRemoved())
|
||||
|
||||
#else
|
||||
|
||||
#define AMS_SDMMC_CHECK_GC_ASIC_REMOVED()
|
||||
|
||||
#endif
|
||||
|
||||
Result GcAsicDeviceAccessor::IssueCommandWriteOperation(const void *op_buf, size_t op_buf_size) const {
|
||||
/* Validate the operation buffer. */
|
||||
AMS_ABORT_UNLESS(op_buf != nullptr);
|
||||
AMS_ABORT_UNLESS(op_buf_size >= GcAsicOperationSize);
|
||||
|
||||
/* Issue the command. */
|
||||
constexpr ResponseType CommandResponseType = ResponseType_R1;
|
||||
Command command(CommandIndex_GcAsicWriteOperation, 0, CommandResponseType, false);
|
||||
TransferData xfer_data(const_cast<void *>(op_buf), GcAsicOperationSize, 1, TransferDirection_WriteToDevice);
|
||||
IHostController *hc = BaseDeviceAccessor::GetHostController();
|
||||
Result result = hc->IssueCommand(std::addressof(command), std::addressof(xfer_data));
|
||||
if (R_FAILED(result)) {
|
||||
/* We failed to write operation. Check if we were removed. */
|
||||
AMS_SDMMC_CHECK_GC_ASIC_REMOVED();
|
||||
|
||||
/* Determine what result we should return. */
|
||||
Result return_result = result;
|
||||
{
|
||||
/* Issue a stop transmission command. */
|
||||
u32 resp = 0;
|
||||
result = hc->IssueStopTransmissionCommand(std::addressof(resp));
|
||||
if (R_SUCCEEDED(result)) {
|
||||
/* If we successfully stopped transmission but have an error status, we prefer to return that. */
|
||||
result = this->gc_asic_device.CheckDeviceStatus(resp);
|
||||
if (R_FAILED(result)) {
|
||||
return_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check again if we were removed. */
|
||||
AMS_SDMMC_CHECK_GC_ASIC_REMOVED();
|
||||
|
||||
/* Request device status. */
|
||||
u32 device_status;
|
||||
result = BaseDeviceAccessor::IssueCommandSendStatus(std::addressof(device_status), 0);
|
||||
|
||||
/* If we got a device status error here and we didn't previously, we prefer to return that. */
|
||||
if (!sdmmc::ResultDeviceStatusHasError::Includes(return_result) && sdmmc::ResultDeviceStatusHasError::Includes(result)) {
|
||||
return_result = result;
|
||||
}
|
||||
}
|
||||
return return_result;
|
||||
}
|
||||
|
||||
/* Get the response. */
|
||||
u32 resp;
|
||||
hc->GetLastResponse(std::addressof(resp), sizeof(resp), CommandResponseType);
|
||||
R_TRY(this->gc_asic_device.CheckDeviceStatus(resp));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::IssueCommandFinishOperation() const {
|
||||
/* Issue the command. */
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicFinishOperation, 0, true, DeviceState_Tran));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::IssueCommandSleep() {
|
||||
/* Issue the command. */
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicSleep, 0, true, DeviceState_Tran));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::IssueCommandUpdateKey() const {
|
||||
/* Issue the command. */
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandAndCheckR1(CommandIndex_GcAsicUpdateKey, 0, true, DeviceState_Tran));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::StartupGcAsicDevice() {
|
||||
/* Start up the host controller. */
|
||||
IHostController *hc = BaseDeviceAccessor::GetHostController();
|
||||
R_TRY(hc->Startup(BusPower_1_8V, BusWidth_8Bit, SpeedMode_GcAsicSpeed, false));
|
||||
|
||||
/* Wait 10 clocks for configuration to take. */
|
||||
WaitClocks(10, hc->GetDeviceClockFrequencyKHz());
|
||||
|
||||
/* Perform tuning with command index 21. */
|
||||
AMS_ABORT_UNLESS(hc->IsSupportedTuning());
|
||||
R_TRY(hc->Tuning(SpeedMode_GcAsicSpeed, 21));
|
||||
|
||||
/* Set the device as low capacity/no memory. */
|
||||
this->gc_asic_device.SetHighCapacity(false);
|
||||
this->gc_asic_device.SetMemoryCapacity(0);
|
||||
|
||||
/* Enable power saving. */
|
||||
hc->SetPowerSaving(true);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::OnActivate() {
|
||||
/* If we fail to start up the device, ensure the host controller is shut down. */
|
||||
auto power_guard = SCOPE_GUARD { BaseDeviceAccessor::GetHostController()->Shutdown(); };
|
||||
|
||||
/* Try to start up the device. */
|
||||
R_TRY(this->StartupGcAsicDevice());
|
||||
|
||||
/* We started up, so we don't need to power down. */
|
||||
power_guard.Cancel();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::OnReadWrite(u32 sector_index, u32 num_sectors, void *buf, size_t buf_size, bool is_read) {
|
||||
/* Check that we're not performing zero-byte rw. */
|
||||
AMS_ABORT_UNLESS(num_sectors > 0);
|
||||
|
||||
/* Check that the buffer is big enough for the rw. */
|
||||
AMS_ABORT_UNLESS((buf_size / SectorSize) >= num_sectors);
|
||||
|
||||
/* Perform the read/write. */
|
||||
u32 num_transferred_blocks;
|
||||
R_TRY(BaseDeviceAccessor::ReadWriteSingle(std::addressof(num_transferred_blocks), sector_index, num_sectors, buf, is_read));
|
||||
|
||||
/* Require that we read/wrote as many sectors as we expected. */
|
||||
AMS_ABORT_UNLESS(num_transferred_blocks == num_sectors);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void GcAsicDeviceAccessor::Initialize() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* If we've already initialized, we don't need to do anything. */
|
||||
if (this->is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the base device to our gc asic device. */
|
||||
BaseDeviceAccessor::SetDevice(std::addressof(this->gc_asic_device));
|
||||
|
||||
/* Initialize. */
|
||||
IHostController *hc = BaseDeviceAccessor::GetHostController();
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
{
|
||||
this->gc_asic_device.InitializeRemovedEvent();
|
||||
hc->PreSetRemovedEvent(this->gc_asic_device.GetRemovedEvent());
|
||||
}
|
||||
#endif
|
||||
hc->Initialize();
|
||||
|
||||
/* Mark ourselves as initialized. */
|
||||
this->is_initialized = true;
|
||||
}
|
||||
|
||||
void GcAsicDeviceAccessor::Finalize() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* If we've already finalized, we don't need to do anything. */
|
||||
if (!this->is_initialized) {
|
||||
return;
|
||||
}
|
||||
this->is_initialized = false;
|
||||
|
||||
/* Deactivate the device. */
|
||||
BaseDeviceAccessor::Deactivate();
|
||||
|
||||
/* Finalize the host controller. */
|
||||
BaseDeviceAccessor::GetHostController()->Finalize();
|
||||
|
||||
/* Finalize the removed event. */
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
{
|
||||
this->gc_asic_device.FinalizeRemovedEvent();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::GetSpeedMode(SpeedMode *out_speed_mode) const {
|
||||
/* Check that we can write to output. */
|
||||
AMS_ABORT_UNLESS(out_speed_mode != nullptr);
|
||||
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
*out_speed_mode = SpeedMode_GcAsicSpeed;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void GcAsicDeviceAccessor::PutGcAsicToSleep() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* If the device isn't awake, we don't need to do anything. */
|
||||
if (!this->gc_asic_device.IsAwake()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If necessary, put the host controller to sleep. */
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
if (this->gc_asic_device.IsActive() && !this->gc_asic_device.IsRemoved())
|
||||
#else
|
||||
if (this->gc_asic_device.IsActive())
|
||||
#endif
|
||||
{
|
||||
BaseDeviceAccessor::GetHostController()->PutToSleep();
|
||||
}
|
||||
|
||||
/* Put the gc asic device to sleep. */
|
||||
this->gc_asic_device.PutToSleep();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::AwakenGcAsic() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* If the device is awake, we don't need to do anything. */
|
||||
R_SUCCEED_IF(this->gc_asic_device.IsAwake());
|
||||
|
||||
/* Wake the device. */
|
||||
this->gc_asic_device.Awaken();
|
||||
|
||||
/* Wake the host controller, if we need to.*/
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
if (this->gc_asic_device.IsActive() && !this->gc_asic_device.IsRemoved())
|
||||
#else
|
||||
if (this->gc_asic_device.IsActive())
|
||||
#endif
|
||||
{
|
||||
R_TRY(BaseDeviceAccessor::GetHostController()->Awaken());
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::WriteGcAsicOperation(const void *op_buf, size_t op_buf_size) {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
/* Issue the command. */
|
||||
R_TRY(this->IssueCommandWriteOperation(op_buf, op_buf_size));
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandSendStatus());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::FinishGcAsicOperation() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
/* Issue the command. */
|
||||
R_TRY(this->IssueCommandFinishOperation());
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandSendStatus());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::AbortGcAsicOperation() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
/* Issue stop transmission command. */
|
||||
u32 resp = 0;
|
||||
R_TRY(BaseDeviceAccessor::GetHostController()->IssueStopTransmissionCommand(std::addressof(resp)));
|
||||
R_TRY(this->gc_asic_device.CheckDeviceStatus(resp));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::SleepGcAsic() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
/* Issue the command. */
|
||||
R_TRY(this->IssueCommandSleep());
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandSendStatus());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GcAsicDeviceAccessor::UpdateGcAsicKey() {
|
||||
/* Acquire exclusive access to the device. */
|
||||
AMS_SDMMC_LOCK_GC_ASIC_DEVICE_MUTEX();
|
||||
|
||||
/* Check that we're accessible. */
|
||||
R_TRY(this->gc_asic_device.CheckAccessible());
|
||||
|
||||
/* Issue the command. */
|
||||
R_TRY(this->IssueCommandUpdateKey());
|
||||
R_TRY(BaseDeviceAccessor::IssueCommandSendStatus());
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_base_device_accessor.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
class GcAsicDevice : public BaseDevice {
|
||||
private:
|
||||
static constexpr u16 Rca = 0;
|
||||
private:
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
mutable os::EventType removed_event;
|
||||
#endif
|
||||
public:
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
virtual os::EventType *GetRemovedEvent() const override {
|
||||
return std::addressof(this->removed_event);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual DeviceType GetDeviceType() const override {
|
||||
return DeviceType_GcAsic;
|
||||
}
|
||||
|
||||
virtual u16 GetRca() const override {
|
||||
return Rca;
|
||||
}
|
||||
};
|
||||
|
||||
class GcAsicDeviceAccessor : public BaseDeviceAccessor {
|
||||
private:
|
||||
GcAsicDevice gc_asic_device;
|
||||
bool is_initialized;
|
||||
private:
|
||||
Result IssueCommandWriteOperation(const void *op_buf, size_t op_buf_size) const;
|
||||
Result IssueCommandFinishOperation() const;
|
||||
Result IssueCommandSleep();
|
||||
Result IssueCommandUpdateKey() const;
|
||||
Result StartupGcAsicDevice();
|
||||
protected:
|
||||
virtual Result OnActivate() override;
|
||||
virtual Result OnReadWrite(u32 sector_index, u32 num_sectors, void *buf, size_t buf_size, bool is_read) override;
|
||||
|
||||
virtual Result ReStartup() override {
|
||||
AMS_ABORT("Can't ReStartup GcAsic\n");
|
||||
}
|
||||
public:
|
||||
virtual void Initialize() override;
|
||||
virtual void Finalize() override;
|
||||
virtual Result GetSpeedMode(SpeedMode *out_speed_mode) const override;
|
||||
public:
|
||||
explicit GcAsicDeviceAccessor(IHostController *hc) : BaseDeviceAccessor(hc), is_initialized(false) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void PutGcAsicToSleep();
|
||||
Result AwakenGcAsic();
|
||||
Result WriteGcAsicOperation(const void *op_buf, size_t op_buf_size);
|
||||
Result FinishGcAsicOperation();
|
||||
Result AbortGcAsicOperation();
|
||||
Result SleepGcAsic();
|
||||
Result UpdateGcAsicKey();
|
||||
|
||||
void SignalGcRemovedEvent() {
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
this->gc_asic_device.SignalRemovedEvent();
|
||||
#else
|
||||
AMS_ABORT("SignalGcRemovedEvent called without event support\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClearGcRemovedEvent() {
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
this->gc_asic_device.ClearRemovedEvent();
|
||||
#else
|
||||
AMS_ABORT("ClearGcRemovedEvent called without event support\n");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_i_host_controller.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
class IDeviceAccessor {
|
||||
public:
|
||||
virtual void Initialize() = 0;
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS)
|
||||
virtual void RegisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0;
|
||||
virtual void UnregisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0;
|
||||
#endif
|
||||
|
||||
virtual Result Activate() = 0;
|
||||
virtual void Deactivate() = 0;
|
||||
|
||||
virtual Result ReadWrite(u32 sector_index, u32 num_sectors, void *buffer, size_t buffer_size, bool is_read) = 0;
|
||||
virtual Result CheckConnection(SpeedMode *out_speed_mode, BusWidth *out_bus_width) = 0;
|
||||
|
||||
virtual Result GetSpeedMode(SpeedMode *out) const = 0;
|
||||
virtual Result GetMemoryCapacity(u32 *out_sectors) const = 0;
|
||||
virtual Result GetDeviceStatus(u32 *out) const = 0;
|
||||
virtual Result GetOcr(u32 *out) const = 0;
|
||||
virtual Result GetRca(u16 *out) const = 0;
|
||||
virtual Result GetCid(void *out, size_t size) const = 0;
|
||||
virtual Result GetCsd(void *out, size_t size) const = 0;
|
||||
|
||||
virtual void GetAndClearErrorInfo(ErrorInfo *out_error_info, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
#include <stratosphere/os.hpp>
|
||||
#endif
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
enum ResponseType {
|
||||
ResponseType_R0 = 0,
|
||||
ResponseType_R1 = 1,
|
||||
ResponseType_R2 = 2,
|
||||
ResponseType_R3 = 3,
|
||||
ResponseType_R6 = 4,
|
||||
ResponseType_R7 = 5,
|
||||
};
|
||||
|
||||
enum TransferDirection {
|
||||
TransferDirection_ReadFromDevice = 0,
|
||||
TransferDirection_WriteToDevice = 1,
|
||||
};
|
||||
|
||||
enum CommandIndex {
|
||||
/* Generic commands. */
|
||||
CommandIndex_GoIdleState = 0,
|
||||
CommandIndex_SendOpCond = 1,
|
||||
CommandIndex_AllSendCid = 2,
|
||||
CommandIndex_SendRelativeAddr = 3,
|
||||
CommandIndex_SetRelativeAddr = 3,
|
||||
CommandIndex_SetDsr = 4,
|
||||
|
||||
CommandIndex_Switch = 6,
|
||||
CommandIndex_SelectCard = 7,
|
||||
CommandIndex_DeselectCard = 7,
|
||||
CommandIndex_SendIfCond = 8,
|
||||
CommandIndex_SendExtCsd = 8,
|
||||
CommandIndex_SendCsd = 9,
|
||||
CommandIndex_SendCid = 10,
|
||||
CommandIndex_VoltageSwitch = 11,
|
||||
CommandIndex_StopTransmission = 12,
|
||||
CommandIndex_SendStatus = 13,
|
||||
CommandIndex_SendTaskStatus = 13,
|
||||
|
||||
CommandIndex_GoInactiveState = 15,
|
||||
CommandIndex_SetBlockLen = 16,
|
||||
CommandIndex_ReadSingleBlock = 17,
|
||||
CommandIndex_ReadMultipleBlock = 18,
|
||||
CommandIndex_SendTuningBlock = 19,
|
||||
CommandIndex_SpeedClassControl = 20,
|
||||
|
||||
CommandIndex_AddressExtension = 22,
|
||||
CommandIndex_SetBlockCount = 23,
|
||||
CommandIndex_WriteBlock = 24,
|
||||
CommandIndex_WriteMultipleBlock = 25,
|
||||
|
||||
CommandIndex_ProgramCsd = 27,
|
||||
CommandIndex_SetWriteProt = 28,
|
||||
CommandIndex_ClearWriteProt = 29,
|
||||
CommandIndex_SendWriteProt = 30,
|
||||
|
||||
CommandIndex_EraseWriteBlockStart = 32,
|
||||
CommandIndex_EraseWriteBlockEnd = 33,
|
||||
|
||||
CommandIndex_EraseGroupStart = 35,
|
||||
CommandIndex_EraseGroupEnd = 36,
|
||||
|
||||
CommandIndex_Erase = 38,
|
||||
|
||||
CommandIndex_LockUnlock = 42,
|
||||
|
||||
CommandIndex_AppCmd = 55,
|
||||
CommandIndex_GenCmd = 56,
|
||||
|
||||
/* Nintendo specific vendor commands for lotus3. */
|
||||
CommandIndex_GcAsicWriteOperation = 60,
|
||||
CommandIndex_GcAsicFinishOperation = 61,
|
||||
CommandIndex_GcAsicSleep = 62,
|
||||
CommandIndex_GcAsicUpdateKey = 63,
|
||||
};
|
||||
|
||||
struct Command {
|
||||
u32 command_index;
|
||||
u32 command_argument;
|
||||
ResponseType response_type;
|
||||
bool is_busy;
|
||||
|
||||
constexpr Command(u32 ci, u32 ca, ResponseType r, bool b) : command_index(ci), command_argument(ca), response_type(r), is_busy(b) { /* ... */ }
|
||||
};
|
||||
|
||||
struct TransferData {
|
||||
void *buffer;
|
||||
size_t block_size;
|
||||
u32 num_blocks;
|
||||
TransferDirection transfer_direction;
|
||||
bool is_multi_block_transfer;
|
||||
bool is_stop_transmission_command_enabled;
|
||||
|
||||
constexpr TransferData(void *b, size_t bs, u32 nb, TransferDirection xd, bool mb, bool st)
|
||||
: buffer(b), block_size(bs), num_blocks(nb), transfer_direction(xd), is_multi_block_transfer(mb), is_stop_transmission_command_enabled(st)
|
||||
{
|
||||
if (this->num_blocks > 1) {
|
||||
AMS_ABORT_UNLESS(this->is_multi_block_transfer);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr TransferData(void *b, size_t bs, u32 nb, TransferDirection xd)
|
||||
: buffer(b), block_size(bs), num_blocks(nb), transfer_direction(xd), is_multi_block_transfer(false), is_stop_transmission_command_enabled(false)
|
||||
{
|
||||
AMS_ABORT_UNLESS(this->num_blocks == 1);
|
||||
}
|
||||
};
|
||||
|
||||
class IHostController {
|
||||
public:
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
virtual void PreSetRemovedEvent(ams::os::EventType *event) = 0;
|
||||
#endif
|
||||
|
||||
virtual void Initialize() = 0;
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
#if defined(AMS_SDMMC_USE_DEVICE_VIRTUAL_ADDRESS)
|
||||
virtual void RegisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0;
|
||||
virtual void UnregisterDeviceVirtualAddress(uintptr_t buffer, size_t buffer_size, ams::dd::DeviceVirtualAddress buffer_device_virtual_address) = 0;
|
||||
#endif
|
||||
|
||||
virtual void SetWorkBuffer(void *wb, size_t wb_size) = 0;
|
||||
|
||||
virtual Result Startup(BusPower bus_power, BusWidth bus_width, SpeedMode speed_mode, bool power_saving_enable) = 0;
|
||||
virtual void Shutdown();
|
||||
virtual void PutToSleep();
|
||||
virtual Result Awaken();
|
||||
|
||||
virtual Result SwitchToSdr12();
|
||||
|
||||
virtual bool IsSupportedBusPower(BusPower bus_power) const = 0;
|
||||
virtual BusPower GetBusPower() const = 0;
|
||||
|
||||
virtual bool IsSupportedBusWidth(BusWidth bus_width) const = 0;
|
||||
virtual void SetBusWidth(BusWidth bus_width) = 0;
|
||||
virtual BusWidth GetBusWidth() const = 0;
|
||||
|
||||
virtual Result SetSpeedMode(SpeedMode speed_mode) = 0;
|
||||
virtual SpeedMode GetSpeedMode() const = 0;
|
||||
|
||||
virtual u32 GetDeviceClockFrequencyKHz() const = 0;
|
||||
|
||||
virtual void SetPowerSaving(bool en) = 0;
|
||||
virtual bool IsPowerSavingEnable() const = 0;
|
||||
|
||||
virtual void EnableDeviceClock() = 0;
|
||||
virtual void DisableDeviceClock() = 0;
|
||||
virtual bool IsDeviceClockEnable() const = 0;
|
||||
|
||||
virtual u32 GetMaxTransferNumBlocks() const = 0;
|
||||
|
||||
virtual void ChangeCheckTransferInterval(u32 ms) = 0;
|
||||
virtual void SetDefaultCheckTransferInterval() = 0;
|
||||
|
||||
virtual Result IssueCommand(const Command *command, TransferData *xfer_data, u32 *out_num_transferred_blocks) = 0;
|
||||
virtual Result IssueStopTransmissionCommand(u32 *out_response) = 0;
|
||||
|
||||
ALWAYS_INLINE Result IssueCommand(const Command *command, TransferData *xfer_data) {
|
||||
return this->IssueCommand(command, xfer_data, nullptr);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result IssueCommand(const Command *command) {
|
||||
return this->IssueCommand(command, nullptr, nullptr);
|
||||
}
|
||||
|
||||
virtual void GetLastResponse(u32 *out_response, size_t response_size, ResponseType response_type) const = 0;
|
||||
virtual void GetLastStopTransmissionResponse(u32 *out_response, size_t response_size) const = 0;
|
||||
|
||||
virtual bool IsSupportedTuning() const = 0;
|
||||
virtual Result Tuning(SpeedMode speed_mode, u32 command_index) = 0;
|
||||
virtual void SaveTuningStatusForHs400() = 0;
|
||||
virtual Result GetInternalStatus() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user