2024-10-08 16:10:27 +08:00

894 lines
30 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of libn3ds
* Copyright (C) 2024 derrek, profi200
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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.
*
* 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 <string.h>
#include "drivers/mmc/sdmmc.h" // Includes types.h.
#include "drivers/tmio.h"
#include "drivers/tmio_config.h"
#ifdef __ARM9__
#include "arm9/drivers/timer.h"
#elif __ARM11__
#include "arm11/drivers/timer.h"
#endif // #ifdef __ARM9__
#include "drivers/mmc/mmc_spec.h"
#include "drivers/mmc/sd_spec.h"
// Note on INIT_CLOCK:
// 400 kHz is allowed by the specs. 523 kHz has been proven to work reliably
// for SD cards and eMMC but very early MMCs can fail at init.
// We lose about 5 ms of time on init by using 261 kHz.
#define INIT_CLOCK (400000u) // Maximum 400 kHz.
#define DEFAULT_CLOCK (20000000u) // Maximum 20 MHz.
#define HS_CLOCK (50000000u) // Maximum 50 MHz.
#define MMC_OCR_VOLT_MASK (MMC_OCR_3_2_3_3V) // We support 3.3V only.
#define SD_OCR_VOLT_MASK (SD_OCR_3_2_3_3V) // We support 3.3V only.
#define SD_IF_COND_ARG (SD_CMD8_VHS_2_7_3_6V | SD_CMD8_CHK_PATT)
#define SD_OP_COND_ARG (SD_ACMD41_XPC | SD_OCR_VOLT_MASK) // We support 150 mA and 3.3V. Without HCS bit.
#define MMC_OP_COND_ARG (MMC_OCR_SECT_MODE | MMC_OCR_VOLT_MASK) // We support sector addressing and 3.3V.
// Note: DEV_TYPE_NONE must be zero.
enum
{
// Device types.
DEV_TYPE_NONE = 0u, // Unitialized/no device.
DEV_TYPE_MMC = 1u, // (e)MMC.
DEV_TYPE_MMCHC = 2u, // High capacity (e)MMC (>2 GB).
DEV_TYPE_SDSC = 3u, // SDSC.
DEV_TYPE_SDHC = 4u, // SDHC, SDXC.
DEV_TYPE_SDUC = 5u // SDUC.
};
#define IS_DEV_MMC(dev) ((dev) < DEV_TYPE_SDSC)
typedef struct
{
TmioPort port;
u8 type; // Device type. 0 = none, 1 = (e)MMC, 2 = High capacity (e)MMC,
// 3 = SDSC, 4 = SDHC/SDXC, 5 = SDUC.
u8 prot; // Protection bits. Each bit 1 = protected.
// Bit 0 SD card slider, bit 1 temporary write protection (CSD),
// bit 2 permanent write protection (CSD) and bit 3 password protection.
u16 rca; // Relative Card Address (RCA).
u16 ccc; // (e)MMC/SD command class support from CSD. One per bit starting at 0.
u32 sectors; // Size in 512 byte units.
u32 status; // R1 card status on error. Only updated on errors.
// Cached card infos.
u32 cid[4]; // Raw CID without the CRC.
} SdmmcDev;
static SdmmcDev g_devs[2] = {0};
static u32 sendAppCmd(TmioPort *const port, const u16 cmd, const u32 arg, const u32 rca)
{
// Send app CMD. Same CMD for (e)MMC/SD.
// TODO: Check the APP_CMD bit in the response?
// Linux does it but is it really necessary? SD spec 4.3.9.1.
u32 res = TMIO_sendCommand(port, MMC_APP_CMD, rca);
if(res == 0)
{
res = TMIO_sendCommand(port, cmd, arg);
}
return res;
}
static u32 goIdleState(TmioPort *const port)
{
// Enter idle state before we start the init procedure.
// Works from all but inactive state. CMD is the same for (e)MMC/SD.
// For (e)MMC there are optional init paths:
// arg = 0x00000000 -> GO_IDLE_STATE.
// arg = 0xF0F0F0F0 -> GO_PRE_IDLE_STATE.
// arg = 0xFFFFFFFA -> BOOT_INITIATION.
u32 res = TMIO_sendCommand(port, MMC_GO_IDLE_STATE, 0);
if(res != 0) return SDMMC_ERR_GO_IDLE_STATE;
return SDMMC_ERR_NONE;
}
static u32 initIdleState(TmioPort *const port, u8 *const devTypeOut)
{
// Tell the card what interfaces and voltages we support.
// Only SD v2 and up will respond. (e)MMC won't respond.
u32 res = TMIO_sendCommand(port, SD_SEND_IF_COND, SD_IF_COND_ARG);
if(res == 0)
{
// If the card supports the interfaces and voltages
// it should echo back the check pattern and set the
// support bits.
// Since we don't support anything but the
// standard SD interface at 3.3V we can check
// the whole response at once.
if(port->resp[0] != SD_IF_COND_ARG) return SDMMC_ERR_IF_COND_RESP;
}
else if(res != STATUS_ERR_CMD_TIMEOUT) return SDMMC_ERR_SEND_IF_COND; // Card responded but an error occured.
// Send the first app CMD. If this times out it's (e)MMC.
// If SEND_IF_COND timed out tell the SD card we are a v1 host.
const u32 opCondArg = SD_OP_COND_ARG | (res<<8 ^ SD_ACMD41_HCS); // Caution! Controller specific hack.
u8 devType = DEV_TYPE_SDSC;
res = sendAppCmd(port, SD_APP_SD_SEND_OP_COND, opCondArg, 0);
if(res == STATUS_ERR_CMD_TIMEOUT) devType = DEV_TYPE_MMC; // Continue with (e)MMC init.
else if(res != 0) return SDMMC_ERR_SEND_OP_COND; // Unknown error.
if(devType == DEV_TYPE_MMC) // (e)MMC.
{
// Loop until a timeout of 1 second or the card is ready.
u32 tries = 200;
u32 ocr;
while(1)
{
res = TMIO_sendCommand(port, MMC_SEND_OP_COND, MMC_OP_COND_ARG);
if(res != 0) return SDMMC_ERR_SEND_OP_COND;
ocr = port->resp[0];
if(!--tries || (ocr & MMC_OCR_READY)) break;
// Linux uses 10 ms but the card doesn't become ready faster
// when polling with delay. Use 5 ms as compromise so not much
// time is wasted when the card becomes ready in the middle of the delay.
TIMER_sleepMs(5);
}
// (e)MMC didn't finish init within 1 second.
if(tries == 0) return SDMMC_ERR_OP_COND_TMOUT;
// Check if the (e)MMC supports the voltage and if it's high capacity.
if(!(ocr & MMC_OCR_VOLT_MASK)) return SDMMC_ERR_VOLT_SUPPORT; // Voltage not supported.
if(ocr & MMC_OCR_SECT_MODE) devType = DEV_TYPE_MMCHC; // 7.4.3.
}
else // SD card.
{
// Loop until a timeout of 1 second or the card is ready.
u32 tries = 200;
u32 ocr;
while(1)
{
ocr = port->resp[0];
if(!--tries || (ocr & SD_OCR_READY)) break;
// Linux uses 10 ms but the card doesn't become ready faster
// when polling with delay. Use 5 ms as compromise so not much
// time is wasted when the card becomes ready in the middle of the delay.
TIMER_sleepMs(5);
res = sendAppCmd(port, SD_APP_SD_SEND_OP_COND, opCondArg, 0);
if(res != 0) return SDMMC_ERR_SEND_OP_COND;
}
// SD card didn't finish init within 1 second.
if(tries == 0) return SDMMC_ERR_OP_COND_TMOUT;
if(!(ocr & SD_OCR_VOLT_MASK)) return SDMMC_ERR_VOLT_SUPPORT; // Voltage not supported.
if(ocr & SD_OCR_CCS) devType = DEV_TYPE_SDHC;
}
*devTypeOut = devType;
return SDMMC_ERR_NONE;
}
static u32 initReadyState(SdmmcDev *const dev)
{
TmioPort *const port = &dev->port;
// SD card voltage switch sequence goes here if supported.
// Get the CID. CMD is the same for (e)MMC/SD.
u32 res = TMIO_sendCommand(port, MMC_ALL_SEND_CID, 0);
if(res != 0) return SDMMC_ERR_ALL_SEND_CID;
memcpy(dev->cid, port->resp, 16);
return SDMMC_ERR_NONE;
}
static u32 initIdentState(SdmmcDev *const dev, const u8 devType, u32 *const rcaOut)
{
TmioPort *const port = &dev->port;
u32 rca;
if(IS_DEV_MMC(devType)) // (e)MMC.
{
// Set the RCA of the (e)MMC to 1. 0 is reserved.
// The RCA is in the upper 16 bits of the argument.
rca = 1;
u32 res = TMIO_sendCommand(port, MMC_SET_RELATIVE_ADDR, rca<<16);
if(res != 0) return SDMMC_ERR_SET_SEND_RCA;
}
else // SD card.
{
// Ask the SD card to send its RCA.
u32 res = TMIO_sendCommand(port, SD_SEND_RELATIVE_ADDR, 0);
if(res != 0) return SDMMC_ERR_SET_SEND_RCA;
// RCA in upper 16 bits. Discards lower status bits of R6 response.
rca = port->resp[0]>>16;
}
dev->rca = rca;
*rcaOut = rca<<16;
return SDMMC_ERR_NONE;
}
// Based on UNSTUFF_BITS from linux/drivers/mmc/core/sd.c.
// Extracts up to 32 bits from a u32[4] array.
static inline u32 extractBits(const u32 resp[4], const u32 start, const u32 size)
{
const u32 mask = (size < 32 ? BIT(size) : 0u) - 1;
const u32 off = 3 - (start / 32);
const u32 shift = start & 31u;
u32 res = resp[off]>>shift;
if(size + shift > 32)
res |= resp[off - 1]<<((32u - shift) & 31u);
return res & mask;
}
static void parseCsd(SdmmcDev *const dev, const u8 devType, u8 *const spec_vers_out)
{
// Note: The MSBs are in csd[0].
const u32 *const csd = dev->port.resp;
const u8 structure = extractBits(csd, 126, 2); // [127:126]
*spec_vers_out = extractBits(csd, 122, 4); // [125:122] All 0 for SD cards.
dev->ccc = extractBits(csd, 84, 12); // [95:84]
u32 sectors = 0;
if(structure == 0 || devType == DEV_TYPE_MMC) // structure = 0 is CSD version 1.0.
{
const u32 read_bl_len = extractBits(csd, 80, 4); // [83:80]
const u32 c_size = extractBits(csd, 62, 12); // [73:62]
const u32 c_size_mult = extractBits(csd, 47, 3); // [49:47]
// For SD cards with CSD 1.0 and <=2 GB (e)MMC this calculation is used.
// Note: READ_BL_LEN is at least 9.
// Modified/simplified to calculate sectors instead of bytes.
sectors = (c_size + 1)<<(c_size_mult + 2 + read_bl_len - 9);
}
else if(devType != DEV_TYPE_MMCHC)
{
// SD CSD version 3.0 format.
// For version 2.0 this is 22 bits however the upper bits
// are reserved and zero filled so this is fine.
const u32 c_size = extractBits(csd, 48, 28); // [75:48]
// Calculation for SD cards with CSD >1.0.
sectors = (c_size + 1)<<10;
}
// Else for high capacity (e)MMC the sectors will be read later from EXT_CSD.
dev->sectors = sectors;
// Parse temporary and permanent write protection bits.
u8 prot = extractBits(csd, 12, 1)<<1; // [12:12] Not checked by Linux.
prot |= extractBits(csd, 13, 1)<<2; // [13:13]
dev->prot |= prot;
}
static u32 initStandbyState(SdmmcDev *const dev, const u8 devType, const u32 rca, u8 *const spec_vers_out)
{
TmioPort *const port = &dev->port;
// Get the CSD. CMD is the same for (e)MMC/SD.
u32 res = TMIO_sendCommand(port, MMC_SEND_CSD, rca);
if(res != 0) return SDMMC_ERR_SEND_CSD;
parseCsd(dev, devType, spec_vers_out);
// CMD is the same for (e)MMC/SD however both R1 and R1b responses are used.
// We assume R1b and hope it doesn't time out.
res = TMIO_sendCommand(port, MMC_SELECT_CARD, rca);
if(res != 0) return SDMMC_ERR_SELECT_CARD;
// The SD card spec mentions that we should check the lock bit in the
// response to CMD7 to identify cards requiring a password to unlock.
// Same seems to apply for (e)MMC.
// Same bit for (e)MMC/SD R1 card status.
dev->prot |= (port->resp[0] & MMC_R1_CARD_IS_LOCKED)>>22; // Bit 3.
return SDMMC_ERR_NONE;
}
// TODO: Set the timeout based on clock speed (Tmio uses SDCLK for timeouts).
// The tmio driver sets a sane default but we should calculate it anyway.
static u32 initTranState(SdmmcDev *const dev, const u8 devType, const u32 rca, const u8 spec_vers)
{
TmioPort *const port = &dev->port;
if(IS_DEV_MMC(devType)) // (e)MMC.
{
// EXT_CSD, non-1 bit bus width and HS timing are only
// supported by (e)MMC SPEC_VERS 4.1 and higher.
if(spec_vers > 3) // Version 4.14.24.3 or higher.
{
// The (e)MMC spec says to check the card status after a SWITCH CMD (7.6.1).
// I think we can get away without checking this because support for HS timing
// and 4 bit bus width is mandatory for this spec version. If the card is
// non-standard we will encounter errors on the next CMD anyway.
// Switch to high speed timing (max. 52 MHz).
const u32 hsArg = MMC_SWITCH_ARG(MMC_SWITCH_ACC_WR_BYTE, EXT_CSD_HS_TIMING, 1, 0);
u32 res = TMIO_sendCommand(port, MMC_SWITCH, hsArg);
if(res != 0) return SDMMC_ERR_SWITCH_HS;
TMIO_setClock(port, HS_CLOCK);
// Switch to 4 bit bus mode.
const u32 busWidthArg = MMC_SWITCH_ARG(MMC_SWITCH_ACC_WR_BYTE, EXT_CSD_BUS_WIDTH, 1, 0);
res = TMIO_sendCommand(port, MMC_SWITCH, busWidthArg);
if(res != 0) return SDMMC_ERR_SET_BUS_WIDTH;
TMIO_setBusWidth(port, 4);
// We should also check in the EXT_CSD the power budget for the card.
// Nintendo seems to leave it on default (no change).
if(devType == DEV_TYPE_MMCHC)
{
// Note: The EXT_CSD is normally read before touching HS timing and bus width.
// We can take advantage of the faster data transfer with this order.
alignas(4) u8 ext_csd[512];
TMIO_setBuffer(port, (u32*)ext_csd, 1);
res = TMIO_sendCommand(port, MMC_SEND_EXT_CSD, 0);
if(res != 0) return SDMMC_ERR_SEND_EXT_CSD;
// Get sector count from EXT_CSD only if sector addressing is used because
// byte addressed (e)MMC may set sector count to 0.
dev->sectors = ext_csd[EXT_CSD_SEC_COUNT + 3]<<24 | ext_csd[EXT_CSD_SEC_COUNT + 2]<<16 |
ext_csd[EXT_CSD_SEC_COUNT + 1]<<8 | ext_csd[EXT_CSD_SEC_COUNT + 0];
}
}
}
else // SD card.
{
// Remove DAT3 pull-up. Linux doesn't do it but the SD spec recommends it.
u32 res = sendAppCmd(port, SD_APP_SET_CLR_CARD_DETECT, 0, rca); // arg = 0 removes the pull-up.
if(res != 0) return SDMMC_ERR_SET_CLR_CD;
// Switch to 4 bit bus mode.
res = sendAppCmd(port, SD_APP_SET_BUS_WIDTH, 2, rca); // arg = 2 is 4 bit bus width.
if(res != 0) return SDMMC_ERR_SET_BUS_WIDTH;
TMIO_setBusWidth(port, 4);
if(dev->ccc & BIT(10)) // Class 10 command support.
{
// Set 64 bytes block length for SWITCH_FUNC status.
TMIO_setBlockLen(port, 64);
alignas(4) u8 switchStat[64]; // MSB first and big endian.
TMIO_setBuffer(port, (u32*)switchStat, 1);
const u32 arg = SD_SWITCH_FUNC_ARG(1, 0xF, 0xF, 0xF, 1);
res = TMIO_sendCommand(port, SD_SWITCH_FUNC, arg);
if(res != 0) return SDMMC_ERR_SWITCH_HS;
// Restore default 512 bytes block length.
TMIO_setBlockLen(port, 512);
// [415:400] Support Bits of Functions in Function Group 1.
if(switchStat[63u - 400 / 8] & BIT(1)) // Is group 1, function 1 "High-Speed" supported?
{
// High-Speed (max. 50 MHz at 3.3V) supported. Switch to highest supported clock.
TMIO_setClock(port, HS_CLOCK);
}
}
}
// SD: The description for CMD SET_BLOCKLEN says 512 bytes is the default.
// (e)MMC: The description for READ_BL_LEN (CSD) says 512 bytes is the default.
// So it's not required to set the block length.
return SDMMC_ERR_NONE;
}
ALWAYS_INLINE u8 dev2portNum(const u8 devNum)
{
return (devNum == SDMMC_DEV_eMMC ? TMIO_eMMC_PORT : TMIO_CARD_PORT);
}
u32 SDMMC_init(const u8 devNum)
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
SdmmcDev *const dev = &g_devs[devNum];
if(dev->type != DEV_TYPE_NONE) return SDMMC_ERR_INITIALIZED;
// Check SD card write protection slider.
if(devNum == SDMMC_DEV_CARD)
dev->prot = !TMIO_cardWritable();
// Init port, enable clock output and wait 74 clocks.
TmioPort *const port = &dev->port;
TMIO_initPort(port, dev2portNum(devNum));
TMIO_powerupSequence(port); // Setup continuous clock and wait 74 clocks.
u32 res = goIdleState(port);
if(res != SDMMC_ERR_NONE) return res;
// (e)MMC/SD now in idle state (idle).
u8 devType;
res = initIdleState(port, &devType);
if(res != SDMMC_ERR_NONE) return res;
// Stop clock at idle, init clock.
TMIO_setClock(port, INIT_CLOCK);
// (e)MMC/SD now in ready state (ready).
res = initReadyState(dev);
if(res != SDMMC_ERR_NONE) return res;
// (e)MMC/SD now in identification state (ident).
u32 rca;
res = initIdentState(dev, devType, &rca);
if(res != SDMMC_ERR_NONE) return res;
// (e)MMC/SD now in stand-by state (stby).
// Maximum at this point would be 20 MHz for (e)MMC and 25 for SD.
// SD: We can increase the clock after end of identification state.
// TODO: eMMC spec section 7.6
// "Until the contents of the CSD register is known by the host,
// the fPP clock rate must remain at fOD. (See Section 12.7 on page 176.)"
// Since the absolute minimum clock rate is 20 MHz and we are in push-pull
// mode already can we cheat and switch to <=20 MHz before getting the CSD?
// Note: This seems to be working just fine in all tests.
TMIO_setClock(port, DEFAULT_CLOCK);
u8 spec_vers;
res = initStandbyState(dev, devType, rca, &spec_vers);
if(res != SDMMC_ERR_NONE) return res;
// (e)MMC/SD now in transfer state (tran).
res = initTranState(dev, devType, rca, spec_vers);
if(res != SDMMC_ERR_NONE) return res;
// Only set dev type on successful init.
dev->type = devType;
return SDMMC_ERR_NONE;
}
u32 SDMMC_setSleepMode(const u8 devNum, const bool enabled)
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
SdmmcDev *const dev = &g_devs[devNum];
TmioPort *const port = &dev->port;
const u32 rca = (u32)dev->rca<<16;
const u8 devType = dev->type;
if(enabled)
{
// Deselect card to go back to stand-by state.
// CMD is the same for (e)MMC/SD.
u32 res = TMIO_sendCommand(port, MMC_DESELECT_CARD, 0);
if(res != 0) return SDMMC_ERR_SELECT_CARD;
// Only (e)MMC can go into true sleep mode.
if(IS_DEV_MMC(devType))
{
// Switch (e)MMC into sleep mode.
res = TMIO_sendCommand(port, MMC_SLEEP_AWAKE, rca | BIT(15));
if(res != 0) return SDMMC_ERR_SLEEP_AWAKE;
// TODO: Power down eMMC. This is confirmed working on 3DS.
}
}
else
{
if(IS_DEV_MMC(devType))
{
// TODO: Power up eMMC. This is confirmed working on 3DS.
// Wake (e)MMC up from sleep mode.
u32 res = TMIO_sendCommand(port, MMC_SLEEP_AWAKE, rca);
if(res != 0) return SDMMC_ERR_SLEEP_AWAKE;
}
// Select card to go back to transfer state.
// CMD is the same for (e)MMC/SD.
u32 res = TMIO_sendCommand(port, MMC_SELECT_CARD, rca);
if(res != 0) return SDMMC_ERR_SELECT_CARD;
}
return SDMMC_ERR_NONE;
}
// TODO: Is there any "best practice" way of deinitializing cards?
// Kick the card back into idle state maybe?
// Linux seems to deselect cards on "suspend".
u32 SDMMC_deinit(const u8 devNum)
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
memset(&g_devs[devNum], 0, sizeof(SdmmcDev));
return SDMMC_ERR_NONE;
}
u32 SDMMC_lockUnlock(const u8 devNum, const u8 mode, const u8 *const pwd, const u8 pwdLen)
{
// Password length is maximum 16 bytes except when replacing a password.
if(devNum > SDMMC_MAX_DEV_NUM || pwdLen > 32) return SDMMC_ERR_INVAL_PARAM;
// Set block length on (e)MMC/SD side and host.
// Same CMD for (e)MMC/SD.
SdmmcDev *const dev = &g_devs[devNum];
TmioPort *const port = &dev->port;
const u32 blockLen = (mode != SDMMC_LK_ERASE ? 2 + pwdLen : 1);
u32 res = TMIO_sendCommand(port, MMC_SET_BLOCKLEN, blockLen);
if(res != 0) return SDMMC_ERR_SET_BLOCKLEN;
TMIO_setBlockLen(port, blockLen);
do
{
// Prepare lock/unlock data block.
alignas(4) u8 buf[36] = {0}; // Size multiple of 4 (TMIO driver limitation).
buf[0] = mode;
buf[1] = pwdLen;
memcpy(&buf[2], pwd, pwdLen);
// Dirty hack to extend the data timeout to a bit over 4 minutes with TMIO controller.
// We need 3 minutes minimum for erase.
const u16 clk_ctrl_backup = port->sd_clk_ctrl;
TMIO_setClock(port, 130913);
// Note: Command class 7 support is mandatory for (e)MMC. Not for SD cards until 2.00.
// Same CMD for (e)MMC/SD.
TMIO_setBuffer(port, (u32*)buf, 1);
res = TMIO_sendCommand(port, MMC_LOCK_UNLOCK, 0);
port->sd_clk_ctrl = clk_ctrl_backup; // Undo the data timeout hack.
if(res != 0)
{
res = SDMMC_ERR_LOCK_UNLOCK;
break;
}
// Restore default block length and get the R1 status.
// Same CMD for (e)MMC/SD.
res = TMIO_sendCommand(port, MMC_SET_BLOCKLEN, 512);
if(res != 0)
{
res = SDMMC_ERR_SET_BLOCKLEN;
break;
}
TMIO_setBlockLen(port, 512);
// Check if lock/unlock worked.
// Same bit for (e)MMC/SD R1 card status.
const u32 status = port->resp[0];
if(status & MMC_R1_LOCK_UNLOCK_FAILED)
res = SDMMC_ERR_LOCK_UNLOCK_FAIL;
// Update lock status.
const u8 prot = dev->prot & ~BIT(3);
dev->prot = prot | (status>>22 & BIT(3));
} while(0);
return res;
}
// People should not mess with the state which is the reason
// why the struct is not exposed directly.
static_assert(sizeof(SdmmcDev) == 64, "Wrong SDMMC dev export/import size.");
u32 SDMMC_exportDevState(const u8 devNum, u8 devOut[64])
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
// Check if the device is initialized.
const SdmmcDev *const dev = &g_devs[devNum];
if(dev->type == DEV_TYPE_NONE) return SDMMC_ERR_NO_CARD;
memcpy(devOut, dev, 64);
return SDMMC_ERR_NONE;
}
u32 SDMMC_importDevState(const u8 devNum, const u8 devIn[64])
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
// Make sure there is a card inserted.
if(devNum == SDMMC_DEV_CARD && !TMIO_cardDetected()) return SDMMC_ERR_NO_CARD;
// Check if the device is initialized.
SdmmcDev *const dev = &g_devs[devNum];
if(dev->type != DEV_TYPE_NONE) return SDMMC_ERR_INITIALIZED;
memcpy(dev, devIn, 64);
// Update write protection slider state just in case.
dev->prot |= !TMIO_cardWritable();
return SDMMC_ERR_NONE;
}
#ifdef __ARM9__
typedef struct
{
bool initialized;
bool isMmc; // Set when the first OP_COND APP CMD fails and MMC init (CMD1) succeeds.
bool isSd; // General SD card flag (including SDHC/SDXC). Set when OP_COND APP CMDs succeed.
bool isSdhc; // CCS bit from OCR. Set for SDHC and SDXC.
u32 cid[4]; // In TMIO response format.
u32 csd[4]; // In TMIO response format.
u32 ocr;
u64 scr; // In big endian? All 0 for (e)MMC.
u16 rca;
u8 rsvd[2];
u32 result; // Last driver result/error code.
u32 cardStatus; // Last R1 card status.
u16 sd_clk_ctrl;
u16 sd_option;
bool highCapacity; // (SD) Set when CSD v2.0 (NOT v3.0) or (MMC) when the capacity from CSD is higher than 2 GiB.
u8 rsvd2[3];
u32 sectors; // Capacity in sectors.
u32 sdProtSectors; // Capacity in sectors of SD protected area from 512 bit SD status. 0 for (e)MMC.
u32 initFails; // Failed init attempts?
u32 initFailResult; // Init fail result? Same format as result?
u32 rwFails; // Failed read/write attempts?
u32 rwFailResult; // Read/write fail result? Same format as result?
u32 controller; // TMIO controller number (1-based).
u32 portNum; // TMIO port number.
} HosSdmmcPortCtx;
static_assert(offsetof(HosSdmmcPortCtx, portNum) == 0x60, "Member portNum of HosSdmmcPortCtx not at offset 0x60.");
u32 SDMMC_importHosEmmcState(void)
{
// Check if the device is already initialized.
SdmmcDev *const dev = &g_devs[SDMMC_DEV_eMMC];
if(dev->type != DEV_TYPE_NONE) return SDMMC_ERR_INITIALIZED;
// Check if the HOS port ctx is initialized.
const HosSdmmcPortCtx *const ctx = (HosSdmmcPortCtx*)0x01FFCD80;
if(!ctx->initialized) return SDMMC_ERR_NO_CARD;
TmioPort *const port = &dev->port;
port->portNum = dev2portNum(SDMMC_DEV_eMMC);
port->sd_clk_ctrl = ctx->sd_clk_ctrl;
port->sd_blocklen = 512; // Assumption.
port->sd_option = (ctx->sd_option & 0xFF00u) | OPTION_DEFAULT_TIMINGS; // Use our own timings.
// Remaining fields don't matter.
u8 devType;
if(ctx->isMmc && !ctx->isSd)
{
// Because Nintendos driver never sets the sector addressing bit
// in the argument for CMD1, high capacity eMMC will not work.
// We do the check here anyway just in case.
devType = (ctx->highCapacity ? DEV_TYPE_MMCHC : DEV_TYPE_MMC);
}
else
{
// Unfortunately no flags for detecting SDUC.
devType = (ctx->isSdhc ? DEV_TYPE_SDHC : DEV_TYPE_SDSC);
}
dev->type = devType;
// CSD is in TMIO response format.
u32 csd[4];
const u32 *const csdPtr = ctx->csd;
csd[0] = csdPtr[3]<<8 | csdPtr[2]>>24;
csd[1] = csdPtr[2]<<8 | csdPtr[1]>>24;
csd[2] = csdPtr[1]<<8 | csdPtr[0]>>24;
csd[3] = csdPtr[0]<<8;
// Parse write protection and password protection bits.
// Since boot9 doesn't support password protection
// we could omit parsing that bit. We do it anyway.
u8 prot = extractBits(csd, 12, 1)<<1; // [12:12]
prot |= extractBits(csd, 13, 1)<<2; // [13:13]
prot |= (ctx->cardStatus & MMC_R1_CARD_IS_LOCKED)>>22; // Bit 3.
dev->prot = prot;
dev->rca = ctx->rca;
dev->ccc = extractBits(csd, 84, 12); // [95:84]
dev->sectors = ctx->sectors;
// CID is in TMIO response format.
u32 *const dstCid = dev->cid;
const u32 *const srcCid = ctx->cid;
dstCid[0] = srcCid[3]<<8 | srcCid[2]>>24;
dstCid[1] = srcCid[2]<<8 | srcCid[1]>>24;
dstCid[2] = srcCid[1]<<8 | srcCid[0]>>24;
dstCid[3] = srcCid[0]<<8;
return SDMMC_ERR_NONE;
}
#endif // #ifdef __ARM9__
// TODO: Less controller dependent code.
u32 SDMMC_getDevInfo(const u8 devNum, SdmmcInfo *const infoOut)
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
const SdmmcDev *const dev = &g_devs[devNum];
const TmioPort *const port = &dev->port;
infoOut->type = dev->type;
infoOut->prot = dev->prot;
infoOut->rca = dev->rca;
infoOut->sectors = dev->sectors;
const u32 clkSetting = port->sd_clk_ctrl & 0xFFu;
infoOut->clock = TMIO_HCLK / (clkSetting ? clkSetting<<2 : 2);
memcpy(infoOut->cid, dev->cid, 16);
infoOut->ccc = dev->ccc;
infoOut->busWidth = (port->sd_option & OPTION_BUS_WIDTH1 ? 1 : 4);
return SDMMC_ERR_NONE;
}
u32 SDMMC_getCid(const u8 devNum, u32 cidOut[4])
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
if(cidOut != NULL) memcpy(cidOut, g_devs[devNum].cid, 16);
return SDMMC_ERR_NONE;
}
#include "ff.h" // Needed for the "byte" type used in diskio.h.
#include "diskio.h"
u8 SDMMC_getDiskStatus(const u8 devNum)
{
if(devNum > SDMMC_MAX_DEV_NUM) return STA_NODISK | STA_NOINIT;
u8 status = 0;
if(devNum == SDMMC_DEV_CARD)
status = (TMIO_cardDetected() == true ? 0 : STA_NODISK | STA_NOINIT);
const SdmmcDev *const dev = &g_devs[devNum];
status |= (dev->prot != 0 ? STA_PROTECT : 0);
if(dev->type == DEV_TYPE_NONE)
status |= STA_NOINIT;
// "Not valid if STA_NODISK is set."
/*if(status & STA_NODISK)
status &= ~STA_PROTECT;*/
return status;
}
u32 SDMMC_getSectors(const u8 devNum)
{
if(devNum > SDMMC_MAX_DEV_NUM) return 0;
return g_devs[devNum].sectors;
}
static u32 updateStatus(SdmmcDev *const dev, const bool stopTransmission)
{
TmioPort *const port = &dev->port;
// MMC_STOP_TRANSMISSION: Same CMD for (e)MMC/SD. Relies on the driver returning a proper response.
// MMC_SEND_STATUS: Same CMD for (e)MMC/SD but the argument format differs slightly.
u32 res;
if(stopTransmission) res = TMIO_sendCommand(port, MMC_STOP_TRANSMISSION, 0);
else res = TMIO_sendCommand(port, MMC_SEND_STATUS, (u32)dev->rca<<16);
dev->status = (res == 0 ? port->resp[0] : 0); // Don't update the status with stale data.
return res;
}
// Note: On multi-block read from the last 2 sectors there are no errors reported by the controller
// however the R1 card status may report ADDRESS_OUT_OF_RANGE on next(?) status read.
// This error is normal for (e)MMC and can be ignored.
u32 SDMMC_readSectors(const u8 devNum, u32 sect, void *const buf, const u16 count)
{
if(devNum > SDMMC_MAX_DEV_NUM || count == 0) return SDMMC_ERR_INVAL_PARAM;
// Check if the device is initialized.
SdmmcDev *const dev = &g_devs[devNum];
const u8 devType = dev->type;
if(devType == DEV_TYPE_NONE) return SDMMC_ERR_NO_CARD;
// Set destination buffer and sector count.
TmioPort *const port = &dev->port;
TMIO_setBuffer(port, buf, count);
// Read a single 512 bytes block. Same CMD for (e)MMC/SD.
// Read multiple 512 bytes blocks. Same CMD for (e)MMC/SD.
const u16 readCmd = (count == 1 ? MMC_READ_SINGLE_BLOCK : MMC_READ_MULTIPLE_BLOCK);
if(devType == DEV_TYPE_MMC || devType == DEV_TYPE_SDSC) sect *= 512; // Byte addressing.
u32 res = TMIO_sendCommand(port, readCmd, sect);
if(res != 0)
{
// On error in the middle of multi-block reads the card will be stuck
// in data state and we need to send STOP_TRANSMISSION to bring it
// back to tran state.
// Otherwise for single-block reads just update the status.
updateStatus(dev, count > 1);
return SDMMC_ERR_SECT_RW;
}
return SDMMC_ERR_NONE;
}
// Note: On multi-block write to the last 2 sectors there are no errors reported by the controller
// however the R1 card status may report ADDRESS_OUT_OF_RANGE on next(?) status read.
// This error is normal for (e)MMC and can be ignored.
u32 SDMMC_writeSectors(const u8 devNum, u32 sect, const void *const buf, const u16 count)
{
if(devNum > SDMMC_MAX_DEV_NUM || count == 0) return SDMMC_ERR_INVAL_PARAM;
// Check if the device is initialized.
SdmmcDev *const dev = &g_devs[devNum];
const u8 devType = dev->type;
if(devType == DEV_TYPE_NONE) return SDMMC_ERR_NO_CARD;
// Check if the device is write protected.
if(dev->prot != 0) return SDMMC_ERR_WRITE_PROT;
// Set source buffer and sector count.
TmioPort *const port = &dev->port;
TMIO_setBuffer(port, (void*)buf, count);
// Write a single 512 bytes block. Same CMD for (e)MMC/SD.
// Write multiple 512 bytes blocks. Same CMD for (e)MMC/SD.
const u16 writeCmd = (count == 1 ? MMC_WRITE_BLOCK : MMC_WRITE_MULTIPLE_BLOCK);
if(devType == DEV_TYPE_MMC || devType == DEV_TYPE_SDSC) sect *= 512; // Byte addressing.
const u32 res = TMIO_sendCommand(port, writeCmd, sect);
if(res != 0)
{
// On error in the middle of multi-block writes the card will be stuck
// in data state and we need to send STOP_TRANSMISSION to bring it
// back to tran state.
// Otherwise for single-block writes just update the status.
updateStatus(dev, count > 1);
return SDMMC_ERR_SECT_RW;
}
return SDMMC_ERR_NONE;
}
u32 SDMMC_sendCommand(const u8 devNum, MmcCommand *const mmcCmd)
{
if(devNum > SDMMC_MAX_DEV_NUM) return SDMMC_ERR_INVAL_PARAM;
SdmmcDev *const dev = &g_devs[devNum];
TmioPort *const port = &dev->port;
TMIO_setBlockLen(port, mmcCmd->blkLen);
TMIO_setBuffer(port, mmcCmd->buf, mmcCmd->count);
const u32 res = TMIO_sendCommand(port, mmcCmd->cmd, mmcCmd->arg);
TMIO_setBlockLen(port, 512); // Restore default block length.
if(res != 0)
{
updateStatus(dev, false);
return SDMMC_ERR_SEND_CMD;
}
memcpy(mmcCmd->resp, port->resp, 16);
return SDMMC_ERR_NONE;
}
u32 SDMMC_getLastR1error(const u8 devNum)
{
if(devNum > SDMMC_MAX_DEV_NUM) return 0;
SdmmcDev *const dev = &g_devs[devNum];
const u32 status = dev->status;
dev->status = 0;
return status;
}