Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] SDIO signal voltage switch #9732

Open
GuEe-GUI opened this issue Dec 2, 2024 · 9 comments
Open

[Feature] SDIO signal voltage switch #9732

GuEe-GUI opened this issue Dec 2, 2024 · 9 comments

Comments

@GuEe-GUI
Copy link
Contributor

GuEe-GUI commented Dec 2, 2024

Describe problem solved by the proposed feature

在新的主线上已经支持 switch_uhs_voltage ops,但是目前看上去他更像操作 signal voltage switch 的子集,如果让驱动 ops 实现改进如下是否更好:

struct rt_mmcsd_host_ops
{
    void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
    void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
    rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
    void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
    rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
    /* 设置 uhs 模式或者其他场景可能会用到 */
    rt_bool_t (*card_busy)(struct rt_mmcsd_host *host);
    /* 切换电压模式 */
    rt_err_t (*signal_voltage_switch)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
};

参考实现:

rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage)
{
    rt_err_t err = RT_EOK;
    unsigned char old_signal_voltage = host->io_cfg.signal_voltage;

    host->io_cfg.signal_voltage = signal_voltage;
    if (host->ops->signal_voltage_switch)
    {
        err = host->ops->signal_voltage_switch(host, &host->io_cfg);
    }

    if (err)
    {
        host->io_cfg.signal_voltage = old_signal_voltage;
    }

    return err;
}

rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host)
{
    rt_uint32_t old_clock = host->io_cfg.clock;

    host->io_cfg.clock = 0;
    mmcsd_set_iocfg(host);

    if (mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
    {
        return -RT_ERROR;
    }

    /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
    rt_thread_mdelay(10);

    host->io_cfg.clock = old_clock;
    mmcsd_set_iocfg(host);

    return RT_EOK;
}

static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
    mmcsd_power_off(host);

    /* Wait at least 1 ms according to SD spec */
    rt_thread_mdelay(1);

    mmcsd_power_up(host);
    mmcsd_select_voltage(host, ocr);
}

rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
    rt_err_t err = RT_EOK;
    struct rt_mmcsd_cmd cmd;

    if (!host->ops->signal_voltage_switch)
    {
        return -RT_EINVAL;
    }

    if (!host->ops->card_busy)
    {
        LOG_W("%s: Cannot verify signal voltage switch", host->name);
    }

    rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));

    cmd.cmd_code = VOLTAGE_SWITCH;
    cmd.arg = 0;
    cmd.flags = RESP_R1 | CMD_AC;

    err = mmcsd_send_cmd(host, &cmd, 0);
    if (err)
    {
        goto power_cycle;
    }

    if (!controller_is_spi(host) && (cmd.resp[0] & R1_ERROR))
    {
        return -RT_EIO;
    }

    /*
     * The card should drive cmd and dat[0:3] low immediately
     * after the response of cmd11, but wait 1 ms to be sure
     */
    rt_thread_mdelay(1);
    if (host->ops->card_busy && !host->ops->card_busy(host))
    {
        err = -RT_ERROR;
        goto power_cycle;
    }

    if (mmcsd_host_set_uhs_voltage(host))
    {
        /*
         * Voltages may not have been switched, but we've already
         * sent CMD11, so a power cycle is required anyway
         */
        err = -RT_ERROR;
        goto power_cycle;
    }

    /* Wait for at least 1 ms according to spec */
    rt_thread_mdelay(1);

    /*
     * Failure to switch is indicated by the card holding
     * dat[0:3] low
     */
    if (host->ops->card_busy && host->ops->card_busy(host))
    {
        err = -RT_ERROR;
    }

power_cycle:
    if (err)
    {
        LOG_D("%s: Signal voltage switch failed, power cycling card", host->name);
        mmcsd_power_cycle(host, ocr);
    }

    return err;
}

在原先的 mmcsd_power_up 阶段中,还需要对电压做初始化,从高调到低:

void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host)
{
    /* 3.3V -> 1.8v -> 1.2v */
    if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_330))
    {
        LOG_D("Initial signal voltage of %sv", "3.3");
    }
    else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180))
    {
        LOG_D("Initial signal voltage of %sv", "1.8");
    }
    else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_120))
    {
        LOG_D("Initial signal voltage of %sv", "1.2");
    }
}

static void mmcsd_power_up(struct rt_mmcsd_host *host)
{
    [...]
    host->io_cfg.power_mode = MMCSD_POWER_UP;
    host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
    mmcsd_set_iocfg(host);

    mmcsd_set_initial_signal_voltage(host);

    /*
     * This delay should be sufficient to allow the power supply
     * to reach the minimum voltage.
     */
    rt_thread_mdelay(10);
    [...]
}

主要目的还是为了统一一个电压切换接口并且传递更多参数。

Describe your preferred solution

No response

Describe possible alternatives

No response

@GuEe-GUI
Copy link
Contributor Author

GuEe-GUI commented Dec 2, 2024

@helloeagleyang 能否一起讨论一下

@helloeagleyang
Copy link
Contributor

这个新的整理看起来挺合理的,可能存在的风险在于mmcsd_set_signal_voltage 这个实现.我之前实现UHS voltage 这一套的时候本着最小改动的原则,没敢动太多common的部分,您这个可能需要一个PR,然后找几块板子验证下,看看有没有问题,我可以负责验证一下先楫的板子,也可以配合更改驱动中需要适配的card_busy函数等部分。

@GuEe-GUI
Copy link
Contributor Author

GuEe-GUI commented Dec 2, 2024

测试的话,目前在 rockchip dwc mmc 3308/3568/3588 系列使用都正常,后面考虑下树莓派的测试。

@helloeagleyang
Copy link
Contributor

测试的话,目前在 rockchip dwc mmc 3308/3568/3588 系列使用都正常,后面考虑下树莓派的测试。

请问方便建个分支提交下代码么,我想试一下先楫的HPM6800。

GuEe-GUI added a commit to GuEe-GUI/rt-thread that referenced this issue Dec 6, 2024
1. Support features read by DM.
2. Support regulator API in drivers.
3. Support send tuning option CMD.
4. Replace `switch_uhs_voltage` by `signal_voltage_switch`.

Link: RT-Thread#9732

Signed-off-by: GuEe-GUI <[email protected]>
@GuEe-GUI
Copy link
Contributor Author

GuEe-GUI commented Dec 6, 2024

@helloeagleyang 可以说明一下 MMCSD_SUP_ENH_DS 的全称么,DM OFW 解析可能会协助检测 host flags,需要知道这个 flag 的意义

@helloeagleyang
Copy link
Contributor

@helloeagleyang 可以说明一下 MMCSD_SUP_ENH_DS 的全称么,DM OFW 解析可能会协助检测 host flags,需要知道这个 flag 的意义

Enable Enhanced Data Strobe

GuEe-GUI added a commit to GuEe-GUI/rt-thread that referenced this issue Dec 9, 2024
1. Support features read by DM.
2. Support regulator API in drivers.
3. Support send tuning option CMD.
4. Replace `switch_uhs_voltage` by `signal_voltage_switch`.

Link: RT-Thread#9732

Signed-off-by: GuEe-GUI <[email protected]>
@GuEe-GUI
Copy link
Contributor Author

GuEe-GUI commented Dec 9, 2024

做了简单的修改:#9731
@helloeagleyang 添加了 flags 的检测,应该可以测了

GuEe-GUI added a commit to GuEe-GUI/rt-thread that referenced this issue Dec 13, 2024
1. Support features read by DM.
2. Support regulator API in drivers.
3. Support send tuning option CMD.
4. Replace `switch_uhs_voltage` by `signal_voltage_switch`.

Link: RT-Thread#9732

Signed-off-by: GuEe-GUI <[email protected]>
GuEe-GUI added a commit to GuEe-GUI/rt-thread that referenced this issue Dec 16, 2024
1. Support features read by DM.
2. Support regulator API in drivers.
3. Support send tuning option CMD.
4. Replace `switch_uhs_voltage` by `signal_voltage_switch`.

Link: RT-Thread#9732

Signed-off-by: GuEe-GUI <[email protected]>
@GuEe-GUI
Copy link
Contributor Author

@helloeagleyang 大佬能给个反馈么

@helloeagleyang
Copy link
Contributor

@helloeagleyang 大佬能给个反馈么

最近比较忙,暂时还没时间试,等我试完会在这边反馈的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants