MP157 EMMC驱动分析
最近使用原子mp157制作了自己的底板,然后调试板载功能,将之前tftp下载uimage和dtb打包成bootfs并从emmc启动过程中遇到问题,内核启动时会卡在如下位置:
[ 3.411516] stm32f7-i2c 40015000.i2c: doesn't use DMA
[ 3.418630] stm32f7-i2c 40015000.i2c: STM32F7 I2C-2 bus adapter
[ 3.441446] stm32f7-i2c 5c002000.i2c: doesn't use DMA
[ 3.447882] rtc-pcf8563 3-0051: low voltage detected, date/time is not reliable.
[ 3.454259] rtc-pcf8563 3-0051: registered as rtc0
[ 3.460796] stm32f7-i2c 5c002000.i2c: STM32F7 I2C-3 bus adapter
[ 3.466766] mmci-pl18x 48004000.sdmmc: mmc0: PL180 manf 53 rev1 at 0x48004000 irq 45,0 (pio)
[ 3.473874] usb 2-1: new high-speed USB device number 2 using ehci-platform
[ 3.508829] mmci-pl18x 58005000.sdmmc: mmc1: PL180 manf 53 rev2 at 0x58005000 irq 53,0 (pio)
[ 3.523559] mmci-pl18x 48004000.sdmmc: card claims to support voltages below defined range
[ 3.533714] hub 2-1:1.0: USB hub found
[ 3.536189] hub 2-1:1.0: 7 ports detected
[ 3.545627] mmci-pl18x 58007000.sdmmc: mmc2: PL180 manf 53 rev2 at 0x58007000 irq 54,0 (pio)
[ 3.562674] mmc0: new high speed SDIO card at address 0001
[ 3.583575] stm32-ipcc 4c001000.mailbox: ipcc rev:1.0 enabled, 6 chans, proc 0
[ 3.593236] stm32-rproc mlahb:m4@10000000: wdg irq registered
[ 3.599187] remoteproc remoteproc0: m4 is available
[ 3.630641] st,stm32-i2s 4000b000.audio-controller: No cache defaults, reading back from HW
[ 3.641613] st,stm32-spdifrx 4000d000.audio-controller: No cache defaults, reading back from HW
[ 3.659265] panel-simple panel-rgb: panel-rgb supply power not found, using dummy regulator
[ 3.672989] cs42l51 3-004a: Cirrus Logic CS42L51, Revision: 01
[ 3.685561] asoc-audio-graph-card sound: cs42l51-hifi <-> 4400b004.audio-controller mapping ok
[ 3.695037] mmc2: switch to bus width 8 failed
[ 3.705636] mmc2: new high speed MMC card at address 0001
[ 3.710265] asoc-audio-graph-card sound: cs42l51-hifi <-> 4400b024.audio-controller mapping ok
[ 3.719682] mmcblk2: mmc2:0001 8GTF4R 7.28 GiB
[ 3.723411] mmcblk2boot0: mmc2:0001 8GTF4R partition 1 4.00 MiB
[ 3.730598] mmcblk2boot1: mmc2:0001 8GTF4R partition 2 4.00 MiB
[ 3.735992] asoc-audio-graph-card sound: dir-hifi <-> 4000d000.audio-controller mapping ok
[ 3.743505] mmcblk2rpmb: mmc2:0001 8GTF4R partition 3 512 KiB, chardev (242:0)
[ 3.772811] mmcblk2: p1 p2 p3
[ 3.997037] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[ 4.002307] [drm] Driver supports precise vblank timestamp query.
[ 4.009798] [drm] Initialized stm 1.0.0 20170330 for 5a001000.display-controller on minor 0
[ 4.054333] Console: switching to colour frame buffer device 60x34
[ 4.080118] stm32-display 5a001000.display-controller: fb0: stmdrmfb frame buffer device
[ 4.091631] input: gpio-keys as /devices/platform/gpio-keys/input/input1
[ 4.099414] rtc-pcf8563 3-0051: low voltage detected, date/time is not reliable.
[ 4.105781] rtc-pcf8563 3-0051: hctosys: unable to read the hardware clock
[ 4.112843] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[ 4.122749] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[ 4.128129] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[ 4.136440] cfg80211: failed to load regulatory.db
[ 4.142187] ALSA device list:
[ 4.144212] #0: STM32MP1-DK
[ 4.149045] Waiting for root device /dev/mmcblk1p3...
为了解决如上问题打算深入学习分析一下emmc驱动。
核心板的emmc连接如下所示:
可以看到emmc和控制器之间的连接主要有数据线、cmd、CK和reset四类线。主机测和emmc的连接架构示意图如下:
emmc和nand存储器相比封装了一个控制器,用来处理各种内存相关的特性,主机侧只需要通过接口和emmc连接,大大简化的存储设备的驱动流程。
emmc分区介绍:
emmc的分区结构如下:
BOOT Area Partition 1 & 2分区主要是为了支持从 eMMC 启动系统而设计的。该分区的数据,在 eMMC 上电后,可以通过很简单的协议就可以读取出来。同时,大部分的 SOC 都可以通过 GPIO 或者 FUSE 的配置,让 ROM 代码在上电后,将 eMMC BOOT 分区的内容加载到 SOC 内部的 SRAM 中执行。一般boot分区存放的是uboot等bootloader启动程序。
RPMB(Replay Protected Memory Block重放保护内存块)分区是 eMMC/UFS 中的一个具有安全特性的分区。eMMC/UFS在写入数据到 RPMB 时,会校验数据的合法性,只有指定的 Host 才能够写入,同时在读数据时,也提供了签名机制,保证 Host 读取到的数据是 RPMB 内部数据,而不是攻击者伪造的数据。实现上述读写的签名/校验依赖于eMMc或UFS与CPU共享一把Key,用于生成HMAC。此Key由CPU生成,eMMC/UFS只接受一次,无法擦除和替换。即完成了RPMB Key Provision后,CPU和UFS是绑定且匹配的。在实际应用中,RPMB 分区通常用来保存安全相关的数据,例如指纹数据、安全支付相关的密钥等。
General Purpose Partition 1~4此区域则主要用于存储系统或者用户数据。 General Purpose Partition 在芯片出厂时,通常是不存在的,需要主动进行配置后,才会存在。
User Data Area此区域则主要用于存储系统和用户数据。UDA 通常会进行再分区,例如 Android 系统中,通常在此区域分出 boot、system、userdata 等分区。
MP157 dts关于emmc配置
结合arch/arm/boot/dts/下面的stm32mp151.dtsi 、stm32mp157d-atk.dtsi和stm32mp15-pinctrl.dtsi的配置可以看到mp157的emmc信息如下:
sdmmc2_b4_pins_a: sdmmc2-b4-0 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
<STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-push-pull;
bias-pull-up;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-pull-up;
};
};
sdmmc2_b4_od_pins_a: sdmmc2-b4-od-0 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>; /* SDMMC2_D3 */
slew-rate = <1>;
drive-push-pull;
bias-pull-up;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-pull-up;
};
pins3 {
pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-open-drain;
bias-pull-up;
};
};
sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 {
pins {
pinmux = <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
<STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
<STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
};
};
sdmmc2: sdmmc@58007000 {
compatible = "arm,pl18x", "arm,primecell";
arm,primecell-periphid = <0x00253180>;
reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "cmd_irq";
clocks = <&rcc SDMMC2_K>;
clock-names = "apb_pclk";
resets = <&rcc SDMMC2_R>;
cap-sd-highspeed;
cap-mmc-highspeed;
max-frequency = <120000000>;
status = "disabled";
};
&sdmmc2 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc2_b4_pins_a>;
pinctrl-1 = <&sdmmc2_b4_od_pins_a>;
pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>;
non-removable;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
keep-power-in-suspend;
status = "okay";
};