diff --git a/bdk/storage/mbr_gpt.h b/bdk/storage/mbr_gpt.h index 9e0e97d..7f38108 100644 --- a/bdk/storage/mbr_gpt.h +++ b/bdk/storage/mbr_gpt.h @@ -39,40 +39,40 @@ typedef struct _mbr_part_t typedef struct _mbr_t { - u8 bootstrap[440]; - u32 signature; - u16 copy_protected; - mbr_part_t partitions[4]; - u16 boot_signature; +/* 0x000 */ u8 bootstrap[440]; +/* 0x1B8 */ u32 signature; +/* 0x1BC */ u16 copy_protected; +/* 0x1BE */ mbr_part_t partitions[4]; +/* 0x1FE */ u16 boot_signature; } __attribute__((packed)) mbr_t; typedef struct _gpt_entry_t { - u8 type_guid[0x10]; - u8 part_guid[0x10]; - u64 lba_start; - u64 lba_end; - u64 attrs; - u16 name[36]; +/* 0x00 */ u8 type_guid[0x10]; +/* 0x10 */ u8 part_guid[0x10]; +/* 0x20 */ u64 lba_start; +/* 0x28 */ u64 lba_end; +/* 0x30 */ u64 attrs; +/* 0x38 */ u16 name[36]; } gpt_entry_t; typedef struct _gpt_header_t { - u64 signature; // "EFI PART" - u32 revision; - u32 size; - u32 crc32; - u32 res1; - u64 my_lba; - u64 alt_lba; - u64 first_use_lba; - u64 last_use_lba; - u8 disk_guid[0x10]; - u64 part_ent_lba; - u32 num_part_ents; - u32 part_ent_size; - u32 part_ents_crc32; - u8 res2[420]; // Used as first 3 partition entries backup for HOS. +/* 0x00 */ u64 signature; // "EFI PART" +/* 0x08 */ u32 revision; +/* 0x0C */ u32 size; +/* 0x10 */ u32 crc32; +/* 0x14 */ u32 res1; +/* 0x18 */ u64 my_lba; +/* 0x20 */ u64 alt_lba; +/* 0x28 */ u64 first_use_lba; +/* 0x30 */ u64 last_use_lba; +/* 0x38 */ u8 disk_guid[0x10]; +/* 0x48 */ u64 part_ent_lba; +/* 0x50 */ u32 num_part_ents; +/* 0x54 */ u32 part_ent_size; +/* 0x58 */ u32 part_ents_crc32; +/* 0x5C */ u8 res2[420]; // Used as first 3 partition entries backup for HOS. } gpt_header_t; typedef struct _gpt_t diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c index ca0a115..965fd73 100644 --- a/bdk/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -1187,29 +1187,40 @@ int _sd_storage_set_driver_type(sdmmc_storage_t *storage, u32 driver, u8 *buf) /* * SD Card DDR200 (DDR208) support * - * Proper procedure: + * DLL Tuning (a) or Tuning Window (b) procedure: * 1. Check that Vendor Specific Command System is supported. * Used as Enable DDR200 Bus. * 2. Enable DDR200 bus mode via setting 14 to Group 2 via CMD6. * Access Mode group is left to default 0 (SDR12). * 3. Setup clock to 200 or 208 MHz. - * 4. Set host to DDR bus mode that supports such high clocks. - * Some hosts have special mode, others use DDR50 and others HS400. - * 5. Execute Tuning. + * 4a. Set host to DDR200/HS400 bus mode that enables DLL syncing. + * Actual implementation supported by all DDR200 cards. + * -- + * 4b. Set host to DDR50 bus mode that supports such high clocks. + * Execute Manual Tuning. + * Limited to non-Sandisk cards. * - * The true validation that this value in Group 2 activates it, is that DDR50 bus - * and clocks/timings work fully after that point. + * On Tegra SoCs, that can be done with DDR50 host mode. + * That's because HS400 4-bit or HS400 generally, is not supported on SD SDMMC. + * And also, tuning can't be done automatically on any DDR mode. + * So it needs to be done manually and selected tap will be applied from the + * biggest sampling window. + * That allows DDR200 support on every DDR200 SD card, other than the original + * maker of DDR200, Sandisk. * - * On Tegra X1, that can be done with DDR50 host mode. - * Tuning though can't be done automatically on any DDR mode. - * So it needs to be done manually and selected tap will be applied from the biggest - * sampling window. + * On the original implementation of DDR200 from Sandisk, a DLL mechanism, + * like the one in eMMC HS400 is mandatory. + * So the card can start data signals whenever it wants, and the host should + * synchronize to the first DAT signal edge change. + * Every single other vendor that implemented that, always starts data transfers + * aligned to clock. That basically makes DDR200 in such SD cards a SDR104 but + * sampled on both edges. So effectively, it's an in-spec signal with DDR50, + * only that is clocked at 200MHz, instead of 50MHz. + * So the extra needed thing is using a tuning window, which is absent from the + * original implementation, since DDL syncing does not use that. * - * Finally, all that simply works, because the marketing materials for DDR200 are - * basically overstatements to sell the feature. DDR200 is simply SDR104 in DDR mode, - * so sampling on rising and falling edge and with variable output data window. - * It can be supported by any host that is fast enough to support DDR at 200/208MHz - * and can do hw/sw tuning for finding the proper sampling window in that mode. + * On DLL tuning method expected cards, the tuning window is tiny. + * So check against a minimum of 8 taps window, to disallow DDR200. */ #ifdef BDK_SDMMC_UHS_DDR200_SUPPORT static int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf) diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c index e4f8a37..8f5b658 100644 --- a/bdk/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -344,6 +344,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) break; case SDHCI_TIMING_MMC_HS400: + // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; @@ -723,8 +724,9 @@ static int _sdmmc_manual_tuning_set_tap(sdmmc_t *sdmmc, sdmmc_manual_tuning_t *t } } - // Check if failed. - if (!best_tap) + + // Check if failed or window too small. + if (!best_tap || best_size < SAMPLING_WINDOW_SIZE_MIN) return 0; sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; @@ -743,9 +745,12 @@ static int _sdmmc_manual_tuning_set_tap(sdmmc_t *sdmmc, sdmmc_manual_tuning_t *t * SD Card DDR200 (DDR208) support * * On Tegra X1, that can be done with DDR50 host mode. - * Tuning though can't be done automatically on any DDR mode. + * That's because HS400 4-bit or HS400 generally, is not supported on SDMMC1/3. + * And also, tuning can't be done automatically on any DDR mode. * So it needs to be done manually and selected tap will be applied from the biggest * sampling window. + * That allows DDR200 support on every DDR200 sd card, other than the original maker + * of DDR200, Sandisk. Since Sandisk cards mandate DLL syncing. */ static int sdmmc_tuning_execute_ddr200(sdmmc_t *sdmmc) { @@ -1041,7 +1046,7 @@ static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) sdmmc->dma_addr_next = ALIGN_DOWN((admaaddr + SZ_512K), SZ_512K); - sdmmc->regs->blksize = req->blksize | (7 << 12); // SDMA DMA 512KB Boundary (Detects A18 carry out). + sdmmc->regs->blksize = req->blksize | (7u << 12); // SDMA DMA 512KB Boundary (Detects A18 carry out). sdmmc->regs->blkcnt = blkcnt; if (blkcnt_out) diff --git a/bdk/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h index bbef04e..ee62eaf 100644 --- a/bdk/storage/sdmmc_driver.h +++ b/bdk/storage/sdmmc_driver.h @@ -23,9 +23,9 @@ /*! SDMMC controller IDs. */ #define SDMMC_1 0 // Version 4.00. -#define SDMMC_2 1 // Version 5.1. +#define SDMMC_2 1 // Version 5.0 + SW CQE + Enhanced Strobe. #define SDMMC_3 2 // Version 4.00. -#define SDMMC_4 3 // Version 5.1. +#define SDMMC_4 3 // Version 5.0 + SW CQE + Enhanced Strobe. /*! SDMMC power types. */ #define SDMMC_POWER_OFF 0 @@ -273,8 +273,9 @@ /*! Helper for SWITCH command argument. */ #define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) -#define HW_TAP_TUNING 0x100 -#define INVALID_TAP 0x100 +#define HW_TAP_TUNING 0x100 +#define INVALID_TAP 0x100 +#define SAMPLING_WINDOW_SIZE_MIN 8 /*! SDMMC controller context. */ typedef struct _sdmmc_t