mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-31 03:05:48 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			147 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 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();
 | |
|     }
 | |
| 
 | |
| }
 |