emmc总线设置

您所在的位置:网站首页 uv82频率模式调整 emmc总线设置

emmc总线设置

2024-01-17 06:51| 来源: 网络整理| 查看: 265

一、说明 1、设置总线时需要设置的内容 时钟频率  host需要提供给emmc对应的时钟。如上述所说,不同的总线速度模式对应不同的最大时钟频率。  只需要设置host侧即可。总线速度模式的设置  这是host和emmc card通讯的一种时序规范,因此,host和emmc的总线速度模式必须匹配起来才能正常通讯。  需要设置host侧和emmc侧。总线宽度模式的设置  host和emmc通讯的DATA脚数量的定义,同样会影响他们之间的通讯。因此,双方也必须规定一个固定的宽度来进行后续的数据传输。  需要设置host侧和emmc侧。信号电压的设置  也就是IO电压。对于sd card来说,card侧需要知道host提供的信号电压(3.3V或者1.8V)。但是emmc并不需要。  只需要设置host侧即可。 2、emmc支持的总线速度模式

信号电压、时钟频率、总线宽度很大程度上都取决于总线速度模式。以下来看一下他们的关系。  从《emmc 5.1》协议上看,有如下几种总线速度模式

 

总线速度模式说明  legacy mode  单边采样(SDR),支持3V/1.8V/1.2V的信号电压,总线宽度支持1、4、8bit模式。  最大频率支持到26Mhz。  对应kernel中host的MMC_TIMING_LEGACY时序。HS mode  单边采样(SDR),支持3V/1.8V/1.2V的信号电压,总线宽度支持1、4、8bit模式。  最大频率支持到52Mhz  对应kernel中host的MMC_TIMING_MMC_HS时序。HSDDR mode  双边采样(DDR),支持3V/1.8V/1.2V的信号电压,总线宽度支持4、8bit模式。  最大频率支持到52Mhz  对应kernel中host的MMC_TIMING_UHS_DDR50时序。HS200 mode  单边采样(SDR),支持1.8V/1.2V的信号电压,总线宽度支持4、8bit模式。  最大频率支持到200Mhz  对应kernel中host的MMC_TIMING_MMC_HS200时序。HS400 mode  双边采样(DDR),支持1.8V/1.2V的信号电压,总线宽度支持8bit模式。  最大频率支持到200Mhz。  对应kernel中host的MMC_TIMING_MMC_HS400时序。 二、总线参数设置方法 1、时钟频率的设置 各个总线速度模式下的最大时钟频率在协议中已经是固定的了。  在代码中定义如下  

#define MMC_HIGH_26_MAX_DTR 26000000

#define MMC_HIGH_52_MAX_DTR 52000000

#define MMC_HIGH_DDR_MAX_DTR 52000000

#define MMC_HS200_MAX_DTR 200000000

#define MMC_HS400_MAX_DTR 200000000

设置时钟频率方法  mmc core已经提供了接口,mmc_set_clock,直接调用即可。  示例如下 mmc_set_clock(host, MMC_HIGH_52_MAX_DTR); 1 2、总线速度模式的设置 如何获取emmc支持的总线速度模式?  从ext_csd中获取:

 

kernel中定义如下

 

#define EXT_CSD_CARD_TYPE_26 (1

MMC_BUS_WIDTH_8, MMC_BUS_WIDTH_4, MMC_BUS_WIDTH_1

};

unsigned idx, bus_width = 0;

int err = 0;

host = card->host;

if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) || !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))

// 首先判断emmc是否支持,以及host是否支持,只能往4bit或者8bit去设置

goto out;

 

if (host->caps & MMC_CAP_8_BIT_DATA)

idx = 0;

else

idx = 1;

 

for (; idx < ARRAY_SIZE(bus_widths); idx++) { // 先尝试以SDR对应的总线宽度模式去设置,从8bit-》4bit-》1bit的方式去设置

bus_width = bus_widths[idx];

if (bus_width == MMC_BUS_WIDTH_1)

ddr = 0; /* no DDR for 1-bit width */

err = mmc_select_powerclass(card, ext_csd_bits[idx][0], ext_csd);

 

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][0], card->ext_csd.generic_cmd6_time); // 设置emmc总线宽度

if (!err) {

mmc_set_bus_width(host, bus_width); // 设置host的总线宽度

}

}

 

if (!err && ddr) { // 如果是DDR模式,再设置相应的总线宽度为ddr模式

err = mmc_select_powerclass(card, ext_csd_bits[idx][1], ext_csd);

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][1], card->ext_csd.generic_cmd6_time);

// 重新设置emmc的总线宽度模式为ddr模式

}

 

out:

return err;

}

4、信号电压的设置 如何获取emmc支持的信号电压模式?  支持的信号电压模式和总线速度模式是一起定义的。从ext_csd寄存器中读取

 

 

#define EXT_CSD_CARD_TYPE_26 (1

int err = 0;

struct mmc_host *host;

 

host = card->host;

// hs模式:host——》MMC_CAP_MMC_HIGHSPEED

// hs模式:emmc——》EXT_CSD_CARD_TYPE_52

if (!(host->caps & MMC_CAP_MMC_HIGHSPEED) || !(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_52)) {

err = -EOPNOTSUPP;

goto out;

}

 

// 切换emmc的总线速度模式

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1, card->ext_csd.generic_cmd6_time);

 

if (err && err != -EBADMSG)

goto out;

// 切换成功,后续emmc都使用hs模式

mmc_card_set_highspeed(card);

// 切换host的总线速度模式(时序)

mmc_set_timing(host, MMC_TIMING_MMC_HS);

// 设置时钟频率

mmc_set_clock(host, MMC_HIGH_52_MAX_DTR);

// 切换总线宽度

err = mmc_select_bus_width(card, 0, ext_csd);

 

out:

if (err && err != -EOPNOTSUPP)

pr_warning("%s: Switch to HighSpeed mode failed (err:%d)\n",

mmc_hostname(host), err);

return err;

}

注意,并没有为hs模式设置总线信号电压,所以其信号电压还是3V.

3、mmc_select_hsddr

尝试设置总线模式为hsddr模式。

 

static int mmc_select_hsddr(struct mmc_card *card, u8 *ext_csd)

{

int ddr = 0, err = 0;

struct mmc_host *host;

 

host = card->host;

 

if (!(host->caps & MMC_CAP_HSDDR) || // 判断host是否支持hsddr模式

!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_52)) { // 判断emmc是否支持hsddr模式

err = -EOPNOTSUPP;

goto out;

}

 

err = mmc_select_hs(card, ext_csd); // 先尝试设置为hs模式,对于emmc来说,hs_timing的值是一样的,都是EXT_CSD_HS_TIMING

if (err)

goto out;

mmc_card_clr_highspeed(card);

 

if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)

&& ((host->caps & (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50))

== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))

ddr = MMC_1_8V_DDR_MODE; // 判断是否要设置成ddr 1.8V模式

else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)

&& ((host->caps & (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50))

== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))

ddr = MMC_1_2V_DDR_MODE; // 判断是否要设置成ddr 1.2V模式

 

err = mmc_select_bus_width(card, ddr, ext_csd); // 重新设置总线宽度,在这里面选择DDR模式的总线宽度模式

if (err)

goto out;

 

if (host->ios.bus_width == MMC_BUS_WIDTH_1) { // hsddr模式不支持1bit的总线宽度

pr_err("%s: failed to switch to wide bus\n",

mmc_hostname(host));

goto out;

}

 

if (ddr == MMC_1_2V_DDR_MODE) {

err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); // 切换信号电压为1.2V

if (err)

goto out;

}

mmc_card_set_ddr_mode(card);

mmc_set_timing(host, MMC_TIMING_UHS_DDR50); // 设置host的总线速度模式为MMC_TIMING_UHS_DDR50

mmc_set_bus_width(host, host->ios.bus_width); // 设置host的总线宽度,其实在mmc_select_bus_width已经设置过一次了。

 

out:

if (err && err != -EOPNOTSUPP)

pr_warning("%s: Switch to HighSpeed DDR mode failed (err:%d)\n",

mmc_hostname(host), err);

return err;

}

4、mmc_select_hs200

尝试设置总线模式为hs200模式。

 

static int mmc_select_hs200(struct mmc_card *card, u8 *ext_csd)

{

int err = 0;

struct mmc_host *host;

 

host = card->host;

 

if (!(host->caps2 & MMC_CAP2_HS200) || // 判断host是否支持hs200模式

!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS200)) { // 判断emmc是否支持hs200模式

err = -EOPNOTSUPP;

goto out;

}

 

// HS200只支持1.2V或者1.8V的信号电压

if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V && // 判断emmc是否支持hs200_1.2V模式

host->caps2 & MMC_CAP2_HS200_1_2V_SDR) // 判断host是否支持hs200_1.2V模式

if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) // 如果是的话切换信号电压到1.2V

err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); // 否则,切换信号电压到1.8V

// 这里很不能理解,如果不支持1.2V的话,连1.8V的信号电压都不用设置了???

// 根据实际结果来看,确实hs200模式下如果没有设置1.2V的话,确实也就没有设置成1.8V了,而是直接使用3V的信号电压

 

// 注意如下顺序:

/*

* For devices supporting HS200 mode, the bus width has

* to be set before executing the tuning function. If

* set before tuning, then device will respond with CRC

* errors for responses on CMD line. So for HS200 the

* sequence will be

* 1. set bus width 4bit / 8 bit (1 bit not supported) // 先设置总线宽度,hs200不支持1bit的总线宽度

* 2. switch to HS200 mode // 切换emmc和host的总线速度模式为hs200模式

* 3. set the clock to > 52Mhz ops->execute_tuning) { // 进行tuning操作

mmc_host_clk_hold(host);

err = host->ops->execute_tuning(host,

MMC_SEND_TUNING_BLOCK_HS200);

mmc_host_clk_release(host);

}

if (err) {

pr_warning("%s: tuning execution failed\n",

mmc_hostname(host));

goto out;

}

mmc_card_set_hs200(card); // 设置mmc_card状态为MMC_STATE_HIGHSPEED_200

 

out:

if (err && err != -EOPNOTSUPP)

pr_warning("%s: Switch to HS200 mode failed (err:%d)\n",

mmc_hostname(host), err);

return err;

}

5、mmc_select_hs400

尝试设置总线模式为hs400模式。

 

static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)

{

int err = 0;

struct mmc_host *host;

 

host = card->host;

 

if (!(host->caps2 & MMC_CAP2_HS400) || // 判断host是否支持hs400模式

!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400)) { // 判断emmc是否支持hs400模式

err = -EOPNOTSUPP;

goto out;

}

 

// 根据协议emmc 5.0,不能直接切换到hs400模式,而是需要结果如下步骤

/*

* eMMC5.0 spec doesn't allow switching to HS400 mode from

* HS200 mode directly. Hence follow these steps to switch

* to HS400 mode:

* Enable HS200 mode

* Enable HighSpeed mode (The clk should be low enough

* to enable HighSpeed mode) - HS_TIMING is 0x1

* Enable DDR mode (Set bus width to 8-bit DDR)

* Enable HS400 mode (Set HS_TIMING to 0x3 and change

* frequency to ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) // 判断emmc是否支持hs400_1.2v模式

&& (host->caps2 & MMC_CAP2_HS400_1_2V)) // 判断host是否支持hs400_1.2v模式

if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) // 如果是的话切换信号电压到1.2V

err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); // 否则,切换信号电压到1.8V

// 这里的疑问和前面说的一样

 

/*

* Lower the clock and adjust the timing to be able

* to switch to HighSpeed mode

*/

mmc_set_timing(host, MMC_TIMING_LEGACY); // 设置host总线速度模式为legacy模式

mmc_set_clock(host, MMC_HIGH_26_MAX_DTR); // 设置时钟为legacy的最大频率

 

/* Switch to 8-bit HighSpeed DDR mode */

err = mmc_select_hsddr(card, ext_csd); // 设置总线速度模式为hsddr模式

mmc_card_clr_ddr_mode(card);

  

/* Switch to HS400 mode if bus width set successfully */

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,

EXT_CSD_HS_TIMING, 3, 0); // 设置card的总线速度模式为hs400模式

mmc_set_timing(host, MMC_TIMING_MMC_HS400); // 设置host的总线速度模式为hs400模式

mmc_set_clock(host, MMC_HS400_MAX_DTR); // 设置时钟频率

 

if (host->ops->execute_tuning) {

mmc_host_clk_hold(host);

err = host->ops->execute_tuning(host, MMC_SEND_TUNING_BLOCK_HS400); // 执行tuning操作

mmc_host_clk_release(host);

}

mmc_card_set_hs400(card); // 设置mmc_card状态为MMC_STATE_HIGHSPEED_400

 

out:

return err;



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3