0,查看mmc 信息
=> bdinfo
arch_number = 0x00000000
boot_params = 0x00000000
DRAM bank = 0x00000000
-> start = 0x00200000
-> size = 0x08200000
DRAM bank = 0x00000001
-> start = 0x09400000
-> size = 0x76C00000
baudrate = 1500000 bps
TLB addr = 0x7FFF0000
relocaddr = 0x7DC1C000
reloc off = 0x7D21C000
irq_sp = 0x7B9F8570
sp start = 0x7B9F8570
FB base = 0x00000000
Early malloc usage: 3568 / 80000
fdt_blob = 0000000008300000
1,初始化
// 文件:common/board_r.c
static init_fnc_t init_sequence_r[] = {
// ... 其他初始化 ...
initr_mmc, // MMC子系统初始化
// ... 后续初始化 ...
};
// 文件:common/board_r.c
static int initr_mmc(void)
{
struct mmc *mmc;
int ret = 0;
int i;
debug("Initializing MMC subsystem\n");
// 遍历所有MMC控制器
for (i = 0; ; i++) {
mmc = find_mmc_device(i);
if (!mmc)
break;
debug("Found MMC device %d: %s\n", i, mmc->cfg->name);
// 执行MMC初始化
ret = mmc_init(mmc);
if (ret) {
printf("MMC%d init failed (ret=%d)\n", i, ret);
continue;
}
// 打印MMC设备信息
printf("MMC%d: ", i);
if (mmc->version & MMC_VERSION_SD)
printf("SD ");
if (mmc->version & MMC_VERSION_MMC)
printf("MMC ");
printf("card ");
if (mmc->high_capacity)
printf("high speed ");
printf("at ");
if (mmc->bus_width == 8)
printf("8-bit, ");
else if (mmc->bus_width == 4)
printf("4-bit, ");
else
printf("1-bit, ");
printf("%llu MB\n", mmc->capacity / (1024 * 1024));
}
return 0;
}
DWMMC控制器初始化
// 文件:drivers/mmc/rockchip_dw_mmc.c
static int rockchip_dwmmc_probe(struct udevice *dev)
{
struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc_config *cfg = &priv->cfg;
struct mmc *mmc;
int ret;
debug("%s: probing Rockchip DWMMC controller\n", __func__);
// 1. 获取寄存器基地址
priv->regbase = dev_read_addr_ptr(dev);
if (!priv->regbase) {
printf("%s: Failed to get ioaddr\n", __func__);
return -EINVAL;
}
// 2. 获取时钟
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret) {
debug("%s: Failed to get clock (ret=%d)\n", __func__, ret);
return ret;
}
// 3. 获取复位信号
ret = reset_get_by_index(dev, 0, &priv->reset);
if (!ret) {
reset_deassert(&priv->reset);
udelay(1000);
}
// 4. 从设备树读取控制器参数
cfg->f_max = dev_read_u32_default(dev, "max-frequency", 52000000);
priv->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0x100);
priv->fifo_mode = dev_read_bool(dev, "fifo-mode");
// 5. 配置MMC主机参数
cfg->name = dev->name;
cfg->host_caps = 0;
cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
cfg->f_min = 400000; // 400kHz
// 6. 读取总线宽度配置
u32 bus_width = 1;
if (!dev_read_u32(dev, "bus-width", &bus_width)) {
if (bus_width == 8) {
cfg->host_caps |= MMC_MODE_8BIT;
} else if (bus_width == 4) {
cfg->host_caps |= MMC_MODE_4BIT;
} else if (bus_width == 1) {
cfg->host_caps |= MMC_MODE_1BIT;
} else {
printf("%s: Invalid bus-width %d\n", __func__, bus_width);
return -EINVAL;
}
}
// 7. 创建MMC设备
mmc = mmc_create(cfg, priv);
if (!mmc) {
printf("%s: mmc_create failed\n", __func__);
return -ENODEV;
}
// 8. 设置私有数据
priv->mmc = mmc;
upriv->mmc = mmc;
debug("%s: MMC controller %s initialized successfully\n", __func__, dev->name);
return 0;
}
sd卡初始化
// 文件:drivers/mmc/mmc.c
int mmc_init(struct mmc *mmc)
{
int err = 0;
uint mult, freq;
u32 cid[4];
uint mmc_voltage;
bool no_card;
int ret = 0;
debug("Initialising MMC card\n");
if (mmc->has_init)
return 0;
// 1. 设置初始时钟频率
mmc_set_clock(mmc, mmc->cfg->f_min, MMC_CLK_ENABLE);
// 2. 发送CMD0使卡进入空闲状态
err = mmc_go_idle(mmc);
if (err)
goto err;
// 3. 发送CMD8检查SD卡电压兼容性
err = mmc_send_if_cond(mmc);
// 4. 发送CMD55+ACMD41初始化SD卡
if (!err) {
err = mmc_send_op_cond_sd(mmc);
if (!err) {
mmc->version = SD_VERSION_2;
printf("SD card detected\n");
}
}
// 5. 如果不是SD卡,尝试初始化MMC卡
if (err) {
err = mmc_send_op_cond_mmc(mmc);
if (!err) {
mmc->version = MMC_VERSION_1_2;
printf("MMC card detected\n");
}
}
if (err) {
printf("No card detected\n");
goto err;
}
// 6. 发送CMD2获取CID
err = mmc_all_send_cid(mmc);
if (err)
goto err;
// 7. 发送CMD3设置相对地址
err = mmc_set_relative_addr(mmc);
if (err)
goto err;
// 8. 发送CMD9获取CSD
err = mmc_send_csd(mmc, mmc->csd);
if (err)
goto err;
// 9. 解析CSD获取容量等信息
err = mmc_decode_csd(mmc);
if (err)
goto err;
// 10. 切换到高速模式
if (!mmc_host_is_spi(mmc) && mmc->version & MMC_VERSION_SD) {
err = sd_change_freq(mmc);
if (err)
goto err;
// 设置总线宽度
err = sd_set_bus_width(mmc);
if (err)
goto err;
}
// 11. 标记为已初始化
mmc->has_init = 1;
mmc->init_in_progress = 0;
printf("MMC card init complete\n");
return 0;
err:
mmc->has_init = 0;
printf("MMC card init failed: %d\n", err);
return err;
}
2,读写接口
// 文件:drivers/mmc/mmc_write.c
#ifdef CONFIG_BLK
ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
#else
ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, void *dst)
#endif
{
#ifdef CONFIG_BLK
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
#endif
int dev_num = block_dev->devnum;
struct mmc *mmc = find_mmc_device(dev_num);
ulong n = 0;
struct mmc_cmd cmd = {0};
struct mmc_data data = {0};
if (!mmc) {
printf("No MMC device at devnum %d\n", dev_num);
return 0;
}
if (mmc_getwp(mmc) == 1) {
printf("Card is write protected\n");
return 0;
}
debug("MMC read: dev=%d, start=" LBAF ", cnt=" LBAF "\n",
dev_num, start, blkcnt);
// 1. 检查边界
if ((start + blkcnt) > block_dev->lba) {
printf("MMC read: out of range\n");
return 0;
}
// 2. 配置读取命令
if (mmc->high_capacity) {
cmd.cmdarg = start;
} else {
cmd.cmdarg = start * mmc->read_bl_len;
}
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.resp_type = MMC_RSP_R1;
// 3. 配置数据
data.dest = dst;
data.blocks = blkcnt;
data.blocksize = mmc->read_bl_len;
data.flags = MMC_DATA_READ;
// 4. 发送命令读取数据
if (mmc_send_cmd(mmc, &cmd, &data)) {
printf("MMC read failed\n");
return 0;
}
// 5. 等待传输完成
if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
printf("MMC stop command failed\n");
return 0;
}
}
n = blkcnt;
debug("MMC read: read " LBAF " blocks\n", n);
return n;
}
#ifdef CONFIG_BLK
ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, const void *src)
#else
ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, const void *src)
#endif
{
#ifdef CONFIG_BLK
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
#endif
int dev_num = block_dev->devnum;
struct mmc *mmc = find_mmc_device(dev_num);
ulong n = 0;
struct mmc_cmd cmd = {0};
struct mmc_data data = {0};
if (!mmc) {
printf("No MMC device at devnum %d\n", dev_num);
return 0;
}
if (mmc_getwp(mmc) == 1) {
printf("Card is write protected\n");
return 0;
}
debug("MMC write: dev=%d, start=" LBAF ", cnt=" LBAF "\n",
dev_num, start, blkcnt);
// 1. 检查边界
if ((start + blkcnt) > block_dev->lba) {
printf("MMC write: out of range\n");
return 0;
}
// 2. 配置写入命令
if (mmc->high_capacity) {
cmd.cmdarg = start;
} else {
cmd.cmdarg = start * mmc->write_bl_len;
}
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
cmd.resp_type = MMC_RSP_R1;
// 3. 配置数据
data.src = src;
data.blocks = blkcnt;
data.blocksize = mmc->write_bl_len;
data.flags = MMC_DATA_WRITE;
// 4. 发送命令写入数据
if (mmc_send_cmd(mmc, &cmd, &data)) {
printf("MMC write failed\n");
return 0;
}
// 5. 等待传输完成
if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
printf("MMC stop command failed\n");
return 0;
}
}
n = blkcnt;
debug("MMC write: wrote " LBAF " blocks\n", n);
return n;
}
// 文件:drivers/mmc/dw_mmc.c
static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct dwmci_host *host = dev_get_priv(dev);
struct mmc *mmc = mmc_get_mmc_dev(dev);
u32 mask, flags = 0;
int ret = 0;
debug("CMD%d: arg=0x%08x, resp_type=0x%08x\n",
cmd->cmdidx, cmd->cmdarg, cmd->resp_type);
// 1. 配置命令
mask = dwmci_prepare_command(host, cmd);
// 2. 配置数据传输
if (data) {
flags = dwmci_prepare_data(host, data, cmd);
mask |= DWMCI_INTMSK_RXFIFO | DWMCI_INTMSK_TXFIFO |
DWMCI_INTMSK_DTO | DWMCI_INTMSK_DCRC |
DWMCI_INTMSK_DTO | DWMCI_INTMSK_SBE |
DWMCI_INTMSK_HTO | DWMCI_INTMSK_EBE;
}
// 3. 发送命令
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
dwmci_writel(host, DWMCI_CMD, mask);
// 4. 等待命令完成
ret = dwmci_wait_for_bit(host, DWMCI_RINTSTS, mask, false);
if (ret) {
printf("CMD%d failed (ret=%d)\n", cmd->cmdidx, ret);
goto out;
}
// 5. 处理数据
if (data) {
if (data->flags & MMC_DATA_READ) {
ret = dwmci_read_data(host, data);
} else {
ret = dwmci_write_data(host, data);
}
if (ret) {
printf("Data transfer failed (ret=%d)\n", ret);
goto out;
}
}
// 6. 获取响应
if (cmd->resp_type & MMC_RSP_PRESENT) {
if (cmd->resp_type & MMC_RSP_136) {
cmd->response[0] = dwmci_readl(host, DWMCI_RESP3);
cmd->response[1] = dwmci_readl(host, DWMCI_RESP2);
cmd->response[2] = dwmci_readl(host, DWMCI_RESP1);
cmd->response[3] = dwmci_readl(host, DWMCI_RESP0);
} else {
cmd->response[0] = dwmci_readl(host, DWMCI_RESP0);
}
}
out:
// 7. 清除中断状态
dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF);
return ret;
}
// 文件:common/cmd_mmc.c
static int do_mmc_send_cmd(struct cmd_tbl *cmdtp, int flag,
int argc, char *const argv[])
{
struct mmc *mmc;
struct mmc_cmd cmd;
int i, ret;
u32 arg, resp[4];
if (argc < 3)
return CMD_RET_USAGE;
// 获取当前MMC设备
mmc = find_mmc_device(curr_device);
if (!mmc) {
printf("No MMC device available\n");
return CMD_RET_FAILURE;
}
// 解析命令参数
cmd.cmdidx = (int)simple_strtoul(argv[1], NULL, 16);
cmd.cmdarg = hextoul(argv[2], NULL);
// 解析响应类型
if (argc > 3) {
cmd.resp_type = hextoul(argv[3], NULL);
} else {
// 默认响应类型
switch (cmd.cmdidx) {
case MMC_CMD_SEND_STATUS:
case MMC_CMD_SET_RELATIVE_ADDR:
case MMC_CMD_SELECT_CARD:
case MMC_CMD_SEND_CSD:
case MMC_CMD_SEND_CID:
case MMC_CMD_READ_SINGLE_BLOCK:
case MMC_CMD_READ_MULTIPLE_BLOCK:
case MMC_CMD_WRITE_SINGLE_BLOCK:
case MMC_CMD_WRITE_MULTIPLE_BLOCK:
case MMC_CMD_PROGRAM_CID:
case MMC_CMD_PROGRAM_CSD:
case MMC_CMD_SET_BLOCKLEN:
case MMC_CMD_ERASE_GROUP_START:
case MMC_CMD_ERASE_GROUP_END:
case MMC_CMD_ERASE:
case MMC_CMD_LOCK_UNLOCK:
case MMC_CMD_APP_CMD:
case MMC_CMD_GEN_CMD:
cmd.resp_type = MMC_RSP_R1;
break;
case MMC_CMD_SEND_OP_COND:
case SD_CMD_SEND_IF_COND:
case MMC_CMD_SPI_READ_OCR:
case MMC_CMD_SPI_CRC_ON_OFF:
cmd.resp_type = MMC_RSP_R3;
break;
case MMC_CMD_ALL_SEND_CID:
case MMC_CMD_SEND_CSD:
cmd.resp_type = MMC_RSP_R2;
break;
default:
cmd.resp_type = MMC_RSP_NONE;
break;
}
}
printf("Sending CMD%d, arg=0x%08x, resp_type=0x%08x\n",
cmd.cmdidx, cmd.cmdarg, cmd.resp_type);
// 发送命令
ret = mmc_send_cmd(mmc, &cmd, NULL);
if (ret) {
printf("CMD%d failed (ret=%d)\n", cmd.cmdidx, ret);
return CMD_RET_FAILURE;
}
// 显示响应
if (cmd.resp_type & MMC_RSP_PRESENT) {
if (cmd.resp_type & MMC_RSP_136) {
printf("Response: 0x%08x 0x%08x 0x%08x 0x%08x\n",
cmd.response[0], cmd.response[1],
cmd.response[2], cmd.response[3]);
} else {
printf("Response: 0x%08x\n", cmd.response[0]);
}
} else {
printf("No response expected\n");
}
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
mmc_send_cmd, 4, 1, do_mmc_send_cmd,
"Send raw MMC command",
"<cmd> <arg> [resp_type] - Send raw MMC command"
);
在U-Boot命令行中发送MMC命令
=> mmc_send_cmd 0 0 # CMD0: GO_IDLE_STATE
=> mmc_send_cmd 8 0x1AA 0x107 # CMD8: SEND_IF_COND, 响应类型R7
=> mmc_send_cmd 55 0 0x101 # CMD55: APP_CMD
=> mmc_send_cmd 41 0x40FF8000 0x103 # ACMD41: SD_APP_OP_COND
=> mmc_send_cmd 2 0 0x102 # CMD2: ALL_SEND_CID
=> mmc_send_cmd 3 0x1234 0x101 # CMD3: SET_RELATIVE_ADDR
=> mmc_send_cmd 9 0x12340000 0x102 # CMD9: SEND_CSD
=> mmc_send_cmd 7 0x12340000 0x101 # CMD7: SELECT_CARD
命令行实现
// 读取功能
static int mmc_read(int dev, int argc, char * const argv[])
{
struct mmc *mmc = find_mmc_device(dev);
u32 blk, cnt, n;
void *addr;
if (argc != 6)
return CMD_RET_USAGE;
addr = (void *)hextoul(argv[2], NULL);
blk = hextoul(argv[3], NULL);
cnt = hextoul(argv[4], NULL);
printf("\nMMC read: dev # %d, block # %d, count %d ... ",
dev, blk, cnt);
n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
// 写入功能
static int mmc_write(int dev, int argc, char * const argv[])
{
struct mmc *mmc = find_mmc_device(dev);
u32 blk, cnt, n;
void *addr;
if (argc != 6)
return CMD_RET_USAGE;
addr = (void *)hextoul(argv[2], NULL);
blk = hextoul(argv[3], NULL);
cnt = hextoul(argv[4], NULL);
printf("\nMMC write: dev # %d, block # %d, count %d ... ",
dev, blk, cnt);
n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
=> mmc list
dwmmc@fe2b0000: 1
dwmmc@fe2c0000: 2
sdhci@fe310000: 0 (eMMC)
=> mmc devswitch to partitions #0, OK
mmc0(part 0) is current device
=> mmc infoDevice: sdhci@fe310000
Manufacturer ID: ec
OEM: 2900
Name: AT2S3
Timing Interface: HS200
Tran Speed: 200000000
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 7.2 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 7.2 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
插上SD卡测试
=> mmc dev 1
Repair the backup gpt table OK!
Repair the backup gpt table OK!
switch to partitions #0, OK
mmc1 is current device
=> mmc dev
switch to partitions #0, OK
mmc1 is current device
查看sd卡信息
=> mmc info
Device: dwmmc@fe2b0000
Manufacturer ID: 12
OEM: 3456
Name: SDTiming Interface: Legacy
Tran Speed: 52000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 14.8 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
查看信息:uboot/arch/arm/dts/rk3568.dtsi里面 mmc的匹配
sdmmc0: dwmmc@fe2b0000 {
compatible = "rockchip,rk3568-dw-mshc",
"rockchip,rk3288-dw-mshc";
reg = <0x0 0xfe2b0000 0x0 0x4000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
max-frequency = <150000000>;
clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>,
<&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
resets = <&cru SRST_SDMMC0>;
reset-names = "reset";
pinctrl-names = "default";
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
status = "disabled";
};
sdmmc1: dwmmc@fe2c0000 {
compatible = "rockchip,rk3568-dw-mshc",
"rockchip,rk3288-dw-mshc";
reg = <0x0 0xfe2c0000 0x0 0x4000>;
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
max-frequency = <150000000>;
clocks = <&cru HCLK_SDMMC1>, <&cru CLK_SDMMC1>,
<&cru SCLK_SDMMC1_DRV>, <&cru SCLK_SDMMC1_SAMPLE>;
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
resets = <&cru SRST_SDMMC1>;
reset-names = "reset";
status = "disabled";
};
sfc: sfc@fe300000 {
compatible = "rockchip,sfc";
reg = <0x0 0xfe300000 0x0 0x4000>;
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_SFC>, <&cru HCLK_SFC>;
clock-names = "clk_sfc", "hclk_sfc";
assigned-clocks = <&cru SCLK_SFC>;
assigned-clock-rates = <100000000>;
status = "disabled";
};
sdhci: sdhci@fe310000 {
compatible = "rockchip,dwcmshc-sdhci", "snps,dwcmshc-sdhci";
reg = <0x0 0xfe310000 0x0 0x10000>;
max-frequency = <200000000>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>;
assigned-clock-rates = <200000000>, <24000000>;
clocks = <&cru CCLK_EMMC>, <&cru HCLK_EMMC>,
<&cru ACLK_EMMC>, <&cru BCLK_EMMC>,
<&cru TCLK_EMMC>;
clock-names = "core", "bus", "axi", "block", "timer";
status = "disabled";
};
. 读取数据
=> mmc read 0x1000000 0 100
从0块开始读取100个块到内存0x1000000
写入数据
=> mmc write 0x1000000 0 100
从内存0x1000000写入100个块到0块
. 发送原始命令
=> mmc send 0 0
发送CMD0(复位命令)到设备0
=> mmc send 0 1
发送CMD1(发送操作条件)到设备0
. 擦除数据
=> mmc erase 0 100
擦除从0块开始的100个块
. 重新扫描设备
=> mmc rescan
重新检测MMC设备
3, 协议
// 文件:drivers/mmc/mmc.c
static int mmc_send_op_cond_sd(struct mmc *mmc)
{
int err;
struct mmc_cmd cmd = {0};
int i;
for (i = 0; i < 4; i++) {
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
if (mmc->version == SD_VERSION_2)
cmd.cmdarg = 0x40000000; // 支持高容量
else
cmd.cmdarg = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
if (cmd.response[0] & 0x80000000)
break;
udelay(1000);
}
if (i == 4)
return -ETIMEDOUT;
// 检查是否是高容量卡
if (cmd.response[0] & 0x40000000)
mmc->high_capacity = 1;
else
mmc->high_capacity = 0;
return 0;
}
static int mmc_send_op_cond_mmc(struct mmc *mmc)
{
struct mmc_cmd cmd = {0};
int err;
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = OCR_HCS | 0xff8000; // 支持高容量
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
if (cmd.response[0] & 0x80000000) {
if (cmd.response[0] & 0x40000000)
mmc->high_capacity = 1;
else
mmc->high_capacity = 0;
return 0;
}
return -EOPNOTSUPP;
}
// 从CID中提取制造商信息
static void mmc_decode_cid(struct mmc *mmc)
{
u32 *resp = mmc->cid;
// 解析CID寄存器
mmc->cid[0] = resp[0];
mmc->cid[1] = resp[1];
mmc->cid[2] = resp[2];
mmc->cid[3] = resp[3];
// 提取制造商ID
mmc->cid_manfid = (resp[0] >> 24) & 0xFF;
// 提取产品名
mmc->cid_prod_name[0] = (resp[0] >> 16) & 0xFF;
mmc->cid_prod_name[1] = (resp[0] >> 8) & 0xFF;
mmc->cid_prod_name[2] = resp[0] & 0xFF;
mmc->cid_prod_name[3] = (resp[1] >> 24) & 0xFF;
mmc->cid_prod_name[4] = (resp[1] >> 16) & 0xFF;
mmc->cid_prod_name[5] = '\0';
// 打印芯片信息
printf("Manufacturer ID: 0x%02x\n", mmc->cid_manfid);
printf("Product: %s\n", mmc->cid_prod_name);
// 根据制造商ID识别芯片类型
switch (mmc->cid_manfid) {
case 0x02: // SanDisk
printf("Chip: SanDisk\n");
break;
case 0x03: // Toshiba
printf("Chip: Toshiba\n");
break;
case 0x11: // Silicon Motion
printf("Chip: Silicon Motion\n");
break;
case 0x13: // Micron
printf("Chip: Micron\n");
break;
case 0x15: // Samsung
printf("Chip: Samsung\n");
break;
case 0x45: // Sandisk
printf("Chip: SanDisk\n");
break;
case 0x90: // SK Hynix
printf("Chip: SK Hynix\n");
break;
default:
printf("Chip: Unknown (0x%02x)\n", mmc->cid_manfid);
break;
}
}
4,u-boot测试
=> mmc info
Device: sdhci@fe310000
Manufacturer ID: ec
OEM: 2900
Name: AT2S3
Timing Interface: HS200
Tran Speed: 200000000
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 7.2 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 7.2 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
5, 分区设置
=> mmc part
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00004000 0x00005fff "uboot"
attrs: 0x0000000000000000
type: e73b0000-0000-4077-8000-3d7c00004ada
guid: 726d0000-0000-4c5a-8000-5b0d00006a23
2 0x00006000 0x00007fff "misc"
attrs: 0x0000000000000000
type: a40d0000-0000-4206-8000-2a210000761c
guid: 85340000-0000-4c42-8000-55610000443d
3 0x00008000 0x00027fff "boot"
attrs: 0x0000000000000000
type: 5e370000-0000-4248-8000-6eb70000413f
guid: b9740000-0000-4e0c-8000-344a0000401c
4 0x00028000 0x00067fff "recovery"
attrs: 0x0000000000000000
type: 5f240000-0000-4912-8000-6d840000480c
guid: 582a0000-0000-4c3c-8000-2e0e00006b87
5 0x00068000 0x00077fff "backup"
attrs: 0x0000000000000000
type: ed630000-0000-4f1a-8000-30d100000c48
guid: a8770000-0000-4c3c-8000-1df500003748
6 0x00078000 0x00e73fbf "rootfs"
attrs: 0x0000000000000000
type: 51270000-0000-4c7d-8000-62e5000070be
guid: 614e0000-0000-4b53-8000-1d28000054a9
文件路径:
drivers/mmc/rockchip_dw_mmc.c
RK3568 DWMMC控制器驱动
drivers/mmc/rockchip_sdhci.c
RK3568 SDHCI控制器驱动
drivers/mmc/mmc.c
MMC协议核心实现
drivers/mmc/mmc_write.c
MMC读写操作实现
drivers/mmc/dw_mmc.c
DesignWare MMC通用驱动
common/cmd_mmc.c
MMC命令行工具
include/mmc.h
MMC数据结构和定义
arch/arm/dts/rk3568.dtsi
RK3568设备树定义
drivers/mmc/mmc-uclass.c
MMC U-Boot设备模型