Atmosphere-libs/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.hpp
2021-10-15 23:54:35 -07:00

144 lines
7.5 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/>.
*/
#pragma once
#include <vapours.hpp>
#include "sdmmc_base_device_accessor.hpp"
namespace ams::sdmmc::impl {
class MmcDevice : public BaseDevice {
private:
static constexpr u16 Rca = 2;
public:
#if defined(AMS_SDMMC_USE_OS_EVENTS)
virtual os::EventType *GetRemovedEvent() const override {
/* Mmc can't be removed. */
return nullptr;
}
#endif
virtual DeviceType GetDeviceType() const override {
return DeviceType_Mmc;
}
virtual u16 GetRca() const override {
return Rca;
}
void SetOcrAndHighCapacity(u32 ocr);
};
class MmcDeviceAccessor : public BaseDeviceAccessor {
private:
MmcDevice m_mmc_device;
void *m_work_buffer;
size_t m_work_buffer_size;
BusWidth m_max_bus_width;
SpeedMode m_max_speed_mode;
MmcPartition m_current_partition;
bool m_is_initialized;
private:
enum CommandSwitch {
CommandSwitch_SetBitsProductionStateAwarenessEnable = 0,
CommandSwitch_ClearBitsAutoModeEnable = 1,
CommandSwitch_WriteProductionStateAwarenessNormal = 2,
CommandSwitch_WriteProductionStateAwarenessPreSolderingWrites = 3,
CommandSwitch_WriteProductionStateAwarenessPreSolderingPostWrites = 4,
CommandSwitch_SetBitsBkopsEnAutoEn = 5,
CommandSwitch_WriteBusWidth1Bit = 6,
CommandSwitch_WriteBusWidth4Bit = 7,
CommandSwitch_WriteBusWidth8Bit = 8,
CommandSwitch_WriteBusWidth8BitDdr = 9,
CommandSwitch_WriteHsTimingLegacySpeed = 10,
CommandSwitch_WriteHsTimingHighSpeed = 11,
CommandSwitch_WriteHsTimingHs200 = 12,
CommandSwitch_WriteHsTimingHs400 = 13,
CommandSwitch_WritePartitionAccessDefault = 14,
CommandSwitch_WritePartitionAccessRwBootPartition1 = 15,
CommandSwitch_WritePartitionAccessRwBootPartition2 = 16,
};
static constexpr ALWAYS_INLINE u32 GetCommandSwitchArgument(CommandSwitch cs) {
switch (cs) {
case CommandSwitch_SetBitsProductionStateAwarenessEnable: return 0x01111000;
case CommandSwitch_ClearBitsAutoModeEnable: return 0x02112000;
case CommandSwitch_WriteProductionStateAwarenessNormal: return 0x03850000;
case CommandSwitch_WriteProductionStateAwarenessPreSolderingWrites: return 0x03850100;
case CommandSwitch_WriteProductionStateAwarenessPreSolderingPostWrites: return 0x03850200;
case CommandSwitch_SetBitsBkopsEnAutoEn: return 0x01A30200;
case CommandSwitch_WriteBusWidth1Bit: return 0x03B70000;
case CommandSwitch_WriteBusWidth4Bit: return 0x03B70100;
case CommandSwitch_WriteBusWidth8Bit: return 0x03B70200;
case CommandSwitch_WriteBusWidth8BitDdr: return 0x03B70600;
case CommandSwitch_WriteHsTimingLegacySpeed: return 0x03B90000;
case CommandSwitch_WriteHsTimingHighSpeed: return 0x03B90100;
case CommandSwitch_WriteHsTimingHs200: return 0x03B90200;
case CommandSwitch_WriteHsTimingHs400: return 0x03B90300;
case CommandSwitch_WritePartitionAccessDefault: return 0x03B30000;
case CommandSwitch_WritePartitionAccessRwBootPartition1: return 0x03B30100;
case CommandSwitch_WritePartitionAccessRwBootPartition2: return 0x03B30200;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
private:
Result IssueCommandSendOpCond(u32 *out_ocr, BusPower bus_power) const;
Result IssueCommandSetRelativeAddr() const;
Result IssueCommandSwitch(CommandSwitch cs) const;
Result IssueCommandSendExtCsd(void *dst, size_t dst_size) const;
Result IssueCommandEraseGroupStart(u32 sector_index) const;
Result IssueCommandEraseGroupEnd(u32 sector_index) const;
Result IssueCommandErase() const;
Result CancelToshibaMmcModel();
Result ChangeToReadyState(BusPower bus_power);
Result ExtendBusWidth(BusWidth max_bus_width);
Result EnableBkopsAuto();
Result ChangeToHighSpeed(bool check_before);
Result ChangeToHs200();
Result ChangeToHs400();
Result ExtendBusSpeed(u8 device_type, SpeedMode max_sm);
Result StartupMmcDevice(BusWidth max_bw, SpeedMode max_sm, void *wb, size_t wb_size);
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;
public:
virtual void Initialize() override;
virtual void Finalize() override;
virtual Result GetSpeedMode(SpeedMode *out_speed_mode) const override;
public:
explicit MmcDeviceAccessor(IHostController *hc)
: BaseDeviceAccessor(hc), m_work_buffer(nullptr), m_work_buffer_size(0),
m_max_bus_width(BusWidth_8Bit), m_max_speed_mode(SpeedMode_MmcHs400), m_current_partition(MmcPartition_Unknown),
m_is_initialized(false)
{
/* ... */
}
void SetMmcWorkBuffer(void *wb, size_t wb_size) {
m_work_buffer = wb;
m_work_buffer_size = wb_size;
}
void PutMmcToSleep();
void AwakenMmc();
Result SelectMmcPartition(MmcPartition part);
Result EraseMmc();
Result GetMmcBootPartitionCapacity(u32 *out_num_sectors) const;
Result GetMmcExtendedCsd(void *dst, size_t dst_size) const;
};
}