rk3568 mmc 驱动之u-boot代码分析

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 dev

switch to partitions #0, OK

mmc0(part 0) is current device
=> 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

插上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设备模型

相关推荐
2401_8628808240 分钟前
ARM 嵌入式开发 ---知识点
arm开发·嵌入式硬件·物联网
AAA代码批发商3 小时前
DAY43 ARM 体系结构学习笔记|嵌入式入门,从硬件组件到流水线、内存与栈帧
arm开发·笔记·学习
女神下凡4 小时前
带NPU的电脑 和不带NPU的电脑 在使用上有什么不样
arm开发·单片机·pcm
T1mzhou18 小时前
ARM64 Linux 6.10 内核驱动(12):dd.c:probe/ remove、延迟 probe
linux·服务器·c语言·arm开发·arm
Doraemomo19 小时前
IMX6ULL裸机开发——系统主频和时钟配置
arm开发·嵌入式硬件·makefile·imx6ull
T1mzhou1 天前
ARM64 平台安全学习记录
linux·服务器·arm开发·arm
云栖梦泽1 天前
网络设备驱动(1)
linux·arm开发·嵌入式硬件
零依赖极客2 天前
Day 9·1 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
c语言·开发语言·arm开发·人工智能·缓存·矩阵
secondyoung3 天前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
奔跑的架构师3 天前
[A-50]ARMv9/v8-DVFS系统架构
linux·arm开发·架构·系统架构·arm