mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-03 11:11:14 +00:00
sdmmc: skeleton implementation of Sdmmc1Controller
This commit is contained in:
parent
53957bb5c7
commit
bd9b01e405
11 changed files with 581 additions and 9 deletions
|
@ -27,6 +27,7 @@
|
|||
//#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_OS_EVENTS
|
||||
//#define AMS_SDMMC_USE_OS_TIMER
|
||||
#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
|
@ -36,6 +37,7 @@
|
|||
//#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_OS_EVENTS
|
||||
//#define AMS_SDMMC_USE_OS_TIMER
|
||||
#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
|
@ -45,6 +47,7 @@
|
|||
#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_OS_EVENTS
|
||||
#define AMS_SDMMC_USE_OS_TIMER
|
||||
//#define AMS_SDMMC_USE_UTIL_TIMER
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#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)
|
||||
|
||||
|
@ -52,6 +54,11 @@ 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);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_port_mmc0.hpp"
|
||||
#include "sdmmc_select_sdmmc_controller.hpp"
|
||||
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
SdmmcControllerForPortGcAsic0 g_gc_asic0_host_controller;
|
||||
|
||||
}
|
||||
|
||||
IHostController *GetHostControllerOfPortGcAsic0() {
|
||||
return std::addressof(g_gc_asic0_host_controller);
|
||||
}
|
||||
|
||||
}
|
|
@ -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.hpp>
|
||||
#include "sdmmc_i_host_controller.hpp"
|
||||
#include "sdmmc_i_device_accessor.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
IHostController *GetHostControllerOfPortGcAsic0();
|
||||
IDeviceAccessor *GetDeviceAccessorOfPortGcAsic0();
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ namespace ams::sdmmc::impl {
|
|||
|
||||
namespace {
|
||||
|
||||
SdmmcControllerForMmc g_mmc0_host_controller;
|
||||
SdmmcControllerForPortMmc0 g_mmc0_host_controller;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 <vapours.hpp>
|
||||
#include "sdmmc_port_mmc0.hpp"
|
||||
#include "sdmmc_select_sdmmc_controller.hpp"
|
||||
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
SdmmcControllerForPortSdCard0 g_sd_card0_host_controller;
|
||||
|
||||
}
|
||||
|
||||
IHostController *GetHostControllerOfPortSdCard0() {
|
||||
return std::addressof(g_sd_card0_host_controller);
|
||||
}
|
||||
|
||||
}
|
|
@ -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.hpp>
|
||||
#include "sdmmc_i_host_controller.hpp"
|
||||
#include "sdmmc_i_device_accessor.hpp"
|
||||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
IHostController *GetHostControllerOfPortSdCard0();
|
||||
IDeviceAccessor *GetDeviceAccessorOfPortSdCard0();
|
||||
|
||||
}
|
|
@ -869,4 +869,234 @@ namespace ams::sdmmc::impl {
|
|||
this->is_valid_tap_value_for_hs_400 = true;
|
||||
}
|
||||
|
||||
Result Sdmmc1Controller::PowerOnForRegisterControl(BusPower bus_power) {
|
||||
AMS_ABORT_UNLESS(bus_power == BusPower_3_3V);
|
||||
|
||||
/* Nintendo sets the current bus power regardless of whether the call succeeds. */
|
||||
ON_SCOPE_EXIT { this->current_bus_power = BusPower_3_3V; };
|
||||
|
||||
/* TODO: equivalent of return pcv::PowerOn(pcv::PowerControlTarget_SdCard, 3300000); */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::PowerOffForRegisterControl() {
|
||||
/* If we're already off, there's nothing to do. */
|
||||
if (this->current_bus_power == BusPower_Off) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're at 3.3V, lower to 1.8V. */
|
||||
{
|
||||
/* TODO: equivalent of pcv::ChangeVoltage(pcv::PowerControlTarget_SdCard, 1800000); */
|
||||
this->current_bus_power = BusPower_1_8V;
|
||||
}
|
||||
|
||||
/* TODO: Equivalent of pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1OutputHigh); */
|
||||
|
||||
/* TODO: Equivalent of pcv::PowerOff(pcv::PowerControlTarget_SdCard); */
|
||||
this->current_bus_power = BusPower_Off;
|
||||
|
||||
/* TODO: Equivalent of pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1ResetState); */
|
||||
}
|
||||
|
||||
Result Sdmmc1Controller::LowerBusPowerForRegisterControl() {
|
||||
/* Nintendo sets the current bus power regardless of whether the call succeeds. */
|
||||
ON_SCOPE_EXIT { this->current_bus_power = BusPower_1_8V; };
|
||||
|
||||
/* TODO: equivalent of return pcv::ChangeVoltage(pcv::PowerControlTarget_SdCard, 1800000); */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::SetSchmittTriggerForRegisterControl(BusPower bus_power) {
|
||||
SdHostStandardController::EnsureControl();
|
||||
|
||||
if (IsSocMariko()) {
|
||||
/* TODO: equivalent of pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtEnable); */
|
||||
} else {
|
||||
switch (bus_power) {
|
||||
case BusPower_1_8V:
|
||||
/* TODO: equivalent of pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtEnable); */
|
||||
break;
|
||||
case BusPower_3_3V:
|
||||
/* TODO: equivalent of pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtDisable); */
|
||||
break;
|
||||
case BusPower_Off:
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
Result Sdmmc1Controller::PowerOnForPcvControl(BusPower bus_power) {
|
||||
AMS_ABORT_UNLESS(bus_power == BusPower_3_3V);
|
||||
|
||||
/* Nintendo sets the current bus power regardless of whether the call succeeds. */
|
||||
ON_SCOPE_EXIT { this->current_bus_power = BusPower_3_3V; };
|
||||
|
||||
/* TODO: return pcv::PowerOn(pcv::PowerControlTarget_SdCard, 3300000); */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::PowerOffForPcvControl() {
|
||||
/* If we're already off, there's nothing to do. */
|
||||
if (this->current_bus_power == BusPower_Off) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're at 3.3V, lower to 1.8V. */
|
||||
{
|
||||
/* TODO: pcv::ChangeVoltage(pcv::PowerControlTarget_SdCard, 1800000); */
|
||||
this->current_bus_power = BusPower_1_8V;
|
||||
}
|
||||
|
||||
/* TODO: pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1OutputHigh); */
|
||||
|
||||
/* TODO: pcv::PowerOff(pcv::PowerControlTarget_SdCard); */
|
||||
this->current_bus_power = BusPower_Off;
|
||||
|
||||
/* TODO: pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1ResetState); */
|
||||
|
||||
}
|
||||
|
||||
Result Sdmmc1Controller::LowerBusPowerForPcvControl() {
|
||||
/* Nintendo sets the current bus power regardless of whether the call succeeds. */
|
||||
ON_SCOPE_EXIT { this->current_bus_power = BusPower_1_8V; };
|
||||
|
||||
/* TODO: return pcv::ChangeVoltage(pcv::PowerControlTarget_SdCard, 1800000); */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::SetSchmittTriggerForPcvControl(BusPower bus_power) {
|
||||
SdHostStandardController::EnsureControl();
|
||||
|
||||
if (IsSocMariko()) {
|
||||
/* TODO: pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtEnable); */
|
||||
} else {
|
||||
switch (bus_power) {
|
||||
case BusPower_1_8V:
|
||||
/* TODO: pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtEnable); */
|
||||
break;
|
||||
case BusPower_3_3V:
|
||||
/* TODO: pinmux::SetPinAssignment(std::addressof(this->pinmux_session), pinmux::PinAssignment_Sdmmc1SchmtDisable); */
|
||||
break;
|
||||
case BusPower_Off:
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Result Sdmmc1Controller::PowerOn(BusPower bus_power) {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
if (this->is_pcv_control) {
|
||||
return this->PowerOnForPcvControl(bus_power);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return this->PowerOnForRegisterControl(bus_power);
|
||||
}
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::PowerOff() {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
if (this->is_pcv_control) {
|
||||
return this->PowerOffForPcvControl();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return this->PowerOffForRegisterControl();
|
||||
}
|
||||
}
|
||||
|
||||
Result Sdmmc1Controller::LowerBusPower() {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
if (this->is_pcv_control) {
|
||||
return this->LowerBusPowerForPcvControl();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return this->LowerBusPowerForRegisterControl();
|
||||
}
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::SetSchmittTrigger(BusPower bus_power) {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
if (this->is_pcv_control) {
|
||||
return this->SetSchmittTriggerForPcvControl(bus_power);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return this->SetSchmittTriggerForRegisterControl(bus_power);
|
||||
}
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::Initialize() {
|
||||
return this->InitializeForRegisterControl();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::Finalize() {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
if (this->is_pcv_control) {
|
||||
return this->FinalizeForPcvControl();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return this->FinalizeForRegisterControl();
|
||||
}
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::InitializeForRegisterControl() {
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
/* Mark ourselves as initialized by register control. */
|
||||
this->is_pcv_control = false;
|
||||
#endif
|
||||
|
||||
/* TODO: equivalent of pinmux::Initialize(); */
|
||||
/* TODO: equivalent of pinmux::OpenSession(std::addressof(this->pinmux_session), pinmux::AssignablePinGroupName_Sdmmc1); */
|
||||
/* TODO: equivalent of pcv::Initialize(); */
|
||||
|
||||
/* Perform base initialization. */
|
||||
SdmmcController::Initialize();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::FinalizeForRegisterControl() {
|
||||
/* Perform base finalization. */
|
||||
SdmmcController::Finalize();
|
||||
|
||||
/* TODO: equivalent of pcv::Finalize(); */
|
||||
/* TODO: equivalent of pinmux::CloseSession(std::addressof(this->pinmux_session)); */
|
||||
/* TODO: equivalent of pinmux::Finalize(); */
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
/* Mark ourselves as initialized by register control. */
|
||||
this->is_pcv_control = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
void Sdmmc1Controller::InitializeForPcvControl() {
|
||||
/* Mark ourselves as initialized by pcv control. */
|
||||
this->is_pcv_control = true;
|
||||
|
||||
/* TODO: pinmux::Initialize(); */
|
||||
/* TODO: pinmux::OpenSession(std::addressof(this->pinmux_session), pinmux::AssignablePinGroupName_Sdmmc1); */
|
||||
/* TODO: pcv::Initialize(); */
|
||||
|
||||
/* Perform base initialization. */
|
||||
SdmmcController::Initialize();
|
||||
}
|
||||
|
||||
void Sdmmc1Controller::FinalizeForPcvControl() {
|
||||
/* Perform base finalization. */
|
||||
SdmmcController::Finalize();
|
||||
|
||||
/* TODO: pcv::Finalize(); */
|
||||
/* TODO: pinmux::CloseSession(std::addressof(this->pinmux_session)); */
|
||||
/* TODO: pinmux::Finalize(); */
|
||||
|
||||
/* Mark ourselves as initialized by register control. */
|
||||
this->is_pcv_control = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -203,6 +203,216 @@ namespace ams::sdmmc::impl {
|
|||
}
|
||||
};
|
||||
|
||||
constexpr inline dd::PhysicalAddress Sdmmc1RegistersPhysicalAddress = UINT64_C(0x700B0000);
|
||||
|
||||
class Sdmmc1Controller : public SdmmcController {
|
||||
private:
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
static constinit inline os::InterruptEventType s_interrupt_event{};
|
||||
#endif
|
||||
private:
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
/* TODO: pinmux::PinmuxSession pinmux_session; */
|
||||
#endif
|
||||
BusPower current_bus_power;
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
bool is_pcv_control;
|
||||
#endif
|
||||
private:
|
||||
Result PowerOnForRegisterControl(BusPower bus_power);
|
||||
void PowerOffForRegisterControl();
|
||||
Result LowerBusPowerForRegisterControl();
|
||||
void SetSchmittTriggerForRegisterControl(BusPower bus_power);
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
Result PowerOnForPcvControl(BusPower bus_power);
|
||||
void PowerOffForPcvControl();
|
||||
Result LowerBusPowerForPcvControl();
|
||||
void SetSchmittTriggerForPcvControl(BusPower bus_power);
|
||||
#endif
|
||||
protected:
|
||||
virtual void SetPad() override {
|
||||
/* Nothing is needed here. */
|
||||
}
|
||||
|
||||
virtual ClockResetController::Module GetClockResetModule() const override {
|
||||
return ClockResetController::Module_Sdmmc1;
|
||||
}
|
||||
|
||||
#if defined(AMS_SDMMC_USE_OS_EVENTS)
|
||||
virtual int GetInterruptNumber() const override {
|
||||
return 46;
|
||||
}
|
||||
|
||||
virtual os::InterruptEventType *GetInterruptEvent() const override {
|
||||
return std::addressof(s_interrupt_event);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool IsNeedPeriodicDriveStrengthCalibration() override {
|
||||
return !IsSocMariko();
|
||||
}
|
||||
|
||||
virtual void ClearPadParked() override {
|
||||
/* Nothing is needed here. */
|
||||
}
|
||||
|
||||
virtual Result PowerOn(BusPower bus_power) override;
|
||||
virtual void PowerOff() override;
|
||||
virtual Result LowerBusPower() override;
|
||||
|
||||
virtual void SetSchmittTrigger(BusPower bus_power) override;
|
||||
|
||||
virtual u8 GetOutboundTapValue() const override {
|
||||
if (IsSocMariko()) {
|
||||
return 0xE;
|
||||
} else {
|
||||
return 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
virtual u8 GetDefaultInboundTapValue() const override {
|
||||
if (IsSocMariko()) {
|
||||
return 0xB;
|
||||
} else {
|
||||
return 0x4;
|
||||
}
|
||||
}
|
||||
|
||||
virtual u8 GetVrefSelValue() const override {
|
||||
if (IsSocMariko()) {
|
||||
return 0x0;
|
||||
} else {
|
||||
return 0x7;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetSlewCodes() override {
|
||||
if (IsSocMariko()) {
|
||||
/* Do nothing. */
|
||||
} else {
|
||||
/* Ensure that we can control registers. */
|
||||
SdHostStandardController::EnsureControl();
|
||||
|
||||
/* Get the apb registers address. */
|
||||
const uintptr_t apb_address = dd::QueryIoMapping(ApbMiscRegistersPhysicalAddress, ApbMiscRegistersSize);
|
||||
|
||||
/* Write the slew values to APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL. */
|
||||
reg::ReadWrite(apb_address + APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL, APB_MISC_REG_BITS_VALUE(GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_CLK_CFG_CAL_DRVDN_SLWR, 0x1),
|
||||
APB_MISC_REG_BITS_VALUE(GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_CLK_CFG_CAL_DRVDN_SLWF, 0x1));
|
||||
|
||||
/* Read to be sure our config takes. */
|
||||
reg::Read(apb_address + APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void GetAutoCalOffsets(u8 *out_auto_cal_pd_offset, u8 *out_auto_cal_pu_offset, BusPower bus_power) const override {
|
||||
/* Ensure that we can write the offsets. */
|
||||
AMS_ABORT_UNLESS(out_auto_cal_pd_offset != nullptr);
|
||||
AMS_ABORT_UNLESS(out_auto_cal_pu_offset != nullptr);
|
||||
|
||||
/* Set the offsets. */
|
||||
if (IsSocMariko()) {
|
||||
switch (bus_power) {
|
||||
case BusPower_1_8V:
|
||||
*out_auto_cal_pd_offset = 6;
|
||||
*out_auto_cal_pu_offset = 6;
|
||||
break;
|
||||
case BusPower_3_3V:
|
||||
*out_auto_cal_pd_offset = 0;
|
||||
*out_auto_cal_pu_offset = 0;
|
||||
break;
|
||||
case BusPower_Off:
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
} else {
|
||||
switch (bus_power) {
|
||||
case BusPower_1_8V:
|
||||
*out_auto_cal_pd_offset = 0x7B;
|
||||
*out_auto_cal_pu_offset = 0x7B;
|
||||
break;
|
||||
case BusPower_3_3V:
|
||||
*out_auto_cal_pd_offset = 0x7D;
|
||||
*out_auto_cal_pu_offset = 0;
|
||||
break;
|
||||
case BusPower_Off:
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDriveStrengthToDefaultValues(BusPower bus_power) override {
|
||||
/* Ensure that we can control registers. */
|
||||
SdHostStandardController::EnsureControl();
|
||||
|
||||
/* Get the apb registers address. */
|
||||
const uintptr_t apb_address = dd::QueryIoMapping(ApbMiscRegistersPhysicalAddress, ApbMiscRegistersSize);
|
||||
|
||||
/* Determine the drive code values. */
|
||||
u8 drvdn, drvup;
|
||||
if (IsSocMariko()) {
|
||||
drvdn = 0x8;
|
||||
drvup = 0x8;
|
||||
} else {
|
||||
switch (bus_power) {
|
||||
case BusPower_1_8V:
|
||||
drvdn = 0xF;
|
||||
drvup = 0xB;
|
||||
break;
|
||||
case BusPower_3_3V:
|
||||
drvdn = 0xC;
|
||||
drvup = 0xC;
|
||||
break;
|
||||
case BusPower_Off:
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the drv up/down values to APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL. */
|
||||
reg::ReadWrite(apb_address + APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL, APB_MISC_REG_BITS_VALUE(GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_PAD_CAL_DRVDN, drvdn),
|
||||
APB_MISC_REG_BITS_VALUE(GP_SDMMC1_PAD_CFGPADCTRL_CFG2TMC_SDMMC1_PAD_CAL_DRVUP, drvup));
|
||||
|
||||
/* Read to be sure our config takes. */
|
||||
reg::Read(apb_address + APB_MISC_GP_EMMC4_PAD_CFGPADCTRL);
|
||||
}
|
||||
public:
|
||||
Sdmmc1Controller() : SdmmcController(Sdmmc1RegistersPhysicalAddress) {
|
||||
this->current_bus_power = BusPower_Off;
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
this->is_pcv_control = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Initialize() override;
|
||||
virtual void Finalize() override;
|
||||
|
||||
void InitializeForRegisterControl();
|
||||
void FinalizeForRegisterControl();
|
||||
|
||||
#if defined(AMS_SDMMC_USE_PCV_CLOCK_RESET_CONTROL)
|
||||
void InitializeForPcvControl();
|
||||
void FinalizeForPcvControl();
|
||||
#endif
|
||||
|
||||
virtual bool IsSupportedBusPower(BusPower bus_power) const override {
|
||||
switch (bus_power) {
|
||||
case BusPower_Off: return true;
|
||||
case BusPower_1_8V: return true;
|
||||
case BusPower_3_3V: return true;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool IsSupportedBusWidth(BusWidth bus_width) const override {
|
||||
switch (bus_width) {
|
||||
case BusWidth_1Bit: return true;
|
||||
case BusWidth_4Bit: return true;
|
||||
case BusWidth_8Bit: return false;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Sdmmc2And4Controller : public SdmmcController {
|
||||
protected:
|
||||
virtual bool IsNeedPeriodicDriveStrengthCalibration() override {
|
||||
|
@ -330,7 +540,7 @@ namespace ams::sdmmc::impl {
|
|||
}
|
||||
|
||||
virtual void SetDriveStrengthToDefaultValues(BusPower bus_power) override {
|
||||
/* SDMMC4 only supports 1.8v. */
|
||||
/* SDMMC2 only supports 1.8v. */
|
||||
AMS_ABORT_UNLESS(bus_power == BusPower_1_8V);
|
||||
|
||||
/* Ensure that we can control registers. */
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
namespace ams::sdmmc::impl {
|
||||
|
||||
using SdmmcControllerForMmc = Sdmmc4Controller;
|
||||
using SdmmcControllerForPortSdCard0 = Sdmmc1Controller;
|
||||
using SdmmcControllerForPortGcAsic0 = Sdmmc2Controller;
|
||||
using SdmmcControllerForPortMmc0 = Sdmmc4Controller;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "impl/sdmmc_i_device_accessor.hpp"
|
||||
#include "impl/sdmmc_clock_reset_controller.hpp"
|
||||
#include "impl/sdmmc_port_mmc0.hpp"
|
||||
#include "impl/sdmmc_port_sd_card0.hpp"
|
||||
#include "impl/sdmmc_port_gc_asic0.hpp"
|
||||
|
||||
namespace ams::sdmmc {
|
||||
|
||||
|
@ -27,9 +29,9 @@ namespace ams::sdmmc {
|
|||
/* Get the controller. */
|
||||
impl::IHostController *host_controller = nullptr;
|
||||
switch (port) {
|
||||
case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break;
|
||||
case Port_SdCard0: /* TODO */ break;
|
||||
case Port_GcAsic0: /* TODO */ break;
|
||||
case Port_Mmc0: host_controller = impl::GetHostControllerOfPortMmc0(); break;
|
||||
case Port_SdCard0: host_controller = impl::GetHostControllerOfPortSdCard0(); break;
|
||||
case Port_GcAsic0: host_controller = impl::GetHostControllerOfPortGcAsic0(); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
|
@ -42,9 +44,9 @@ namespace ams::sdmmc {
|
|||
/* Get the accessor. */
|
||||
impl::IDeviceAccessor *device_accessor = nullptr;
|
||||
switch (port) {
|
||||
case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break;
|
||||
case Port_SdCard0: /* TODO */ break;
|
||||
case Port_GcAsic0: /* TODO */ break;
|
||||
case Port_Mmc0: device_accessor = impl::GetDeviceAccessorOfPortMmc0(); break;
|
||||
case Port_SdCard0: device_accessor = impl::GetDeviceAccessorOfPortSdCard0(); break;
|
||||
case Port_GcAsic0: device_accessor = impl::GetDeviceAccessorOfPortGcAsic0(); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue