diff --git a/psp2ref b/psp2ref index 50a503a..94318a3 160000 --- a/psp2ref +++ b/psp2ref @@ -1 +1 @@ -Subproject commit 50a503abe97cbdbbe40b51a7408a068a3748bb04 +Subproject commit 94318a3bbb3f82729304e0a226b54da0a7306725 diff --git a/source/include/sdif.h b/source/include/sdif.h index b9575ac..58f67c9 100644 --- a/source/include/sdif.h +++ b/source/include/sdif.h @@ -5,41 +5,63 @@ #include "types.h" #include "utils.h" -struct _sdif_arg_s { +#include "hardware/sdif.h" + +struct _sdif_command_s { + /* Size of this structure */ uint32_t this_size; - uint32_t some_arg1; - uint32_t op_id; - uint32_t sector; - uint32_t unk_4; - uint32_t unk_5; - uint32_t unk_6; - uint32_t unk_7; + + /* ? */ + uint32_t cmd_settings; + + /* Command Index - as defined in the SD Specification */ + uint32_t cmd_index; + + /* Command Argument1 - as defined in the SD Specification */ + uint32_t argument1; + + /* Response buffer - as defined in the SD Specification */ + uint32_t response[4]; + + /* Destination address for writes (source for reads?) */ uint32_t dst_addr; - uint32_t sector_size; - uint32_t sector_count; - uint32_t unk_11; + + /* Block size for operation */ + uint32_t block_size; + + /* Number of blocks for operation */ + uint32_t block_count; + + /* Command status / result code (SCE format) */ + int status; }; -typedef struct _sdif_arg_s sdif_arg_s; +typedef struct _sdif_command_s sdif_command_s; struct _unk_sdif_ctx_init { uint32_t unk_0; - uint32_t unk_clk1; - uint32_t unk_clk2; + uint32_t base_clock; + uint32_t max_clock; uint16_t unk_half_id; uint16_t dev_id; - sdif_arg_s* sdif_arg; - sdif_arg_s* sdif_arg2; - volatile uint16_t* sdif_regs_addr; + sdif_command_s* sdif_arg; + sdif_command_s* sdif_arg2; + SceSdifReg* sdif_regs_addr; }; typedef struct _unk_sdif_ctx_init unk_sdif_ctx_init; struct _unk2_sdif_gigactx { // shrunk version of the original gigactx unk_sdif_ctx_init* sctx; uint32_t quirks; // bit 0: use sector offset instead of byte offset - uint8_t op9_argx33[0x10]; - uint32_t op9_lutd; // lut0[op9_4b99] * lut1[op9_3bx60] + uint8_t cardSpecificData[0x10]; + uint32_t maxTransferSpeed; /* Maximum data transfer rate per one data line, in bits per second */ union { - uint32_t op9_switchd; // (op9_22bx30 + 1) * 0x400 or (op9_12bx3e + 1) << ((op9_3bx2f + 2) & 0x1f) + /** + * For GC-SD only: card size, in number of blocks + * + SD standard capacity: block size is fixed in READ_BL_LEN field of CSD + * + SDHC / SDXC: block size is fixed at 512 bytes + */ + uint32_t gcsdCardSizeInBlocks; + /* For eMMC only: clock speed? */ uint32_t op8_switchd; }; }; diff --git a/source/sdif.c b/source/sdif.c index 6c1c49d..f993644 100644 --- a/source/sdif.c +++ b/source/sdif.c @@ -13,78 +13,118 @@ #define CONCAT12(high, low) ((high << 16) | low) #define CONCAT13(high, low) ((high << 24) | low) -static void sdif_cfgwait_regs16_x19nx1b(unk_sdif_ctx_init *param_1, uint32_t param_2) { - volatile uint16_t *puVar1; - uint16_t uVar2; +#define SECTOR_SIZE (512) + +/* SD Card-Specific Data structure layout */ +#define CSD_STRUCTURE_OFFSET 126 +#define CSD_STRUCTURE_SIZE 2 + +#define CSD_TAAC_VALUE_OFFSET 115 +#define CSD_TAAC_VALUE_SIZE 4 +#define CSD_TAAC_UNIT_OFFSET 112 +#define CSD_TAAC_UNIT_SIZE 3 + +#define CSD_TRAN_SPEED_VALUE_OFFSET 99 +#define CSD_TRAN_SPEED_VALUE_SIZE 4 +#define CSD_TRAN_SPEED_UNIT_OFFSET 96 +#define CSD_TRAN_SPEED_UNIT_SIZE 3 - puVar1 = param_1->sdif_regs_addr; +/* CSD Version 2.0-only definitions */ +#define CSD_20_C_SIZE_OFFSET 48 +#define CSD_20_C_SIZE_SIZE 22 + +/* CSD Version 1.0-only definitions */ +#define CSD_10_C_SIZE_OFFSET 62 +#define CSD_10_C_SIZE_SIZE 12 +#define CSD_10_C_SIZE_MULT_OFFSET 47 +#define CSD_10_C_SIZE_MULT_SIZE 3 + +static void sdif_cfgwait_regs16_x19nx1b(unk_sdif_ctx_init *param_1, uint32_t param_2) { if (param_2 != 0) { - uVar2 = puVar1[0x1b]; - puVar1[0x1b] = 0; - do { - } while (puVar1[0x1b] != 0); + SceSdifReg *sdif = param_1->sdif_regs_addr; + + /* Suspend error interrupts */ + uint16_t prevEIS = sdif->ErrorInterruptStatusEnable; + sdif->ErrorInterruptStatusEnable = 0; + + while (sdif->ErrorInterruptStatusEnable != 0) + ; + if ((param_2 & 0xf) != 0) { - v8p((int)puVar1 + 0x2f) = 2; - do { - } while ((v8p((int)puVar1 + 0x2f) & 2) != 0); + /* Reset command line logic */ + sdif->SoftwareReset = SDHC_SOFTWARE_RESET_CMD_LINE; + while (sdif->SoftwareReset & SDHC_SOFTWARE_RESET_CMD_LINE) + ; } + if ((param_2 & 0x70) != 0) { - v8p((int)puVar1 + 0x2f) = 4; - do { - } while ((v8p((int)puVar1 + 0x2f) & 4) != 0); + /* Reset data line logic */ + sdif->SoftwareReset = SDHC_SOFTWARE_RESET_DAT_LINE; + while (sdif->SoftwareReset & SDHC_SOFTWARE_RESET_DAT_LINE) + ; } - puVar1[0x19] = puVar1[0x19]; - do { - } while (puVar1[0x19] != 0); - puVar1[0x1b] = uVar2; - do { - } while (puVar1[0x1b] != uVar2); + + /* Clear error interrupt flags */ + sdif->ErrorInterruptStatus = sdif->ErrorInterruptStatus; + while (sdif->ErrorInterruptStatus != 0) + ; + + /* Restore error interrupts that we suspended earlier */ + sdif->ErrorInterruptStatusEnable = prevEIS; + while (sdif->ErrorInterruptStatusEnable != prevEIS) + ; } return; } static void sdif_rx_maybe(unk_sdif_ctx_init *ctx, uint32_t param_2, uint32_t param_3) { - sdif_arg_s *psVar1; + SceSdifReg *sdif = ctx->sdif_regs_addr; + sdif_command_s *psVar1; uint32_t uVar2; - volatile uint16_t *puVar3; uint16_t uVar4; uint32_t uVar5; int iVar6; - sdif_arg_s *psVar7; + sdif_command_s *psVar7; int iVar8; uint8_t *puVar9; uint32_t *puVar10; psVar1 = ctx->sdif_arg; - if (psVar1 != (sdif_arg_s *)0x0) { - if (ctx->sdif_arg2 == (sdif_arg_s *)0x0) { - if (((param_2 & 2) != 0) && ((psVar1->some_arg1 & 8) != 0)) { - psVar1->some_arg1 = psVar1->some_arg1 | 0x80000000; + if (psVar1 != NULL) { + if (ctx->sdif_arg2 == NULL) { + if (((param_2 & 2) != 0) && ((psVar1->cmd_settings & 8) != 0)) { + psVar1->cmd_settings = psVar1->cmd_settings | 0x80000000; } } else if (param_3 == 0) { - if ((((param_2 & 0x20) != 0) && ((psVar1->some_arg1 & 0x700) == 0x100)) && (0 < (int)psVar1->sector_count)) { + if ((((param_2 & 0x20) != 0) && ((psVar1->cmd_settings & 0x700) == 0x100)) && (0 < (int)psVar1->block_count)) { uVar2 = psVar1->dst_addr; - puVar3 = ctx->sdif_regs_addr; - psVar1->sector_count = psVar1->sector_count - 1; - do { - } while ((v32p(puVar3 + 0x12) & 0x800) == 0); + +// puVar3 = ctx->sdif_regs_addr; + + psVar1->block_count = psVar1->block_count - 1; + + /* Wait for readable data in controller buffer */ + while (!(sdif->PresentState & SDHC_PRESENT_STATE_BUFFER_READ_ENABLED)) + ; + iVar6 = 0; - if (0 < (int)psVar1->sector_size) { + if (0 < (int)psVar1->block_size) { do { - iVar8 = psVar1->sector_size - iVar6; + iVar8 = psVar1->block_size - iVar6; if (iVar8 == 1) { puVar9 = (uint8_t *)(iVar6 + uVar2); iVar6 = iVar6 + 1; - *puVar9 = v8p(puVar3 + 0x10); + + *puVar9 = v8p(&sdif->BufferDataPort); } else { puVar10 = (uint32_t *)(uVar2 + iVar6); if (iVar8 < 4) { - uVar4 = puVar3[0x10]; + uVar4 = v16p(&sdif->BufferDataPort); iVar6 = iVar6 + 2; v8p puVar10 = (uint8_t)uVar4; v8p((int)puVar10 + 1) = (uint8_t)(uVar4 >> 8); } else { - uVar5 = v32p(puVar3 + 0x10); + uVar5 = sdif->BufferDataPort; if ((uVar2 & 3) == 0) { *puVar10 = uVar5; } else { @@ -96,29 +136,33 @@ static void sdif_rx_maybe(unk_sdif_ctx_init *ctx, uint32_t param_2, uint32_t par iVar6 = iVar6 + 4; } } - } while (iVar6 < (int)psVar1->sector_size); + } while (iVar6 < (int)psVar1->block_size); } - psVar1->dst_addr = psVar1->dst_addr + psVar1->sector_size; + psVar1->dst_addr = psVar1->dst_addr + psVar1->block_size; } - if ((((param_2 & 0x10) != 0) && ((psVar1->some_arg1 & 0x700) == 0x200)) && (0 < (int)psVar1->sector_count)) { + if ((((param_2 & 0x10) != 0) && ((psVar1->cmd_settings & 0x700) == 0x200)) && (0 < (int)psVar1->block_count)) { uVar2 = psVar1->dst_addr; - puVar3 = ctx->sdif_regs_addr; - psVar1->sector_count = psVar1->sector_count - 1; - do { - } while ((v32p(puVar3 + 0x12) & 0x400) == 0); +// puVar3 = ctx->sdif_regs_addr; + psVar1->block_count = psVar1->block_count - 1; + + /* Wait for free space in controller write buffer */ + while (!(sdif->PresentState & SDHC_PRESENT_STATE_BUFFER_WRITE_ENABLED)) + ; + iVar6 = 0; - if (0 < (int)psVar1->sector_size) { + if (0 < (int)psVar1->block_size) { do { - iVar8 = psVar1->sector_size - iVar6; + iVar8 = psVar1->block_size - iVar6; if (iVar8 == 1) { puVar9 = (uint8_t *)(iVar6 + uVar2); iVar6 = iVar6 + 1; - v8p(puVar3 + 0x10) = *puVar9; + + v8p(&sdif->BufferDataPort) = *puVar9; } else { puVar10 = (uint32_t *)(iVar6 + uVar2); if (iVar8 < 4) { iVar6 = iVar6 + 2; - puVar3[0x10] = CONCAT11(v8p((int)puVar10 + 1), v8p puVar10); + v16p(&sdif->BufferDataPort) = CONCAT11(v8p((int)puVar10 + 1), v8p puVar10); } else { if ((uVar2 & 3) == 0) { uVar5 = *puVar10; @@ -126,79 +170,82 @@ static void sdif_rx_maybe(unk_sdif_ctx_init *ctx, uint32_t param_2, uint32_t par uVar5 = CONCAT13(v8p((int)puVar10 + 3), CONCAT12(v8p((int)puVar10 + 2), CONCAT11(v8p((int)puVar10 + 1), v8p puVar10))); } iVar6 = iVar6 + 4; - v32p(puVar3 + 0x10) = uVar5; + sdif->BufferDataPort = uVar5; } } - } while (iVar6 < (int)psVar1->sector_size); + } while (iVar6 < (int)psVar1->block_size); } - psVar1->dst_addr = psVar1->dst_addr + psVar1->sector_size; + psVar1->dst_addr = psVar1->dst_addr + psVar1->block_size; } if ((param_2 & 2) != 0) { - psVar7 = (sdif_arg_s *)(int)v8p((int)&ctx->dev_id + 1); - if (psVar7 != (sdif_arg_s *)0x0) { - psVar7 = (sdif_arg_s *)0x0; - psVar1->some_arg1 = psVar1->some_arg1 | 0x80000000; + psVar7 = NULL; + if ((int)v8p((int)&ctx->dev_id + 1) != 0x0) { + + psVar1->cmd_settings = psVar1->cmd_settings | 0x80000000; } ctx->sdif_arg2 = psVar7; } } else { - ctx->sdif_arg2 = (sdif_arg_s *)0x0; - psVar1->unk_11 = ((param_3 & 0x10) == 0) + 0x80320002; - psVar1->some_arg1 = psVar1->some_arg1 | 0x40000000; + ctx->sdif_arg2 = NULL; + psVar1->status = ((param_3 & 0x10) == 0) + 0x80320002; + psVar1->cmd_settings = psVar1->cmd_settings | 0x40000000; sdif_cfgwait_regs16_x19nx1b(ctx, param_3); } } return; } -static void sdif_prep_txarg(unk_sdif_ctx_init *param_1, sdif_arg_s *param_2) { +static void sdif_prep_txarg(unk_sdif_ctx_init *param_1, sdif_command_s *param_2) { + SceSdifReg *sdif = param_1->sdif_regs_addr; uint32_t uVar1; uint32_t uVar2; int iVar3; uint32_t uVar4; - volatile uint16_t *regs; - regs = param_1->sdif_regs_addr; - param_2->unk_11 = 0; - uVar4 = param_2->some_arg1 & 0xf8; + param_2->status = 0; + uVar4 = param_2->cmd_settings & 0xf8; if (((((uVar4 == 0x90) || (uVar4 == 0x80)) || (uVar4 == 0x78)) || ((uVar4 == 0x60 || (uVar4 == 0x50)))) || (uVar4 == 0x40)) { - param_2->unk_4 = v32p(regs + 8); + param_2->Response[0] = sdif->Response[0]; } else if (uVar4 == 0x30) { - uVar4 = v32p(regs + 8); - uVar1 = v32p(regs + 10); - uVar2 = v32p(regs + 0xc); - iVar3 = *(volatile int *)(regs + 0xe); - param_2->unk_4 = uVar4 << 8; - param_2->unk_5 = uVar1 << 8 | uVar4 >> 0x18; - param_2->unk_6 = uVar2 << 8 | uVar1 >> 0x18; - param_2->unk_7 = iVar3 << 8 | uVar2 >> 0x18; - } else if (((uVar4 == 0x28) || (uVar4 == 0x10)) && (param_2->unk_4 = v32p(regs + 8), (param_2->some_arg1 & 0x800) != 0)) { - param_2->unk_7 = v32p(regs + 0xe); + uVar4 = sdif->Response[0]; + uVar1 = sdif->Response[1]; + uVar2 = sdif->Response[2]; + iVar3 = sdif->Response[3]; + param_2->response[0] = uVar4 << 8; + param_2->response[1] = uVar1 << 8 | uVar4 >> 0x18; + param_2->response[2] = uVar2 << 8 | uVar1 >> 0x18; + param_2->response[3] = iVar3 << 8 | uVar2 >> 0x18; + } else if (((uVar4 == 0x28) || (uVar4 == 0x10)) && (param_2->response[0] = sdif->Response[0], (param_2->cmd_settings & 0x800) != 0)) { + param_2->response[3] = sdif->Response[3]; } - if ((param_2->some_arg1 & 0x3000) != 0) { - v8p((int)regs + 0x2f) = 6; - do { - } while ((v8p((int)regs + 0x2f) & 6) != 0); + + if ((param_2->cmd_settings & 0x3000) != 0) { + /* Reset command and data logic (including DMA) */ + sdif->SoftwareReset = (SDHC_SOFTWARE_RESET_DAT_LINE | SDHC_SOFTWARE_RESET_CMD_LINE); + + while (sdif->SoftwareReset & (SDHC_SOFTWARE_RESET_DAT_LINE | SDHC_SOFTWARE_RESET_CMD_LINE)) { + /* Wait until reset is complete */ + } } return; } static void sdif_tx_maybe(unk_sdif_ctx_init *ctx, uint32_t param_2, uint32_t param_3) { - sdif_arg_s *psVar1; + sdif_command_s *psVar1; psVar1 = ctx->sdif_arg; - if (psVar1 != (sdif_arg_s *)0x0) { + if (psVar1 != NULL) { if (param_3 == 0) { if ((param_2 & 1) != 0) { v8p((int)&ctx->dev_id + 1) = 1; sdif_prep_txarg(ctx, psVar1); - if ((ctx->sdif_arg2 == (sdif_arg_s *)0x0) && ((psVar1->some_arg1 & 8) == 0)) { - psVar1->some_arg1 = psVar1->some_arg1 | 0x80000000; + if ((ctx->sdif_arg2 == NULL) && ((psVar1->cmd_settings & 8) == 0)) { + psVar1->cmd_settings = psVar1->cmd_settings | 0x80000000; } } } else { - psVar1->unk_11 = ((param_3 & 1) == 0) + 0x80320002; - psVar1->some_arg1 = psVar1->some_arg1 | 0x40000000; + psVar1->status = ((param_3 & 1) == 0) + 0x80320002; + psVar1->cmd_settings = psVar1->cmd_settings | 0x40000000; sdif_cfgwait_regs16_x19nx1b(ctx, param_3); } } @@ -206,52 +253,72 @@ static void sdif_tx_maybe(unk_sdif_ctx_init *ctx, uint32_t param_2, uint32_t par } static uint32_t sdif_trans_action(uint32_t dev_id, unk_sdif_ctx_init *ctx) { - uint16_t uVar1; - uint16_t uVar2; - volatile uint16_t *sdif; - - sdif = ctx->sdif_regs_addr; - uVar1 = sdif[0x18]; - uVar2 = sdif[0x19]; - if (((uVar1 & 1) != 0) || ((uVar2 & 0xf) != 0)) { - sdif[0x18] = 1; - sdif[0x19] = 0xf; - do { - } while ((sdif[0x18] & 1) != 0); - do { - } while ((sdif[0x19] & 0xf) != 0); - sdif_tx_maybe(ctx, (uint32_t)(uVar1 & 0xfe3f), (uint32_t)uVar2); + SceSdifReg *sdif = ctx->sdif_regs_addr; + uint16_t NIS = sdif->NormalInterruptStatus; + uint16_t EIS = sdif->ErrorInterruptStatus; + + /* Check for command phase completion or errors */ + if ((NIS & SDHC_NORMAL_IRQ_STATUS_CMD_COMPLETE) || (EIS & SDHC_ERROR_IRQ_STATUS_COMMAND_PHASE_ERRORS)) { + /* Clear related interrupt flags */ + sdif->NormalInterruptStatus = SDHC_NORMAL_IRQ_STATUS_CMD_COMPLETE; + sdif->ErrorInterruptStatus = SDHC_ERROR_IRQ_STATUS_COMMAND_PHASE_ERRORS; + + /* Wait until flags are cleared */ + while (sdif->NormalInterruptStatus & SDHC_NORMAL_IRQ_STATUS_CMD_COMPLETE) + ; + while (sdif->ErrorInterruptStatus & SDHC_ERROR_IRQ_STATUS_COMMAND_PHASE_ERRORS) + ; + + sdif_tx_maybe(ctx, (uint32_t)(NIS & ~SDHC_NORMAL_IRQ_STATUS_CARD_STATUS_FLAGS), (uint32_t)EIS); } - if (((uVar1 & 0x32) != 0) || ((uVar2 & 0x70) != 0)) { - sdif[0x18] = 0x32; - sdif[0x19] = 0x70; - do { - } while ((sdif[0x18] & 0x32) != 0); - do { - } while ((sdif[0x19] & 0x70) != 0); - sdif_rx_maybe(ctx, (uint32_t)(uVar1 & 0xfe3f), (uint32_t)uVar2); + + /* Check for data phase completion or errors */ + const uint32_t DATA_PHASE_STATUS_BITS = SDHC_NORMAL_IRQ_STATUS_TFR_COMPLETE | SDHC_NORMAL_IRQ_STATUS_BUFFER_WRITE_READY | SDHC_NORMAL_IRQ_STATUS_BUFFER_READ_READY; + if ((NIS & DATA_PHASE_STATUS_BITS) || (EIS & SDHC_ERROR_IRQ_STATUS_DATA_PHASE_ERRORS)) { + /* Clear related interrupt flags */ + sdif->NormalInterruptStatus = DATA_PHASE_STATUS_BITS; + sdif->ErrorInterruptStatus = SDHC_ERROR_IRQ_STATUS_DATA_PHASE_ERRORS; + + /* Wait until flags are cleared */ + while (sdif->NormalInterruptStatus & DATA_PHASE_STATUS_BITS) + ; + while (sdif->ErrorInterruptStatus & SDHC_ERROR_IRQ_STATUS_DATA_PHASE_ERRORS) + ; + + sdif_rx_maybe(ctx, (uint32_t)(NIS & ~SDHC_NORMAL_IRQ_STATUS_CARD_STATUS_FLAGS), (uint32_t)EIS); } + return 0; } -static uint32_t write_args(unk_sdif_ctx_init *ctx, sdif_arg_s *op) { - uint16_t uVar1; - sdif_arg_s *psVar2; +static uint32_t write_args(unk_sdif_ctx_init *ctx, sdif_command_s *op) { + SceSdifReg *sdif = ctx->sdif_regs_addr; + uint16_t transferMode; + sdif_command_s *psVar2; uint16_t uVar3; uint32_t uVar4; - volatile uint16_t *sdif_regs; - op->unk_11 = 0; - op->some_arg1 = op->some_arg1 & 0x3fffffff; + op->status = 0; + op->cmd_settings = op->cmd_settings & 0x3fffffff; v8p((int)&ctx->dev_id + 1) = 0; - ctx->sdif_arg2 = (sdif_arg_s *)0x0; - sdif_regs = ctx->sdif_regs_addr; + ctx->sdif_arg2 = NULL; ctx->sdif_arg = op; do { - do { - } while ((v32p(sdif_regs + 0x12) & 1) != 0); - } while ((op->op_id != 0xc) && ((((op->some_arg1 & 7) == 4 || ((op->some_arg1 & 0xf8) == 0x28)) && ((v32p(sdif_regs + 0x12) & 2) != 0)))); - uVar4 = op->some_arg1 & 0xf8; + while (sdif->PresentState & SDHC_PRESENT_STATE_CMD_INHIBITED) { + /* Wait until CMD line is not in use */ + } + } while ( + /* Check that command doesn't need DAT lines, or wait until they are free */ + (op->cmd_index != 12) && + ( + ( + (op->cmd_settings & 7) == 4 || + ((op->cmd_settings & 0xf8) == 0x28) + ) && (sdif->PresentState & SDHC_PRESENT_STATE_DAT_INHIBITED) + ) + ); + + uVar4 = op->cmd_settings & 0xf8; if (uVar4 == 0x30) { uVar3 = 9; } else if ((uVar4 == 0x78) || (uVar4 == 0x28)) { @@ -263,52 +330,63 @@ static uint32_t write_args(unk_sdif_ctx_init *ctx, sdif_arg_s *op) { } else { uVar3 = 0; } - uVar4 = op->some_arg1 & 7; + uVar4 = op->cmd_settings & 7; if (uVar4 == 4) { ctx->sdif_arg2 = op; - v8p(sdif_regs + 0x17) = 0xe; - v8p(sdif_regs + 0x14) = v8p(sdif_regs + 0x14) & 0xe7; - sdif_regs[2] = (uint16_t)op->sector_size | 0x7000; - sdif_regs[3] = (uint16_t)op->sector_count; - uVar1 = 0; - if ((op->some_arg1 & 0x100) != 0) { - uVar1 = 0x10; + + sdif->TimeoutControl = SDHC_TIMEOUT_CONTROL_DATA_TIMEOUT_2_27; + sdif->HostControl1 = (sdif->HostControl1 & ~SDHC_HOST_CONTROL1_DMA_SELECT_Msk) | SDHC_HOST_CONTROL1_DMA_SELECT_SDMA; + + sdif->BlockSize = SDHC_BLOCK_SIZE_HOST_SDMA_BOUNDARY_512K | (uint16_t)op->block_size; + sdif->BlockCount = (uint16_t)op->block_count; + + if (op->cmd_settings & 0x100) { + transferMode = SDHC_TRANSFER_MODE_DATA_DIRECTION_WRITE; + } else { + transferMode = SDHC_TRANSFER_MODE_DATA_DIRECTION_READ; } - if ((op->some_arg1 & 0x800) != 0) { - uVar1 = uVar1 | 4; + + if ((op->cmd_settings & 0x800) != 0) { + transferMode |= SDHC_TRANSFER_MODE_AUTO_CMD12_ENABLE; } - if (op->sector_count == 0) { - op->sector_count = 1; - } else if (op->sector_count == 1) { - uVar1 = uVar1 | 2; - } else if (1 < (int)op->sector_count) { - uVar1 = uVar1 | 0x22; + + if (op->block_count == 0) { + op->block_count = 1; + } else if (op->block_count == 1) { + transferMode |= (SDHC_TRANSFER_MODE_BLOCK_COUNT_ENABLE | SDHC_TRANSFER_MODE_SINGLE_BLOCK); + } else if (1 < (int)op->block_count) { + transferMode = (SDHC_TRANSFER_MODE_BLOCK_COUNT_ENABLE | SDHC_TRANSFER_MODE_MULTI_BLOCK); } - v32p(sdif_regs + 4) = op->sector; - sdif_regs[6] = uVar1; - sdif_regs[7] = (uint16_t)(op->op_id << 8) | 0x20 | uVar3; + + sdif->Argument1 = op->argument1; + sdif->TransferMode = transferMode; + + /* Kickstart SDIF command */ + sdif->Command = (uint16_t)(op->cmd_index << SDHC_COMMAND_COMMAND_INDEX_Pos) | SDHC_COMMAND_DATA_PRESENT_YES | uVar3; } else if (((uVar4 == 3) || (uVar4 == 2)) || (uVar4 == 1)) { - v32p(sdif_regs + 4) = op->sector; - sdif_regs[6] = 0; - sdif_regs[7] = (uint16_t)(op->op_id << 8) | uVar3; + sdif->Argument1 = op->argument1; + + sdif->TransferMode = SDHC_TRANSFER_MODE_DATA_DIRECTION_READ; + sdif->Command = (uint16_t)(op->cmd_index << SDHC_COMMAND_COMMAND_INDEX_Pos) | uVar3; } - while ((op->some_arg1 & 0xc0000000) == 0) { - if ((sdif_regs[0x18] != 0) || (sdif_regs[0x19] != 0)) { + + while ((op->cmd_settings & 0xc0000000) == 0) { + if (sdif->NormalInterruptStatus || sdif->ErrorInterruptStatus) { sdif_trans_action((uint32_t) * (volatile uint8_t *)&ctx->dev_id, ctx); } delay(1000); } + uVar4 = 0; - psVar2 = (sdif_arg_s *)(op->some_arg1 & 0x40000000); - if (psVar2 != (sdif_arg_s *)0x0) { - psVar2 = (sdif_arg_s *)0x0; - uVar4 = op->unk_11; + psVar2 = NULL; + if (op->cmd_settings & 0x40000000) { + uVar4 = op->status; } ctx->sdif_arg = psVar2; return uVar4; } -static int write_args_retry(unk_sdif_ctx_init *ctx, sdif_arg_s *op, int retry_n) { +static int write_args_retry(unk_sdif_ctx_init *ctx, sdif_command_s *op, int retry_n) { int iret; do { @@ -321,17 +399,17 @@ static int write_args_retry(unk_sdif_ctx_init *ctx, sdif_arg_s *op, int retry_n) return iret; } -static int sdif_do_op_0xc(unk_sdif_ctx_init *ctx, int unk_arg1_0x302b) { +static int sdif_cmd12_stop_transmission(unk_sdif_ctx_init *ctx, int unk_arg1_0x302b) { int iVar1; - sdif_arg_s op; + sdif_command_s op; op.this_size = 0x30; - op.some_arg1 = 0x3013; + op.cmd_settings = 0x3013; if (unk_arg1_0x302b != 0) { - op.some_arg1 = 0x302b; + op.cmd_settings = 0x302b; } - op.op_id = 0xc; - op.sector = 0; + op.cmd_index = 12; + op.argument1 = 0; iVar1 = write_args_retry(ctx, &op, 3); if (-1 < iVar1) { iVar1 = 0; @@ -339,52 +417,79 @@ static int sdif_do_op_0xc(unk_sdif_ctx_init *ctx, int unk_arg1_0x302b) { return iVar1; } -static int parse_op_unk_4(uint32_t param_1) { - uint32_t uVar1; - - if ((param_1 & 0xfdffe008) == 0) { +static int R1_card_status_to_errcode(uint32_t card_status) { + const uint32_t AKE_SEQ_ERROR = (1U << 3); + const uint32_t ERASE_RESET = (1U << 13); + const uint32_t CARD_ECC_DISABLED = (1U << 14); + const uint32_t WP_ERASE_SKIP = (1U << 15); + const uint32_t CSD_OVERWRITE = (1U << 16); + const uint32_t rsvd_DEFERRED_RESPONSE = (1U << 17); /* Reserved for eSD */ + const uint32_t rsvd_18 = (1U << 18); /* Reserved! */ + const uint32_t ERROR = (1U << 19); + const uint32_t CC_ERROR = (1U << 20); + const uint32_t CARD_ECC_FAILED = (1U << 21); + const uint32_t ILLEGAL_COMMAND = (1U << 22); + const uint32_t COM_CRC_ERROR = (1U << 23); + const uint32_t LOCK_UNLOCK_FAILED = (1U << 24); + const uint32_t WP_VIOLATION = (1U << 26); + const uint32_t ERASE_PARAM = (1U << 27); + const uint32_t ERASE_SEQ_ERROR = (1U << 28); + const uint32_t BLOCK_LEN_ERROR = (1U << 29); + const uint32_t ADDRESS_ERROR = (1U << 30); + const uint32_t OUT_OF_RANGE = (1U << 31); + + const uint32_t ERRORS_MASK = (OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR + | ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION | LOCK_UNLOCK_FAILED | COM_CRC_ERROR + | ILLEGAL_COMMAND | CARD_ECC_FAILED | CC_ERROR | ERROR | rsvd_18 | rsvd_DEFERRED_RESPONSE + | CSD_OVERWRITE | WP_ERASE_SKIP | CARD_ECC_DISABLED | ERASE_RESET | AKE_SEQ_ERROR); + + if ((card_status & ERRORS_MASK) == 0) { return 0; } - uVar1 = 0; - do { - if ((1 << (uVar1 & 0x1f) & param_1 & 0xfdffe008) != 0) + + int i = 0; + while (i < 32) { + if ((card_status & ERRORS_MASK) & (1 << i)) { break; - uVar1 = uVar1 + 1; - } while ((int)uVar1 < 0x20); - return uVar1 + 0x80320100; + } + i++; + } + + /* 0x80320100 + i */ + return i - 2144206592; } -static int do_op_0x17(unk_sdif_ctx_init *ctx, uint32_t unk_sector_arg) { +static int sdif_cmd23_set_block_count(unk_sdif_ctx_init *ctx, uint32_t block_count) { int iVar1; - sdif_arg_s local_34; + sdif_command_s local_34; local_34.dst_addr = 0; - local_34.op_id = 0x17; - local_34.some_arg1 = 0x13; + local_34.cmd_index = 23; + local_34.cmd_settings = 0x13; local_34.this_size = 0x30; - local_34.sector = unk_sector_arg; + local_34.argument1 = block_count; iVar1 = write_args_retry(ctx, &local_34, 3); - if ((-1 < iVar1) && (iVar1 = parse_op_unk_4(local_34.unk_4), -1 < iVar1)) { + if ((-1 < iVar1) && (iVar1 = R1_card_status_to_errcode(local_34.response[0]), -1 < iVar1)) { iVar1 = 0; } return iVar1; } -static int sdif_do_op_0xd(unk_sdif_ctx_init *ctx, uint32_t *unk_4_ret) { +static int sdif_cmd13_send_status(unk_sdif_ctx_init *ctx, uint32_t *p_card_status) { int iret; - sdif_arg_s op; + sdif_command_s op; - op.some_arg1 = 0x13; - op.op_id = 0xd; + op.cmd_settings = 0x13; + op.cmd_index = 13; op.this_size = 0x30; op.dst_addr = 0; - op.sector = (uint32_t)ctx->unk_half_id << 0x10; + op.argument1 = (uint32_t)ctx->unk_half_id << 0x10; iret = write_args_retry(ctx, &op, 3); if (-1 < iret) { - if (unk_4_ret != (uint32_t *)0x0) { - *unk_4_ret = op.unk_4; + if (p_card_status != NULL) { + *p_card_status = op.reponse[0]; } - iret = parse_op_unk_4(op.unk_4); + iret = R1_card_status_to_errcode(op.response[0]); if (-1 < iret) { iret = 0; } @@ -394,29 +499,29 @@ static int sdif_do_op_0xd(unk_sdif_ctx_init *ctx, uint32_t *unk_4_ret) { int sdif_read_sector_sd(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, uint32_t nsectors) { int iret; - sdif_arg_s op; + sdif_command_s op; op.this_size = 0x30; if (nsectors == 1) { - op.op_id = 0x11; - op.some_arg1 = 0x114; + op.cmd_index = 17; + op.cmd_settings = 0x114; } else { - op.some_arg1 = 0x914; - op.op_id = 0x12; + op.cmd_settings = 0x914; + op.cmd_index = 18; } - op.sector = sector; + op.argument1 = sector; if (!(gctx->quirks & 1)) - op.sector = sector << 9; - op.sector_size = 0x200; + op.argument1 = sector * SECTOR_SIZE; + op.block_size = 0x200; op.dst_addr = dst; - op.sector_count = nsectors; + op.block_count = nsectors; iret = write_args_retry(gctx->sctx, &op, 0); if (iret < 0) { - if (op.op_id == 0x12) { - sdif_do_op_0xc(gctx->sctx, 1); + if (op.cmd_index == 18) { + sdif_cmd12_stop_transmission(gctx->sctx, 1); } } else { - iret = sdif_do_op_0xd(gctx->sctx, 0); + iret = sdif_cmd13_send_status(gctx->sctx, NULL); if (-1 < iret) { iret = 0; } @@ -426,29 +531,29 @@ int sdif_read_sector_sd(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, int sdif_write_sector_sd(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, uint32_t nsectors) { int iret; - sdif_arg_s op; + sdif_command_s op; op.this_size = 0x30; if (nsectors == 1) { - op.op_id = 0x18; - op.some_arg1 = 0x214; + op.cmd_index = 24; + op.cmd_settings = 0x214; } else { - op.some_arg1 = 0xa14; - op.op_id = 0x19; + op.cmd_settings = 0xa14; + op.cmd_index = 25; } - op.sector = sector; + op.argument1 = sector; if (!(gctx->quirks & 1)) - op.sector = sector << 9; - op.sector_size = 0x200; + op.argument1 = sector * SECTOR_SIZE; + op.block_size = 0x200; op.dst_addr = dst; - op.sector_count = nsectors; + op.block_count = nsectors; iret = write_args_retry(gctx->sctx, &op, 0); if (iret < 0) { - if (op.op_id == 0x19) { - sdif_do_op_0xc(gctx->sctx, 1); + if (op.cmd_index == 25) { + sdif_cmd12_stop_transmission(gctx->sctx, 1); } } else { - iret = sdif_do_op_0xd(gctx->sctx, 0); + iret = sdif_cmd13_send_status(gctx->sctx, 0); if (-1 < iret) { iret = 0; } @@ -458,25 +563,25 @@ int sdif_write_sector_sd(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, int sdif_read_sector_mmc(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, uint32_t nsectors) { int iret; - sdif_arg_s op; + sdif_command_s op; - op.some_arg1 = 0x114; + op.cmd_settings = 0x114; op.this_size = 0x30; - op.op_id = (nsectors != 1) + 0x11; - op.sector = sector; + op.cmd_index = (nsectors != 1) ? 18 : 17; + op.argument1 = sector; if (!(gctx->quirks & 1)) - op.sector = sector << 9; - op.sector_size = 0x200; + op.argument1 = sector * SECTOR_SIZE; + op.block_size = 0x200; op.dst_addr = dst; - op.sector_count = nsectors; - if ((op.op_id != 0x12) || (iret = do_op_0x17(gctx->sctx, nsectors), -1 < iret)) { + op.block_count = nsectors; + if ((op.cmd_index != 18) || (iret = sdif_cmd23_set_block_count(gctx->sctx, nsectors), -1 < iret)) { iret = write_args_retry(gctx->sctx, &op, 0); if (iret < 0) { - if ((((op.op_id == 0x12) && (iret != -0x7fcdfee3)) && (iret != -0x7fcdfee2)) && (iret != -0x7fcdfee1)) { - sdif_do_op_0xc(gctx->sctx, 0); + if ((((op.cmd_index == 18) && (iret != -0x7fcdfee3)) && (iret != -0x7fcdfee2)) && (iret != -0x7fcdfee1)) { + sdif_cmd12_stop_transmission(gctx->sctx, 0); } } else { - iret = sdif_do_op_0xd(gctx->sctx, 0); + iret = sdif_cmd13_send_status(gctx->sctx, 0); if (-1 < iret) { iret = 0; } @@ -487,25 +592,26 @@ int sdif_read_sector_mmc(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, int sdif_write_sector_mmc(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst, uint32_t nsectors) { int iret; - sdif_arg_s op; + sdif_command_s op; - op.some_arg1 = 0x214; + op.cmd_settings = 0x214; op.this_size = 0x30; - op.op_id = (nsectors != 1) + 0x18; - op.sector = sector; + op.cmd_index = (nsectors != 1) ? 25 : 24; + op.argument1 = sector; if (!(gctx->quirks & 1)) - op.sector = sector << 9; - op.sector_size = 0x200; + op.argument1 = sector * SECTOR_SIZE; + op.block_size = 0x200; op.dst_addr = dst; - op.sector_count = nsectors; - if ((op.op_id != 0x19) || (iret = do_op_0x17(gctx->sctx, nsectors), -1 < iret)) { + op.block_count = nsectors; + if ((op.cmd_index != 25) || (iret = sdif_cmd23_set_block_count(gctx->sctx, nsectors), -1 < iret)) { iret = write_args_retry(gctx->sctx, &op, 0); if (iret < 0) { - if ((((op.op_id == 0x12) && (iret != -0x7fcdfee3)) && (iret != -0x7fcdfee2)) && (iret != -0x7fcdfee1)) { - sdif_do_op_0xc(gctx->sctx, 0); + //bug? 18 -> 24 + if ((((op.cmd_index == 18) && (iret != -0x7fcdfee3)) && (iret != -0x7fcdfee2)) && (iret != -0x7fcdfee1)) { + sdif_cmd12_stop_transmission(gctx->sctx, 0); } } else { - iret = sdif_do_op_0xd(gctx->sctx, 0); + iret = sdif_cmd13_send_status(gctx->sctx, 0); if (-1 < iret) { iret = 0; } @@ -515,36 +621,54 @@ int sdif_write_sector_mmc(unk2_sdif_gigactx *gctx, uint32_t sector, uint32_t dst } #ifndef SDIF_NOINITS -static uint32_t sdif_pingwaitcfg_regs(unk_sdif_ctx_init *param_1, uint32_t param_2) { - volatile uint16_t *puVar1; +/** reset_mask: bit 0 -> reset controller, bit 1 -> reset IRQ configuration & timeout control */ +static uint32_t sdif_reset_controller_config(unk_sdif_ctx_init *param_1, uint32_t reset_mask) { + SceSdifReg *sdif = param_1->sdif_regs_addr; - puVar1 = param_1->sdif_regs_addr; - if ((param_2 & 1) != 0) { - v8p((int)puVar1 + 0x2f) = 1; - do { - } while ((v8p((int)puVar1 + 0x2f) & 1) != 0); + if ((reset_mask & 1) != 0) { + /* Reset the entire SD host controller */ + sdif->SoftwareReset = SDHC_SOFTWARE_RESET_ALL; + + /* Wait until reset is complete */ + while (sdif->SoftwareReset & SDHC_SOFTWARE_RESET_ALL) + ; } - if ((param_2 & 2) != 0) { - puVar1[0x1a] = 0xf3; - puVar1[0x1b] = 0x17f; - puVar1[0x1c] = 0xf3; - puVar1[0x1d] = 0x17f; - v8p(puVar1 + 0x17) = 0xe; - do { - } while ((v32p(puVar1 + 0x12) & 0x20000) == 0); - puVar1[0x18] = puVar1[0x18]; - puVar1[0x19] = puVar1[0x19]; - do { - } while (puVar1[0x18] != 0); - do { - } while (puVar1[0x19] != 0); + + if ((reset_mask & 2) != 0) { + const uint32_t NIS_ENABLED = + (SDHC_NORMAL_IRQ_STATUS_CARD_REMOVAL | SDHC_NORMAL_IRQ_STATUS_CARD_INSERTION + | SDHC_NORMAL_IRQ_STATUS_BUFFER_READ_READY | SDHC_NORMAL_IRQ_STATUS_BUFFER_WRITE_READY + | SDHC_NORMAL_IRQ_STATUS_TFR_COMPLETE | SDHC_NORMAL_IRQ_STATUS_CMD_COMPLETE); + + const uint32_t EIS_ENABLED = + (SDHC_ERROR_IRQ_STATUS_AUTO_CMD_ERROR | SDHC_ERROR_IRQ_STATUS_DATA_PHASE_ERRORS + | SDHC_ERROR_IRQ_STATUS_COMMAND_PHASE_ERRORS); + + sdif->NormalInterruptStatusEnable = NIS_ENABLED; + sdif->ErrorInterruptStatusEnable = EIS_ENABLED; + sdif->NormalInterruptSignalEnable = NIS_ENABLED; + sdif->ErrorInterruptSignalEnable = EIS_ENABLED; + + sdif->TimeoutControl = SDHC_TIMEOUT_CONTROL_DATA_TIMEOUT_2_27; + + /* Wait until card present state is stable */ + while (!(sdif->PresentState & SDHC_PRESENT_STATE_CARD_STATE_STABLE)) + ; + + /* Clear all interrupt flags */ + sdif->NormalInterruptStatus = sdif->NormalInterruptStatus; + sdif->ErrorInterruptStatus = sdif->ErrorInterruptStatus; + + /* Wait for clear to be completed */ + while (sdif->NormalInterruptStatus != 0) + ; + while (sdif->ErrorInterruptStatus != 0) + ; } return 0; } int sdif_init_ctx(int id, bool alt_clk, unk_sdif_ctx_init *ctx) { - uint8_t *dev_regs; - memset(ctx, 0, sizeof(unk_sdif_ctx_init)); switch (id) { case SDIF_DEV_EMMC: @@ -558,21 +682,25 @@ int sdif_init_ctx(int id, bool alt_clk, unk_sdif_ctx_init *ctx) { ctx->unk_0 = 0; } - ctx->unk_clk1 = 48000000; - ctx->unk_clk2 = alt_clk ? 24000000 : 48000000; + ctx->base_clock = 48000000; + ctx->max_clock = alt_clk ? 24000000 : 48000000; ctx->dev_id = id; - dev_regs = (uint8_t *)0xe0b00000; - if ((id & 0xff) && id != 0x101) - dev_regs = (uint8_t *)(0xe0bf0000 + (id & 0xff) * 0x10000); - ctx->sdif_regs_addr = (volatile uint16_t *)dev_regs; + uint32_t regBase; + if ((id & 0xFF) == 0 || id == 0x101) { + regBase = SDIF0_BASE; + } else { + regBase = (SDIF1_BASE - 0x10000) + (id & 0xFF) * 0x10000; + } + + ctx->sdif_regs_addr = (SceSdifReg *)regBase; - sdif_pingwaitcfg_regs(ctx, 3); + sdif_reset_controller_config(ctx, /* Reset entire controller and IRQ status */ 3); return 0; } -static uint32_t bitfield_extract(int ptr, uint32_t start_bit, uint32_t numbits) { +static uint32_t bitfield_extract(void *ptr, uint32_t start_bit, uint32_t numbits) { uint32_t ui; uint8_t *pos; uint32_t mask1; @@ -602,121 +730,144 @@ static uint32_t bitfield_extract(int ptr, uint32_t start_bit, uint32_t numbits) return accu; } -static uint32_t sdif_wait_reg16x12(unk_sdif_ctx_init *param_1) { - volatile uint16_t *puVar1; - int iVar2; +static int sdif_wait_card_present(unk_sdif_ctx_init *param_1) { + SceSdifReg *sdif = param_1->sdif_regs_addr; + int remainingTries = 1000; - puVar1 = param_1->sdif_regs_addr; - iVar2 = 1000; - while (true) { - if ((v32p(puVar1 + 0x12) & 0x20000) != 0) { - return (uint32_t)((v32p(puVar1 + 0x12) & 0x10000) != 0); + while (remainingTries > 0) { + /* Wait for stabilization of card presence state */ + if (!(sdif->PresentState & SDHC_PRESENT_STATE_CARD_STATE_STABLE)) { + remainingTries--; + delay(1000); } - if (iVar2 == 0) - break; - iVar2 = iVar2 + -1; - delay(1000); + + return (sdif->PresentState & SDHC_PRESENT_STATE_CARD_INSERTED_Msk) >> SDHC_PRESENT_STATE_CARD_INSERTED_Pos; } - return 0x80320002; + + /* 0x80320002 */ + return -2144206846; } -static uint32_t sdif_cfg_reg16x16(unk_sdif_ctx_init *param_1) { - volatile uint16_t *puVar1; +static int sdif_configure_bus(unk_sdif_ctx_init *param_1) { + SceSdifReg *sdif = param_1->sdif_regs_addr; - puVar1 = param_1->sdif_regs_addr; - do { - } while ((v32p(puVar1 + 0x12) & 0x20000) == 0); - if ((v32p(puVar1 + 0x12) & 0x10000) != 0) { - v8p((int)puVar1 + 0x29) = v8p((int)puVar1 + 0x29) | 0xf; - puVar1[0x16] = 0; - puVar1[0x16] = 0x8001; - do { - } while ((puVar1[0x16] & 2) == 0); - puVar1[0x16] = puVar1[0x16] | 4; - v8p(puVar1 + 0x14) = 0; + while (!(sdif->PresentState & SDHC_PRESENT_STATE_CARD_STATE_STABLE)) { + /* Wait for stabilization of card presence state */ + } + + /* If a card is inserted, configure the bus */ + if ((sdif->PresentState & SDHC_PRESENT_STATE_CARD_INSERTED)) { + /* Turn on power on SD Bus @ 1.8V */ + sdif->PowerControl |= (SDHC_POWER_CONTROL_SD_BUS_VOLTAGE_SELECT_1V8 | SDHC_POWER_CONTROL_SD_BUS_POWER_ON); + + /* Disable all clocks */ + sdif->ClockControl = 0; + + /* Enable internal clock and configure SD Clock to lowest speed possible */ + sdif->ClockControl |= (SDHC_CLOCK_CONTROL_SDCLK_FREQ_BASECLK_DIV_256 | SDHC_CLOCK_CONTROL_INTERNAL_CLOCK_ENABLE); + + while (!(sdif->ClockControl & SDHC_CLOCK_CONTROL_INTERNAL_CLOCK_STABLE)) { + /* Wait for internal clock to stabilize */ + } + + /* Enable SD Clock */ + sdif->ClockControl |= SDHC_CLOCK_CONTROL_SD_CLOCK_ENABLE; + + /* Reset HostControl1 */ + sdif->HostControl1 = 0; } + return 0; } -static uint32_t sdif_work_reg16x16(unk_sdif_ctx_init *param_1, uint32_t param_2, int param_3) { - volatile uint16_t *puVar1; - uint8_t bVar2; - int iVar3; +static int sdif_configure_bus_speed(unk_sdif_ctx_init *param_1, uint32_t bus_speed, int enable_high_speed) { + SceSdifReg *sdif = param_1->sdif_regs_addr; uint32_t uVar4; - puVar1 = param_1->sdif_regs_addr; - if (param_1->unk_clk2 < param_2) { - param_2 = param_1->unk_clk2; + if (param_1->max_clock < bus_speed) { + bus_speed = param_1->max_clock; } - uVar4 = 0; - do { - if (param_1->unk_clk1 >> ((uint8_t)uVar4 & 0x1f) <= param_2) - break; - uVar4 = uVar4 + 1; - } while ((int)uVar4 < 8); - iVar3 = 10; - puVar1[0x16] = 0; - puVar1[0x16] = (uint16_t)((0x80 << (uVar4 & 0x1f)) & 0xff00) | puVar1[0x16] | 1; - while (true) { - if ((puVar1[0x16] & 2) != 0) { - puVar1[0x16] = puVar1[0x16] | 4; - if (param_3 == 0) { - bVar2 = v8p(puVar1 + 0x14) & 0xfb; + + /** + * Find the smallest prescaler such that SD clock is less than or equal + * to the bus speed requested by caller. + * N.B. 1: prescalers are powers of two between 0 and 8. + * N.B. 2: (a >> b) is equal to (a / (2^b)) + */ + uint32_t prescaler_log2 = 0; + while ((param_1->base_clock >> prescaler_log2) > bus_speed && prescaler_log2 < 8) { + prescaler_log2++; + } + + /* Reset clock configuration and turn off all clocks */ + sdif->ClockControl = 0; + + /* Enable internal clock and configure SD clock prescaler */ + const uint16_t freq_sel = ((SDHC_CLOCK_CONTROL_SDCLK_FREQ_BASECLK_DIV_2 >> 1) << prescaler_log2) & SDHC_CLOCK_CONTROL_SDCLK_FREQ_SELECT_Msk; + sdif->ClockControl |= (SDHC_CLOCK_CONTROL_INTERNAL_CLOCK_ENABLE | freq_sel); + + int tries = 10; + while (tries != 0) { + if (sdif->ClockControl & SDHC_CLOCK_CONTROL_INTERNAL_CLOCK_STABLE) { + /* Internal clock is stable - enable SD clock */ + sdif->ClockControl |= SDHC_CLOCK_CONTROL_SD_CLOCK_ENABLE; + + /* Configure high speed mode depending on caller's request */ + if (!enable_high_speed) { + sdif->HostControl1 &= ~SDHC_HOST_CONTROL1_HIGH_SPEED_ENABLE; } else { - bVar2 = v8p(puVar1 + 0x14) | 4; + sdif->HostControl1 |= SDHC_HOST_CONTROL1_HIGH_SPEED_ENABLE; } - v8p(puVar1 + 0x14) = bVar2; + return 0; } - if (iVar3 == 0) - break; - iVar3 = iVar3 + -1; + + tries--; delay(1000); } - return 0x80320002; + + /* 0x80320002 */ + return -2144206846; } -static uint32_t sdif_ack_regx14(unk_sdif_ctx_init *param_1, int param_2) { - uint8_t bVar1; +static uint32_t sdif_set_bus_width(unk_sdif_ctx_init *param_1, int bus_width) { + /* This is 1:1 with 2BL implementation but not brom? End results are equivalent */ + uint8_t HC1 = param_1->sdif_regs_addr->HostControl1; - bVar1 = v8p(param_1->sdif_regs_addr + 0x14); - if (param_2 == 8) { - bVar1 = bVar1 | 0x20; + if (bus_width == 8) { + HC1 = (HC1 & ~SDHC_HOST_CONTROL1_DATA_TRANSFER_WIDTH_4BIT) | SDHC_HOST_CONTROL1_EXTENDED_DATA_WIDTH_ON; + } else if (bus_width == 4) { + HC1 = (HC1 & ~SDHC_HOST_CONTROL1_EXTENDED_DATA_WIDTH_ON) | SDHC_HOST_CONTROL1_DATA_TRANSFER_WIDTH_4BIT; } else { - bVar1 = bVar1 & 0xdf; - if (param_2 == 4) { - bVar1 = bVar1 | 2; - goto sdif_ack_regx14_x; - } + HC1 &= ~(SDHC_HOST_CONTROL1_EXTENDED_DATA_WIDTH_ON | SDHC_HOST_CONTROL1_DATA_TRANSFER_WIDTH_4BIT); } - bVar1 = bVar1 & 0xfd; -sdif_ack_regx14_x: - v8p(param_1->sdif_regs_addr + 0x14) = bVar1; + + param_1->sdif_regs_addr->HostControl1 = HC1; return 0; } -static int sdif_op0_arg1(unk_sdif_ctx_init *param_1) { +static int sdif_cmd0_go_idle_state(unk_sdif_ctx_init *param_1) { int iVar1; - sdif_arg_s local_38; + sdif_command_s local_38; - local_38.some_arg1 = 1; + local_38.cmd_settings = 1; local_38.dst_addr = 0; - local_38.sector = 0; - local_38.op_id = 0; + local_38.argument1 = 0; + local_38.cmd_index = 0; local_38.this_size = 0x30; iVar1 = write_args_retry(param_1, &local_38, 0); if (-1 < iVar1) { - sdif_work_reg16x16(param_1, 400000, 0); - sdif_ack_regx14(param_1, 1); + sdif_configure_bus_speed(param_1, 400000, 0); + sdif_set_bus_width(param_1, 1); iVar1 = 0; } return iVar1; } -static int sdif_loop_opx37_argx13_oparg(unk2_sdif_gigactx *gctx, sdif_arg_s *param_2, int param_3) { +static int sdif_loop_opx37_argx13_oparg(unk2_sdif_gigactx *gctx, sdif_command_s *param_2, int param_3) { int iVar1; int unaff_r12; - sdif_arg_s local_44; + sdif_command_s local_44; if (param_3 < 1) { param_3 = 1; @@ -724,14 +875,14 @@ static int sdif_loop_opx37_argx13_oparg(unk2_sdif_gigactx *gctx, sdif_arg_s *par iVar1 = 0; if (0 < param_3) { do { - local_44.op_id = 0x37; - local_44.some_arg1 = 0x13; + local_44.cmd_index = 55; + local_44.cmd_settings = 0x13; local_44.this_size = 0x30; local_44.dst_addr = 0; - local_44.sector = (uint32_t)(gctx->sctx)->unk_half_id << 0x10; + local_44.argument1 = (uint32_t)(gctx->sctx)->unk_half_id << 0x10; unaff_r12 = write_args_retry(gctx->sctx, &local_44, 0); if (-1 < unaff_r12) { - if ((local_44.unk_4 & 0x20) == 0) { + if ((local_44.response[0] & 0x20) == 0) { return -0x7fcdfefb; } unaff_r12 = write_args_retry(gctx->sctx, param_2, 0); @@ -748,20 +899,20 @@ static int sdif_loop_opx37_argx13_oparg(unk2_sdif_gigactx *gctx, sdif_arg_s *par static int sdif_loop_wopx37_opx29_argx42(unk2_sdif_gigactx *gctx, uint32_t param_2, uint32_t *param_3) { int iVar1; int iVar2; - sdif_arg_s local_44; + sdif_command_s local_44; iVar2 = 0; local_44.dst_addr = 0; - local_44.op_id = 0x29; - local_44.some_arg1 = 0x42; + local_44.cmd_index = 41; + local_44.cmd_settings = 0x42; local_44.this_size = 0x30; - local_44.sector = param_2; + local_44.argument1 = param_2; while (true) { iVar1 = sdif_loop_opx37_argx13_oparg(gctx, &local_44, 3); if (iVar1 < 0) { return iVar1; } - if ((param_2 == 0) || ((int)local_44.unk_4 < 0)) + if ((param_2 == 0) || ((int)local_44.response[0] < 0)) break; delay(10000); iVar2 = iVar2 + 1; @@ -770,23 +921,23 @@ static int sdif_loop_wopx37_opx29_argx42(unk2_sdif_gigactx *gctx, uint32_t param } } if (param_3 != (uint32_t *)0x0) { - *param_3 = local_44.unk_4; + *param_3 = local_44.response[0]; } return 0; } static int sdif_op2_argx32(unk_sdif_ctx_init *param_1, void *param_2) { int iVar1; - sdif_arg_s local_38; + sdif_command_s local_38; - local_38.op_id = 2; - local_38.some_arg1 = 0x32; + local_38.cmd_index = 2; + local_38.cmd_settings = 0x32; local_38.dst_addr = 0; - local_38.sector = 0; + local_38.argument1 = 0; local_38.this_size = 0x30; iVar1 = write_args_retry(param_1, &local_38, 3); if (-1 < iVar1) { - memcpy(param_2, &local_38.unk_4, 0x10); + memcpy(param_2, local_38.response, sizeof(local_38.response)); iVar1 = 0; } return iVar1; @@ -794,16 +945,16 @@ static int sdif_op2_argx32(unk_sdif_ctx_init *param_1, void *param_2) { static int sdif_op3_argx82(unk2_sdif_gigactx *gctx, uint16_t *param_2) { int iVar1; - sdif_arg_s local_38; + sdif_command_s local_38; - local_38.sector = 0; - local_38.op_id = 3; - local_38.some_arg1 = 0x82; + local_38.argument1 = 0; + local_38.cmd_index = 3; + local_38.cmd_settings = 0x82; local_38.this_size = 0x30; iVar1 = write_args_retry(gctx->sctx, &local_38, 3); if (-1 < iVar1) { if (param_2 != (uint16_t *)0x0) { - *param_2 = (local_38.unk_4 >> 0x10) & 0xffff; + *param_2 = (local_38.response[0] >> 0x10) & 0xffff; } iVar1 = 0; } @@ -812,17 +963,17 @@ static int sdif_op3_argx82(unk2_sdif_gigactx *gctx, uint16_t *param_2) { static int sdif_op7_argxy3(unk_sdif_ctx_init *param_1, int param_2) { int iVar1; - sdif_arg_s local_34; + sdif_command_s local_34; local_34.this_size = 0x30; - local_34.some_arg1 = 3; + local_34.cmd_settings = 3; if (param_2 != 0) { - local_34.some_arg1 = 0x13; + local_34.cmd_settings = 0x13; } - local_34.sector = 0; - local_34.op_id = 7; + local_34.argument1 = 0; + local_34.cmd_index = 7; if (param_2 != 0) { - local_34.sector = (uint32_t)param_1->unk_half_id << 0x10; + local_34.argument1 = (uint32_t)param_1->unk_half_id << 0x10; } iVar1 = write_args_retry(param_1, &local_34, 3); if (-1 < iVar1) { @@ -833,16 +984,16 @@ static int sdif_op7_argxy3(unk_sdif_ctx_init *param_1, int param_2) { static int sdif_op9_argx33(unk_sdif_ctx_init *param_1, void *param_2) { int iVar1; - sdif_arg_s op; + sdif_command_s op; - op.some_arg1 = 0x33; - op.op_id = 9; + op.cmd_settings = 0x33; + op.cmd_index = 9; op.this_size = 0x30; op.dst_addr = 0; - op.sector = (uint32_t)param_1->unk_half_id << 0x10; + op.argument1 = (uint32_t)param_1->unk_half_id << 0x10; iVar1 = write_args_retry(param_1, &op, 3); if (-1 < iVar1) { - memcpy(param_2, &op.unk_4, 0x10); + memcpy(param_2, op.response, sizeof(op.response)); iVar1 = 0; } return iVar1; @@ -850,61 +1001,78 @@ static int sdif_op9_argx33(unk_sdif_ctx_init *param_1, void *param_2) { static int sdif_opx10_argx13(unk_sdif_ctx_init *param_1, uint32_t param_2) { int iVar1; - sdif_arg_s op; + sdif_command_s op; op.dst_addr = 0; - op.op_id = 0x10; - op.some_arg1 = 0x13; + op.cmd_index = 16; + op.cmd_settings = 0x13; op.this_size = 0x30; - op.sector = param_2; + op.argument1 = param_2; iVar1 = write_args_retry(param_1, &op, 3); - if ((-1 < iVar1) && (iVar1 = parse_op_unk_4(op.unk_4), -1 < iVar1)) { + if ((-1 < iVar1) && (iVar1 = R1_card_status_to_errcode(op.response[0]), -1 < iVar1)) { iVar1 = 0; } return iVar1; } -static uint32_t sdinit_lut0[8] = {0x2710, 0x186a0, 0xf4240, 0x989680, 0, 0, 0, 0}; -static uint8_t sdinit_lut1[0x10] = {0x0, 0xA, 0xC, 0xD, 0xF, 0x14, 0x19, 0x1E, 0x23, 0x28, 0x2d, 0x32, 0x37, 0x3c, 0x46, 0x50}; +/** + * TRAN_SPEED unit and time value look-up tables + * + * N.B.: to remove the need for floating point arithmetic, values in the + * time value LUT are pre-multiplied by 10, and values in the unit LUT are + * pre-divided by 10 to compensate. + */ +static const uint32_t CSD_TRAN_SPEED_unit_LUT[] = { + 10000, /* 100 Kbit/s */ + 100000, /* 1 Mbit/s */ + 1000000, /* 10 Mbit/s */ + 10000000, /* 100 Mbit/s */ + 0, 0, 0, 0 /* Reserved */ +}; + +static const uint8_t CSD_TRAN_SPEED_value_LUT[] = { + 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 +}; int sdif_init_sd(unk2_sdif_gigactx *gctx) { int iret; uint32_t sdif_unk0; - sdif_arg_s op; + sdif_command_s op; if ((!gctx) || (!gctx->sctx)) return -2; - iret = sdif_wait_reg16x12(gctx->sctx); + iret = sdif_wait_card_present(gctx->sctx); if (iret < 0) return iret; if (!iret) return -0x7fcdffff; gctx->quirks = 0; - if (gctx->op9_switchd) { // already ran once, do reset? - volatile uint16_t *regs = gctx->sctx->sdif_regs_addr; - regs[0x16] = 0; - v8p(regs + 0x14) = 0; - v8p((int)regs + 0x29) = 0; + if (gctx->gcsdCardSizeInBlocks) { // already ran once, do reset? + SceSdifReg *sdif = gctx->sctx->sdif_regs_addr; + + sdif->ClockControl = 0; + sdif->HostControl1 = 0; + sdif->PowerControl = 0; delay(10000); } - iret = sdif_cfg_reg16x16(gctx->sctx); + iret = sdif_configure_bus(gctx->sctx); if (iret < 0) return iret; delay(10000); - iret = sdif_pingwaitcfg_regs(gctx->sctx, 2); + iret = sdif_reset_controller_config(gctx->sctx, 2); if (iret < 0) return iret; - iret = sdif_op0_arg1(gctx->sctx); + iret = sdif_cmd0_go_idle_state(gctx->sctx); if (iret < 0) return iret; sdif_unk0 = gctx->sctx->unk_0; { // sdif_op8_argx92 - memset(&op, 0, sizeof(sdif_arg_s)); - op.some_arg1 = 0x92; - op.op_id = 8; + memset(&op, 0, sizeof(op)); + op.cmd_settings = 0x92; + op.cmd_index = 8; op.this_size = 0x30; - op.sector = 0xaa; + op.argument1 = 0xaa; if ((sdif_unk0 & 0xff8000) != 0) { - op.sector = 0x1aa; + op.argument1 = 0x1aa; } op.dst_addr = 0; iret = write_args_retry(gctx->sctx, &op, 3); @@ -931,50 +1099,72 @@ int sdif_init_sd(unk2_sdif_gigactx *gctx) { if (iret < 0) return iret; { // sdif_opx2a_argx13 - memset(&op, 0, sizeof(sdif_arg_s)); - op.op_id = 0x2a; - op.some_arg1 = 0x13; - op.sector = 0; + memset(&op, 0, sizeof(op)); + op.cmd_index = 42; + op.cmd_settings = 0x13; + op.argument1 = 0; op.this_size = 0x30; iret = sdif_loop_opx37_argx13_oparg(gctx, &op, 3); - if ((-1 < iret) && (iret = parse_op_unk_4(op.unk_4), -1 < iret)) { + if ((-1 < iret) && (iret = R1_card_status_to_errcode(op.response[0]), -1 < iret)) { iret = 0; } } if (iret < 0) return iret; sdif_op7_argxy3(gctx->sctx, 0); - iret = sdif_op9_argx33(gctx->sctx, gctx->op9_argx33); + iret = sdif_op9_argx33(gctx->sctx, gctx->cardSpecificData); if (iret < 0) return iret; + iret = sdif_op7_argxy3(gctx->sctx, 1); if (iret < 0) return iret; - uint32_t *tmptr = (uint32_t *)gctx->op9_argx33; - int op9_2bx7e = (uint8_t)bitfield_extract((int)tmptr, 0x7e, 2); // orig gigactx + 0x38 - iret = (int)bitfield_extract((int)tmptr, 99, 4); - if (iret > 0xf) - iret = 0; - gctx->op9_lutd = (uint32_t)sdinit_lut1[iret] * sdinit_lut0[bitfield_extract((int)tmptr, 0x60, 3)]; // orig gigactx + 0x39 - if (op9_2bx7e == 1) { - gctx->op9_switchd = (bitfield_extract((int)tmptr, 0x30, 22) + 1) * 0x400; // orig gigactx + 0x3b + // orig gigactx + 0x38 + int csd_structure_version = (uint8_t)bitfield_extract(gctx->cardSpecificData, CSD_STRUCTURE_OFFSET, CSD_STRUCTURE_SIZE); + { + int tran_speed_val = (int)bitfield_extract(gctx->cardSpecificData, CSD_TRAN_SPEED_VALUE_OFFSET, CSD_TRAN_SPEED_VALUE_SIZE); + if (tran_speed_val > 0xf) + tran_speed_val = 0; + + int tran_speed_unit = (int)bitfield_extract(gctx->cardSpecificData, CSD_TRAN_SPEED_UNIT_OFFSET, CSD_TRAN_SPEED_UNIT_SIZE); + + // orig gigactx + 0x39 + gctx->maxTransferSpeed = (uint32_t)CSD_TRAN_SPEED_value_LUT[tran_speed_val] * CSD_TRAN_SPEED_unit_LUT[tran_speed_unit]; + } + + if (csd_structure_version == 1) { //CSD Version 2.0 + /** + * memory capacity = (C_SIZE + 1) * 512Kbytes, BLOCKNR = memory capacity / SECTOR_SIZE + * ==> BLOCKNR = (C_SIZE + 1) * (512 * 1024) / 512 = (C_SIZE + 1) * 1024 + */ + // orig gigactx + 0x3b + gctx->gcsdCardSizeInBlocks = (bitfield_extract(gctx->cardSpecificData, CSD_20_C_SIZE_OFFSET, CSD_20_C_SIZE_SIZE) + 1) * 1024; + + /* SDHC/SDXC use sector-based addressing */ gctx->quirks = gctx->quirks | 1; - } else { - if (op9_2bx7e) + } else if (csd_structure_version == 0) { //CSD Version 1.0 + /** + * MULT = 2^(C_SIZE_MULT + 2) + * BLOCKNR = (C_SIZE + 1) * MULT + */ + uint32_t C_SIZE = bitfield_extract(gctx->cardSpecificData, CSD_10_C_SIZE_OFFSET, CSD_10_C_SIZE_SIZE); + uint32_t C_SIZE_MULT = bitfield_extract(gctx->cardSpecificData, CSD_10_C_SIZE_MULT_OFFSET, CSD_10_C_SIZE_MULT_SIZE); + + gctx->gcsdCardSizeInBlocks = (C_SIZE + 1) << (2 + C_SIZE_MULT); + } else { // unknown CSD version return -1; - gctx->op9_switchd = ((int)bitfield_extract((int)tmptr, 0x3e, 12) + 1) << (((int)bitfield_extract((int)tmptr, 0x2f, 3) + 2) & 0x1f); } uint8_t opx33_argx114[0x200]; memset(opx33_argx114, 0, 0x200); { // sdif_opx33_argx114 - memset(&op, 0, sizeof(sdif_arg_s)); - op.sector_count = 0; - op.sector = 0; - op.op_id = 0x33; - op.some_arg1 = 0x114; - op.sector_size = 8; + memset(&op, 0, sizeof(op)); + op.block_count = 0; + op.argument1 = 0; + op.cmd_index = 51; + op.cmd_settings = 0x114; + op.block_size = 8; op.this_size = 0x30; op.dst_addr = (uint32_t)opx33_argx114; // orig gigactx + 0x36; iret = sdif_loop_opx37_argx13_oparg(gctx, &op, 3); @@ -994,20 +1184,20 @@ int sdif_init_sd(unk2_sdif_gigactx *gctx) { static int sdif_op1_argx42(unk2_sdif_gigactx *gctx, uint32_t param_2, uint32_t *param_3) { int iVar1; int iVar2; - sdif_arg_s op; + sdif_command_s op; iVar2 = 0; op.dst_addr = 0; - op.op_id = 1; - op.some_arg1 = 0x42; + op.cmd_index = 1; + op.cmd_settings = 0x42; op.this_size = 0x30; - op.sector = param_2; + op.argument1 = param_2; while (true) { iVar1 = write_args_retry(gctx->sctx, &op, 0); if (iVar1 < 0) { return iVar1; } - if ((param_2 == 0) || ((int)op.unk_4 < 0)) + if ((param_2 == 0) || ((int)op.response[0] < 0)) break; delay(10000); iVar2 = iVar2 + 1; @@ -1016,35 +1206,36 @@ static int sdif_op1_argx42(unk2_sdif_gigactx *gctx, uint32_t param_2, uint32_t * } } if (param_3 != (uint32_t *)0x0) { - *param_3 = op.unk_4; + *param_3 = op.response[0]; } return 0; } -static uint32_t *mmcinit_lut0 = sdinit_lut0; -static uint8_t mmcinit_lut1[0x10] = {0x0, 0xA, 0xC, 0xD, 0xF, 0x14, 0x1A, 0x1E, 0x23, 0x28, 0x2d, 0x34, 0x37, 0x3c, 0x46, 0x50}; - // TODO: replicate a "-1" / failed init, left commented printf's for now int sdif_init_mmc(unk2_sdif_gigactx *gctx) { int iret; - sdif_arg_s op; + sdif_command_s op; if ((!gctx) || (!gctx->sctx)) return -2; // printf("pre sdif_wait_reg16x12\n"); - iret = sdif_wait_reg16x12(gctx->sctx); + iret = sdif_wait_card_present(gctx->sctx); if (iret < 0) return iret; - if (!iret) + + if (!iret) /* device not present */ return -1; + gctx->quirks = 1; // printf("pre sdif_cfg_reg16x16\n"); - iret = sdif_cfg_reg16x16(gctx->sctx); + iret = sdif_configure_bus(gctx->sctx); if (iret < 0) return iret; - // printf("pre sdif_op0_arg1\n"); - iret = sdif_op0_arg1(gctx->sctx); + + // printf("pre sdif_cmd0_go_idle_state\n"); + iret = sdif_cmd0_go_idle_state(gctx->sctx); if (iret < 0) return iret; + // printf("pre sdif_op1_argx42\n"); iret = sdif_op1_argx42(gctx, gctx->sctx->unk_0 | 0x40000000, 0); if (iret < 0) @@ -1058,30 +1249,36 @@ int sdif_init_mmc(unk2_sdif_gigactx *gctx) { return iret; { // sdif_op3_argx13 - memset(&op, 0, sizeof(sdif_arg_s)); - op.op_id = 3; - op.some_arg1 = 0x13; - op.sector = 1 << 0x10; + memset(&op, 0, sizeof(op)); + op.cmd_index = 3; + op.cmd_settings = 0x13; + op.argument1 = 1 << 0x10; op.this_size = 0x30; // printf("pre write_args_retry [sdif_op3_argx13]\n"); iret = write_args_retry(gctx->sctx, &op, 3); - if ((-1 < iret) && (iret = parse_op_unk_4(op.unk_4), -1 < iret)) { + if ((-1 < iret) && (iret = R1_card_status_to_errcode(op.response[0]), -1 < iret)) { iret = 0; } } if (iret < 0) return iret; + gctx->sctx->unk_half_id = 1; // printf("pre sdif_op9_argx33\n"); - iret = sdif_op9_argx33(gctx->sctx, gctx->op9_argx33); + iret = sdif_op9_argx33(gctx->sctx, gctx->cardSpecificData); if (iret < 0) return iret; - uint32_t *tmptr = (uint32_t *)gctx->op9_argx33; - iret = (int)bitfield_extract((int)tmptr, 99, 4); - if (iret > 0xf) - iret = 0; - gctx->op9_lutd = (uint32_t)mmcinit_lut1[iret] * mmcinit_lut0[bitfield_extract((int)tmptr, 0x60, 3)]; // orig gigactx + 0xa9 + { + int tran_speed_val = (int)bitfield_extract(gctx->cardSpecificData, CSD_TRAN_SPEED_VALUE_OFFSET, CSD_TRAN_SPEED_VALUE_SIZE); + if (tran_speed_val > 0xf) + tran_speed_val = 0; + + int tran_speed_unit = (int)bitfield_extract(gctx->cardSpecificData, CSD_TRAN_SPEED_UNIT_OFFSET, CSD_TRAN_SPEED_UNIT_SIZE); + + // orig gigactx + 0xa9 + gctx->maxTransferSpeed = (uint32_t)CSD_TRAN_SPEED_value_LUT[tran_speed_val] * CSD_TRAN_SPEED_unit_LUT[trans_speed_unit]; + } // printf("pre sdif_op7_argxy3\n"); iret = sdif_op7_argxy3(gctx->sctx, 1); @@ -1091,12 +1288,12 @@ int sdif_init_mmc(unk2_sdif_gigactx *gctx) { uint8_t buf[0x200]; memset(buf, 0, 0x200); { // sdif_op8_argx114 - memset(&op, 0, sizeof(sdif_arg_s)); - op.sector_count = 0; - op.sector = 0; - op.op_id = 8; - op.some_arg1 = 0x114; - op.sector_size = 0x200; + memset(&op, 0, sizeof(op)); + op.block_count = 0; + op.argument1 = 0; + op.cmd_index = 8; + op.cmd_settings = 0x114; + op.block_size = 0x200; op.this_size = 0x30; op.dst_addr = (uint32_t)buf; // printf("pre write_args_retry [sdif_op8_argx114]\n"); @@ -1125,11 +1322,11 @@ int sdif_init_mmc(unk2_sdif_gigactx *gctx) { if (-1 < iret) { if (gctx->op8_switchd) { { // sdif_op6_argx2b - memset(&op, 0, sizeof(sdif_arg_s)); - op.some_arg1 = 0x2b; - op.op_id = 6; + memset(&op, 0, sizeof(op)); + op.cmd_settings = 0x2b; + op.cmd_index = 6; op.this_size = 0x30; - op.sector = ((1) & 0xff) << 8 | (((0xb9) & 0xff) << 0x10) | ((0) & 3) | 0x3000000; + op.argument1 = ((1) & 0xff) << 8 | (((0xb9) & 0xff) << 0x10) | ((0) & 3) | 0x3000000; // printf("pre write_args_retry [sdif_op6_argx2b]\n"); iret = write_args_retry(gctx->sctx, &op, 3); if (-1 < iret) { @@ -1138,11 +1335,11 @@ int sdif_init_mmc(unk2_sdif_gigactx *gctx) { } if (iret < 0) return iret; - // printf("pre sdif_work_reg16x16\n"); - iret = sdif_work_reg16x16(gctx->sctx, gctx->op9_lutd, 1); + // printf("pre sdif_configure_bus_speed\n"); + iret = sdif_configure_bus_speed(gctx->sctx, gctx->maxTransferSpeed, 1); } else { - // printf("pre sdif_work_reg16x16\n"); - iret = sdif_work_reg16x16(gctx->sctx, gctx->op8_switchd, 0); + // printf("pre sdif_configure_bus_speed\n"); + iret = sdif_configure_bus_speed(gctx->sctx, gctx->op8_switchd, 0); } if (-1 < iret) iret = 0;