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

相关推荐
EnglishJun3 小时前
ARM嵌入式学习(十三)--- IMX6ULL串口
arm开发·学习
CinzWS1 天前
中断向量表中断号与 CMSIS IRQn 映射关系深度剖析:从硬件索引到软件句柄的桥梁
arm开发·架构·系统架构·嵌入式·cortex-m3·中断
FPGA-ADDA2 天前
第一篇:从“软件无线电”到“单芯片无线电”——RFSoC如何重塑无线系统设计
arm开发·信号处理·fpga·通信系统·rfsoc
若风的雨2 天前
【deepseek】ARM TrustZone 架构安全机制
arm开发·安全·架构
Juicedata2 天前
ARM 架构 JuiceFS 性能优化:基于 MLPerf 的实践与调优
arm开发·性能优化·架构
-Try hard-2 天前
ARM | 让蜂鸣器发声!
arm开发
somi72 天前
ARM-07-i.MX6ULL-EPIT定时器和GPT
arm开发·单片机·嵌入式硬件·gpt·定时器·自用·时钟配置
皮皮哎哟2 天前
ARM—点灯(基于正点原子的IMX6U-mini)
arm开发·单片机·嵌入式硬件·imx6ull·点灯·固件库
坤坤藤椒牛肉面2 天前
ARM——General Purpose Timer (GPT)
arm开发·gpt