/* * 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 . */ #include #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.1–4.2–4.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 "fatfs/source/ff.h" // Needed for the "byte" type used in diskio.h. #include "fatfs/source/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; }