1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. 背景
在 S5P4418
的 Android 5.1.1
下调试 eMMC 时的笔记。
3. eMMC参数调试
3.1 eMMC数据位宽调整
/* @lollipop_2nd_release/u-boot/include/configs/s5p6818_drone.h */
#define CONFIG_MMC0_CLOCK 50000000
#define CONFIG_MMC0_CLK_DELAY DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(2)| DW_MMC_SAMPLE_PHASE(1)
#define CONFIG_MMC2_CLOCK 50000000
#define CONFIG_MMC2_CLK_DELAY DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(3)| DW_MMC_SAMPLE_PHASE(2)
#define CONFIG_MMC2_BUS_WIDTH 8 /* 数据位宽调整为 8-bit */
#define CONFIG_MMC2_TRANS_MODE 0 //1 : DDR_MODE, 0: SDR_MODE
3.2 eMMC容量调整
/* @ lollipop-5.1.1_r6/device/nexell/s5p4418_drone/BoardConfig.mk */
# packaging for emmc, sd
TARGET_USERIMAGES_USE_EXT4 := true
BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 790626304
BOARD_CACHEIMAGE_PARTITION_SIZE := 448790528
BOARD_USERDATAIMAGE_PARTITION_SIZE := 6000000000 /6000000000-8G /14000000000 -16G
BOARD_FLASH_BLOCK_SIZE := 4096
3.3 eMMC时钟/时序调整
3.3.1 内核调整
/* @lollipop-5.1.1_r6/kernel/arch/arm/plat-s5p4418/drone/device.c */
#ifdef CONFIG_MMC_NXP_CH0
static struct dw_mci_board _dwmci0_data = {
.quirks = DW_MCI_QUIRK_HIGHSPEED,
.bus_hz = 100 * 1000 * 1000,
.caps = MMC_CAP_CMD23,
.detect_delay_ms= 200,
.cd_type = DW_MCI_CD_EXTERNAL,
.clk_dly = DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(2) | DW_MMC_SAMPLE_PHASE(1),
.init = _dwmci0_init,
.get_ro = _dwmci_get_ro,
.get_cd = _dwmci0_get_cd,
.ext_cd_init = _dwmci_ext_cd_init,
.ext_cd_cleanup = _dwmci_ext_cd_cleanup,
#if defined (CONFIG_MMC_DW_IDMAC) && defined (CONFIG_MMC_NXP_CH0_USE_DMA)
.mode = DMA_MODE,
#else
.mode = PIO_MODE,
#endif
};
#endif
#ifdef CONFIG_MMC_NXP_CH1
static struct dw_mci_board _dwmci1_data = {
.quirks = DW_MCI_QUIRK_HIGHSPEED,
.bus_hz = 100 * 1000 * 1000,
.caps = MMC_CAP_CMD23|MMC_CAP_NONREMOVABLE,
.detect_delay_ms= 200,
.cd_type = DW_MCI_CD_NONE,
.pm_caps = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY,
.clk_dly = DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(0) | DW_MMC_SAMPLE_PHASE(0),
#if defined (CONFIG_MMC_DW_IDMAC) && defined (CONFIG_MMC_NXP_CH1_USE_DMA)
.mode = DMA_MODE,
#else
.mode = PIO_MODE,
#endif
};
#endif
#ifdef CONFIG_MMC_NXP_CH2
static struct dw_mci_board _dwmci2_data = {
.quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION |
DW_MCI_QUIRK_HIGHSPEED |
DW_MMC_QUIRK_HW_RESET_PW |
DW_MCI_QUIRK_NO_DETECT_EBIT,
.bus_hz = 100 * 1000 * 1000,
.caps = MMC_CAP_UHS_DDR50 |
MMC_CAP_NONREMOVABLE |
MMC_CAP_4_BIT_DATA | MMC_CAP_CMD23 |
MMC_CAP_HW_RESET,
.clk_dly = DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(3) | DW_MMC_SAMPLE_PHASE(2),
.desc_sz = 4,
.detect_delay_ms= 200,
.sdr_timing = 0x01010001,
.ddr_timing = 0x03030002,
#if defined (CONFIG_MMC_DW_IDMAC) && defined (CONFIG_MMC_NXP_CH2_USE_DMA)
.mode = DMA_MODE,
#else
.mode = PIO_MODE,
#endif
};
#endif
#endif /* CONFIG_MMC_DW */
3.3.2 u-boot调整
/* @lollipop-5.1.1_r6/u-boot/include/configs/s5p4418_drone.h */
#if defined(CONFIG_CMD_MMC)
#define CONFIG_MMC
#define CONFIG_GENERIC_MMC
#define HAVE_BLOCK_DEVICE
#define CONFIG_MMC0_ATTACH TRUE /* 0 = MMC0 : External */
#define CONFIG_MMC1_ATTACH FALSE /* 1 = MMC1 : */
#define CONFIG_MMC2_ATTACH TRUE /* 2 = MMC2 : BOOT(eMMC) */
#define CONFIG_MMC0_CLOCK 25000000
#define CONFIG_MMC0_CLK_DELAY DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(2)| DW_MMC_SAMPLE_PHASE(1)
#define CONFIG_MMC2_CLOCK 50000000
#define CONFIG_MMC2_CLK_DELAY DW_MMC_DRIVE_DELAY(0) | DW_MMC_SAMPLE_DELAY(0) | DW_MMC_DRIVE_PHASE(3)| DW_MMC_SAMPLE_PHASE(2)
#define CONFIG_MMC2_BUS_WIDTH 4
3.3.3 低版本内核不支持eMMC 5.1及以后版本调整
/* @kernel/drivers/mmc/core/mmc.c */
static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
...
//if (card->ext_csd.rev > 7) {
if (card->ext_csd.rev > 8) { /* 支持 eMMC 5.1 */
...
}
4. 关于 eMMC 常见问题小结
本小节总结调试 eMMC 时遇到的常见问题,将持续更新。
1. 有时候 eMMC 无法初始化成功,内核会打印对不同频率进行设置的日志。这时候可能需要检查 eMMC 各 PIN
脚信号。供电不正常经常导致这类问题,如本应使用 1.8V 供电,却使用了 3.3V 供电,等等情形。
5. 后记
本文以及相关篇章基于刚接触Linux嵌入式系统开发的小白阶段,或存在错漏。从开始学习编译内核,修改内核配置,移植一个驱动,然后学习自己写驱动,各种工具使用,Git代码管理,… 嗯,一段值得怀念的岁月啊_。