From 0e8efbb9e9d8b21f000adddfbfd12fefa081e834 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 21 Oct 2020 13:20:11 -0700 Subject: [PATCH] sdmmc: implement gpio handling for sdmmc1-register-control --- .../impl/sdmmc_io_impl.board.nintendo_nx.cpp | 169 +++++++++++++++++- 1 file changed, 165 insertions(+), 4 deletions(-) diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.cpp index 82c9de3b0..858bffce4 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.cpp @@ -44,20 +44,181 @@ namespace ams::sdmmc::impl { namespace gpio_impl { + namespace { + + constexpr inline dd::PhysicalAddress GpioRegistersPhysicalAddress = 0x6000d000; + constexpr inline size_t GpioRegistersSize = 4_KB; + + enum GpioPadPort { + GpioPadPort_A = 0, + GpioPadPort_B = 1, + GpioPadPort_C = 2, + GpioPadPort_D = 3, + GpioPadPort_E = 4, + GpioPadPort_F = 5, + GpioPadPort_G = 6, + GpioPadPort_H = 7, + GpioPadPort_I = 8, + GpioPadPort_J = 9, + GpioPadPort_K = 10, + GpioPadPort_L = 11, + GpioPadPort_M = 12, + GpioPadPort_N = 13, + GpioPadPort_O = 14, + GpioPadPort_P = 15, + GpioPadPort_Q = 16, + GpioPadPort_R = 17, + GpioPadPort_S = 18, + GpioPadPort_T = 19, + GpioPadPort_U = 20, + GpioPadPort_V = 21, + GpioPadPort_W = 22, + GpioPadPort_X = 23, + GpioPadPort_Y = 24, + GpioPadPort_Z = 25, + GpioPadPort_AA = 26, + GpioPadPort_BB = 27, + GpioPadPort_CC = 28, + GpioPadPort_DD = 29, + GpioPadPort_EE = 30, + GpioPadPort_FF = 31, + }; + + consteval unsigned int GetInternalGpioPadNumber(GpioPadPort port, unsigned int which) { + AMS_ASSUME(which < 8); + + return (static_cast(port) * 8) + which; + } + + enum InternalGpioPadNumber { + InternalGpioPadNumber_E4 = GetInternalGpioPadNumber(GpioPadPort_E, 4), + }; + + constexpr int ConvertInternalGpioPadNumberToController(InternalGpioPadNumber number) { + return (number >> 5); + } + + constexpr int ConvertInternalGpioPadNumberToPort(InternalGpioPadNumber number) { + return (number >> 3); + } + + constexpr int ConvertInternalGpioPadNumberToBitIndex(InternalGpioPadNumber number) { + return (number & 7); + } + + constexpr int ConvertPortNumberToOffset(int port_number) { + return (port_number & 3); + } + + struct PadNameToInternalPadNumberEntry { + GpioPadName pad_name; + InternalGpioPadNumber internal_number; + }; + + constexpr inline const PadNameToInternalPadNumberEntry PadNameToInternalPadNumberTable[] = { + { GpioPadName_PowSdEn, InternalGpioPadNumber_E4 }, + }; + + constexpr InternalGpioPadNumber ConvertPadNameToInternalPadNumber(GpioPadName pad) { + for (const auto &entry : PadNameToInternalPadNumberTable) { + if (entry.pad_name == pad) { + return entry.internal_number; + } + } + + AMS_ASSUME(false); + } + + enum GpioRegisterType { + GpioRegisterType_GPIO_CNF = 0, + GpioRegisterType_GPIO_OE = 1, + GpioRegisterType_GPIO_OUT = 2, + GpioRegisterType_GPIO_IN = 3, + GpioRegisterType_GPIO_INT_STA = 4, + GpioRegisterType_GPIO_INT_ENB = 5, + GpioRegisterType_GPIO_INT_LVL = 6, + GpioRegisterType_GPIO_INT_CLR = 7, + GpioRegisterType_GPIO_DB_CTRL = 8, + GpioRegisterType_GPIO_DB_CNT = 9, + }; + + constexpr inline uintptr_t MaskedWriteAddressOffset = 0x80; + constexpr inline int MaskedWriteBitOffset = 8; + + constexpr uintptr_t GetGpioRegisterAddress(uintptr_t gpio_address, GpioRegisterType reg_type, InternalGpioPadNumber pad_number) { + const auto controller = ConvertInternalGpioPadNumberToController(pad_number); + const auto port = ConvertInternalGpioPadNumberToPort(pad_number); + const auto offset = ConvertPortNumberToOffset(port); + + switch (reg_type) { + default: + return gpio_address + (0x100 * controller) + (0x10 * reg_type) + (0x4 * offset); + case GpioRegisterType_GPIO_DB_CTRL: + return gpio_address + (0x100 * controller) + (0x10 * GpioRegisterType_GPIO_IN) + (0x4 * offset); + case GpioRegisterType_GPIO_DB_CNT: + return gpio_address + (0x100 * controller) + MaskedWriteAddressOffset + (0x10 * GpioRegisterType_GPIO_INT_CLR) + (0x4 * offset); + } + } + + void SetMaskedBit(uintptr_t gpio_address, int index, int value) { + const uintptr_t mask_address = gpio_address + MaskedWriteAddressOffset; + + reg::Write(mask_address, (1u << (MaskedWriteBitOffset + index)) | (static_cast(value) << index)); + } + + } + void OpenSession(GpioPadName pad) { - /* TODO */ + /* Convert the pad to an internal number. */ + const auto pad_number = ConvertPadNameToInternalPadNumber(pad); + + /* Get the gpio registers address. */ + const uintptr_t gpio_address = dd::QueryIoMapping(GpioRegistersPhysicalAddress, GpioRegistersSize); + + /* Configure the pad as GPIO by setting the appropriate bit in CNF. */ + const uintptr_t pad_address = GetGpioRegisterAddress(gpio_address, GpioRegisterType_GPIO_CNF, pad_number); + const uintptr_t pad_index = ConvertInternalGpioPadNumberToBitIndex(pad_number); + SetMaskedBit(pad_address, pad_index, 1); + + /* Read the pad address to make sure our configuration takes. */ + reg::Read(pad_address); } void CloseSession(GpioPadName pad) { - /* TODO */ + /* Nothing needs to be done here, as the only thing official code does is unbind the interrupt event. */ + AMS_UNUSED(pad); } void SetDirection(GpioPadName pad, Direction direction) { - /* TODO */ + /* Convert the pad to an internal number. */ + const auto pad_number = ConvertPadNameToInternalPadNumber(pad); + + /* Get the gpio registers address. */ + const uintptr_t gpio_address = dd::QueryIoMapping(GpioRegistersPhysicalAddress, GpioRegistersSize); + + /* Configure the pad direction modifying the appropriate bit in OE. */ + const uintptr_t pad_address = GetGpioRegisterAddress(gpio_address, GpioRegisterType_GPIO_OE, pad_number); + const uintptr_t pad_index = ConvertInternalGpioPadNumberToBitIndex(pad_number); + SetMaskedBit(pad_address, pad_index, direction); + + /* Read the pad address to make sure our configuration takes. */ + reg::Read(pad_address); } void SetValue(GpioPadName pad, GpioValue value) { - /* TODO */ + /* Convert the pad to an internal number. */ + const auto pad_number = ConvertPadNameToInternalPadNumber(pad); + + /* Get the gpio registers address. */ + const uintptr_t gpio_address = dd::QueryIoMapping(GpioRegistersPhysicalAddress, GpioRegistersSize); + + /* Configure the pad value modifying the appropriate bit in OUT. */ + const uintptr_t pad_address = GetGpioRegisterAddress(gpio_address, GpioRegisterType_GPIO_OUT, pad_number); + const uintptr_t pad_index = ConvertInternalGpioPadNumberToBitIndex(pad_number); + SetMaskedBit(pad_address, pad_index, value); + + /* Read the pad address to make sure our configuration takes. */ + reg::Read(pad_address); }