4. VIVO-Y927 Linux 内核设备树完善(eMMC-SD卡-屏幕驱动) | 字数总计: 2.8k | 阅读时长: 14分钟 | 阅读量: |
第2阶段:启用eMMC/SD卡设备
目标
上一章节只有 initramfs 的临时文件系统(RAM),断电就没了。手机有 16GB 的 eMMC 芯片焊在主板上,我们需要内核识别它,为后续挂载持久化 rootfs 做准备。
DTS 改动分析
需要写多少 DTS?
答案:两行 。
1 2 &sdhc_1 { status = "okay" ; }; &sdhc_2 { status = "okay" ; };
不需要写 GPIO、不需要写 pinctrl、不需要写寄存器地址。原因和阶段0的骨架 DTS 一样——这一切早在 msm8916.dtsi 和 msm8916-pm8916.dtsi 里定义好了。
msm8916.dtsi(SoC 级)第 2170-2190 行为 sdhc_1 写了:
属性
值
含义
reg
0x07824900 / 0x07824000
eMMC 控制器寄存器物理地址
interrupts
GIC_SPI 123 / GIC_SPI 138
中断线
clocks
GCC_SDCC1_*
eMMC 专用时钟
pinctrl-0
sdc1_default
引脚配置(sdc1_clk/sdc1_cmd/sdc1_data,专用 SDC 功能引脚,在 msm8916.dtsi 第 1466-1500 行定义)
bus-width
8
8 位数据总线
non-removable
标记不可插拔(焊死的)
status
"disabled"
← 板级 DTS 唯一要改的
msm8916-pm8916.dtsi(PMIC 级)第 37-40 行给 sdhc_1 配好了供电:
1 2 3 4 &sdhc_1 { vmmc-supply = <&pm8916_l8 > ; vqmmc-supply = <&pm8916_l5 > ; };
SD 卡(sdhc_2)同理——SoC dtsi 已定义 4 位总线 + pinctrl,PMIC dtsi 已配好 pm8916_l11/pm8916_l12 供电。唯一多出来的板级信息是 card detect GPIO (SD 卡槽的物理检测脚),这个确实是板子决定的:
1 2 3 4 &sdhc_2 { status = "okay" ; cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW> ; };
msm8916-mtp.dts 参考板也配了 cd-gpios = <&tlmm 38 ...>,Y927 复用了同样的 GPIO。
DTS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 /dts-v1/ ; #include "msm8916-pm8916.dtsi" #include <dt-bindings/gpio/gpio.h> / { model = "vivo Y927 (PD1410V)" ; compatible = "vivo,y927" , "qcom,msm8916" ; chassis-type = "handset" ; aliases { mmc0 = &sdhc_1 ; mmc1 = &sdhc_2 ; }; usb_id: usb-id { compatible = "linux,extcon-usb-gpio" ; id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH> ; pinctrl-names = "default" ; pinctrl-0 = <&usb_id_default > ; }; }; &usb { dr_mode = "peripheral" ; extcon = <&usb_id > , <&usb_id > ; status = "okay" ; }; &usb_hs_phy { extcon = <&usb_id > ; status = "okay" ; }; &tlmm { usb_id_default: usb-id-default { pins = "gpio110" ; function = "gpio" ; drive-strength = <8 > ; bias-pull-up ; }; }; &sdhc_1 { status = "okay" ; }; &sdhc_2 { status = "okay" ; cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW> ; };
内核配置
不需要改动。msm8916_defconfig 已包含:
1 2 3 4 CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y # MSM8916 的 SDHC 控制器驱动
initramfs
沿用第1阶段的 initramfs(USB serial 交互 shell),无需修改。第2阶段只是在 DTS 中启用了 eMMC/SD 控制器,内核启动后 /dev/mmcblk0* 会自然出现,不需要 init 脚本做任何事。
编译 Linux 内核
1 2 cd ~/y927/linuxmake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) Image.gz dtbs
构建 boot.img 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cd ~/y927/linuxcat arch /arm64/boot/Image.gz \ arch /arm64/boot/dts/qcom/msm8916-vivo-y927.dtb \ > vmlinuz-dtb ~/y927/lk2nd/lk2nd/scripts/mkbootimg \ --kernel vmlinuz-dtb \ --ramdisk $HOME /y927/initramfs/initramfs-phase-1.cpio.gz \ --cmdline "console=ttyGS0,115200 panic=1" \ --base 0x80000000 \ --kernel_offset 0x00008000 \ --ramdisk_offset 0x01000000 \ --second_offset 0x00f00000 \ --tags_offset 0x00000100 \ --pagesize 2048 \ --header_version 0 \ --output boot-phase2.img
刷入 boot.img 文件
1 2 fastboot flash boot boot-phase2.img fastboot reboot
测试
1 sudo picocom -b 115200 /dev/ttyACM0
输入busybox fdisk -l可以识别到16GB eMMC和8GB SD卡了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Disk /dev/mmcblk0: 14.5G, 15634268160 bytes, 30535680 sectors 1893 cylinders, 256 heads, 63 sectors/track Units: cylinders of 16128 * 512 = 8257536 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk0p1 0,0,1 1023,255,63 1 4294967295 4294967295 2047G ee EFI GPT Disk /dev/mmcblk1: 7619M, 7989100544 bytes, 15603712 sectors 3504 cylinders, 73 heads, 61 sectors/track Units: cylinders of 4453 * 512 = 2279936 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 0,130,3 971,72,61 8192 15603711 15595520 7615M b Win95 FAT32 Disk /dev/mmcblk0boot0: 4096K, 4194304 bytes, 8192 sectors 128 cylinders, 4 heads, 16 sectors/track Units: cylinders of 64 * 512 = 32768 bytes Disk /dev/mmcblk0boot0 doesn't contain a valid partition table Disk /dev/mmcblk0boot1: 4096K, 4194304 bytes, 8192 sectors 128 cylinders, 4 heads, 16 sectors/track Units: cylinders of 64 * 512 = 32768 bytes Disk /dev/mmcblk0boot1 doesn' t contain a valid partition table
第3阶段:真正的DRM显示(HX8394A 面板驱动移植)
目标
在lk1st的移植过程中,已经用lmdpdg.py工具反编译生成了完整的 Linux DRM panel 驱动,驱动源码在
~/y927/linux-mdss-dsi-panel-driver-generator/workdir/dtb/plat_ce-var_1-sub_0/hx8394a_720p_video
这一阶段将这一驱动移植到主线 Linux 内核中。
内核驱动移植
复制驱动源码
1 2 cp ~/y927/linux-mdss-dsi-panel-driver-generator/workdir/dtb/plat_ce-var_1-sub_0/hx8394a_720p_video/panel-hx8394a.c \ ~/y927/linux/drivers/gpu/drm/panel/msm8916-generated/panel-vivo-y927-hx8394a.c
修改驱动 compatible 字符串
lmdpdg 生成的 .c 文件用的是下游 compatible "mdss,hx8394a",需要改成与 DTS 一致的 "vivo,y927-hx8394a",否则 panel 永远不 probe,dmesg 里看不到任何 panel/dsi/backlight 字样。
1 2 sed -i 's|"mdss,hx8394a"|"vivo,y927-hx8394a"|' \ ~/y927/linux/drivers/gpu/drm/panel/msm8916-generated/panel-vivo-y927-hx8394a.c
对应源码改动(约 238 行):
1 2 3 4 static const struct of_device_id hx8394a_of_match [] = { { .compatible = "vivo,y927-hx8394a" }, { } };
注册到 Kconfig / Makefile
drivers/gpu/drm/panel/msm8916-generated/Kconfig:
1 2 3 config DRM_PANEL_VIVO_Y927_HX8394A tristate "vivo Y927 HX8394A" default DRM_PANEL_MSM8916_GENERATED
drivers/gpu/drm/panel/msm8916-generated/Makefile:
1 obj-$(CONFIG_DRM_PANEL_VIVO_Y927_HX8394A) += panel-vivo-y927-hx8394a.o
内核配置
1 2 3 4 5 6 7 8 9 sudo apt install -y libncurses-devcd ~/y927/linuxmake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
等价于直接编辑.config文件,添加以下内容:
1 2 3 CONFIG_DRM_PANEL_VIVO_Y927_HX8394A=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_GPIO=y
或者是使用./scripts/config命令:
1 2 3 4 5 6 7 8 9 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- msm8916_defconfig ./scripts/config --enable DRM_PANEL_VIVO_Y927_HX8394A ./scripts/config --enable BACKLIGHT_CLASS_DEVICE ./scripts/config --enable BACKLIGHT_GPIO ./scripts/config --enable CONFIG_REGULATOR_FIXED_VOLTAGE ./scripts/config --enable DRM_MSM ./scripts/config --enable USB_G_SERIAL ./scripts/config --enable U_SERIAL_CONSOLE make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig
⚠️ CONFIG_BACKLIGHT_GPIO=y 不能漏。缺了它 panel 驱动里 drm_panel_of_backlight() 永远返回 -EPROBE_DEFER,并且 dev_err_probe 不打印 EPROBE_DEFER —— 整条 DSI 链路会"静默卡死",dmesg 里看不到任何 panel/dsi/backlight 字样,看起来像是什么都没发生。
⚠️ olddefconfig 必须带 ARCH=arm64 。不带 ARCH 跑会按 x86 树读 Kconfig,新加的 ARM 平台 symbol 不会被识别,编 Image.gz 时 kbuild 会反复弹"Restart config…"交互问每个未识别项。
DTS 完善
lmdpdg 生成的 panel-hx8394a.dtsi 模板内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 &mdss_dsi0 { panel@0 { compatible = "mdss,hx8394a" ; reg = <0 > ; backlight = <&backlight > ; reset-gpios = <&tlmm XY GPIO_ACTIVE_LOW> ; port { panel_in: endpoint { remote-endpoint = <&mdss_dsi0_out > ; }; }; }; }; &mdss_dsi0_out { data-lanes = <0 1 2 3 > ; remote-endpoint = <&panel_in > ; };
最后的 DTS 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 /dts-v1/ ; #include "msm8916-pm8916.dtsi" #include <dt-bindings/gpio/gpio.h> / { model = "vivo Y927 (PD1410V)" ; compatible = "vivo,y927" , "qcom,msm8916" ; chassis-type = "handset" ; aliases { mmc0 = &sdhc_1 ; mmc1 = &sdhc_2 ; }; usb_id: usb-id { compatible = "linux,extcon-usb-gpio" ; id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH> ; pinctrl-names = "default" ; pinctrl-0 = <&usb_id_default > ; }; backlight: backlight { compatible = "gpio-backlight" ; gpios = <&tlmm 8 GPIO_ACTIVE_HIGH> ; default-on ; }; reg_lcd_enp: regulator-lcd-enp { compatible = "regulator-fixed" ; regulator-name = "lcd_enp" ; gpio = <&tlmm 97 GPIO_ACTIVE_HIGH> ; enable-active-high ; regulator-always-on ; regulator-boot-on ; }; reg_lcd_enn: regulator-lcd-enn { compatible = "regulator-fixed" ; regulator-name = "lcd_enn" ; gpio = <&tlmm 98 GPIO_ACTIVE_HIGH> ; enable-active-high ; regulator-always-on ; regulator-boot-on ; }; reserved-memory { cont-splash@83200000 { reg = <0 0x83200000 0 0x800000 > ; no-map ; }; }; }; &usb { dr_mode = "peripheral" ; extcon = <&usb_id > , <&usb_id > ; status = "okay" ; }; &usb_hs_phy { extcon = <&usb_id > ; status = "okay" ; }; &tlmm { usb_id_default: usb-id-default { pins = "gpio110" ; function = "gpio" ; drive-strength = <8 > ; bias-pull-up ; }; mdss_default: mdss-default-state { pins = "gpio25" ; function = "gpio" ; drive-strength = <8 > ; bias-disable ; }; mdss_sleep: mdss-sleep-state { pins = "gpio25" ; function = "gpio" ; drive-strength = <2 > ; bias-pull-down ; }; }; &sdhc_1 { status = "okay" ; }; &sdhc_2 { status = "okay" ; cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW> ; }; &mdss { status = "okay" ; }; &mdss_dsi0 { pinctrl-names = "default" , "sleep" ; pinctrl-0 = <&mdss_default > ; pinctrl-1 = <&mdss_sleep > ; status = "okay" ; panel@0 { compatible = "vivo,y927-hx8394a" ; reg = <0 > ; reset-gpios = <&tlmm 25 GPIO_ACTIVE_LOW> ; backlight = <&backlight > ; vsp-supply = <®_lcd_enp > ; vsn-supply = <®_lcd_enn > ; port { panel_in: endpoint { remote-endpoint = <&mdss_dsi0_out > ; }; }; }; }; &mdss_dsi0_out { data-lanes = <0 1 2 3 > ; remote-endpoint = <&panel_in > ; };
⚠️ 不要把 data-lanes 放在 panel 的 endpoint 里 ,也不要 省略 &mdss_dsi0_out { remote-endpoint = <&panel_in>; }。DSI host 在 dsi_bind() 里通过 devm_drm_of_get_bridge(np, port=1, ep=0) 沿自己的 port@1 endpoint 找下游 panel —— host 这一侧少了 remote-endpoint 会让 component_bind 返回 -ENODEV,dmesg 里出现:
1 2 msm_mdp 1a01000.display-controller: failed to bind 1a98000.dsi (-19) panel-hx8394a 1a98000.dsi.0: error -ENODEV: Failed to attach to DSI host
dmesg 里启动早期会有几行 Fixed dependency cycle(s) with /soc@0/display-subsystem@1a00000/dsi@1a98000 —— 这只是 driver_deferred_probe 的常规告警,所有 msm8916 mainline 设备都有这一行,不是循环依赖问题 。社区参考写法见 arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts。
GPIO 对照(引自 lk2nd DTS msm8916-vivo-y927.dts lk1st 移植时已验证的实机配置):
GPIO
功能
方向
lk2nd 中的写法
8
背光 enable
输出高有效
regulator-backlight { gpios = <&tlmm 8 ...>; }
25
面板 reset
输出低有效
(lk2nd 由 panel driver 内部管理)
97
VSP 正偏压
输出高有效
regulator-lcd-enp { gpios = <&tlmm 97 ...>; }
98
VSN 负偏压
输出高有效
regulator-lcd-enn { gpios = <&tlmm 98 ...>; }
initramfs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 BUSYBOX_BINARY=~/y927/busybox-1.38.0/busybox cd ~/y927/initramfsrm -rf phase-3mkdir -p phase-3 && cd phase-3mkdir -p bin dev proc sys lib/modulescp $BUSYBOX_BINARY bin/cd binfor cmd in sh mount ls cat sleep exec echo ; do ln -sf busybox $cmd done cd ..cat > init << 'EOF' mount -t proc proc /proc mount -t sysfs sys /sys mount -t devtmpfs dev /dev echo "===== Phase 1: kernel booted! =====" echo "Serial: $(cat /proc/cmdline) " sleep 5exec sh </dev/ttyGS0 >/dev/ttyGS0 2>&1EOF chmod +x initfind . | cpio -o -H newc | gzip > ../initramfs-phase-3.cpio.gz
编译 Linux 内核
1 2 cd ~/y927/linuxmake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) Image.gz dtbs
构建 boot.img 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cd ~/y927/linuxcat arch /arm64/boot/Image.gz \ arch /arm64/boot/dts/qcom/msm8916-vivo-y927.dtb \ > vmlinuz-dtb ~/y927/lk2nd/lk2nd/scripts/mkbootimg \ --kernel vmlinuz-dtb \ --ramdisk $HOME /y927/initramfs/initramfs-phase-3.cpio.gz \ --cmdline "console=tty0 console=ttyMSM0,115200 panic=1 initcall_blacklist=simpledrm_platform_driver_init" \ --base 0x80000000 \ --kernel_offset 0x00008000 \ --ramdisk_offset 0x01000000 \ --second_offset 0x00f00000 \ --tags_offset 0x00000100 \ --pagesize 2048 \ --header_version 0 \ --output boot-phase3.img
⚠️ cmdline 必须含 console=tty0,否则屏幕亮但内核 console 不往 fbdev 写,启动时屏上一片空白。initcall_blacklist=simpledrm_platform_driver_init 阻止 simpledrm 抢先绑定 framebuffer,让 MSM DRM 接管。
刷入 boot.img 文件
1 2 fastboot flash boot boot-phase3.img fastboot reboot
测试
2026-06-14 01:50 屏幕亮起,console 正常滚动内核日志。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ~ [ 0.000000] Kernel command line: console=tty0 console=ttyMSM0,115200 panic=1 initcall_blacklist=simpledrm_platform_driver_init [ 0.000000] blacklisting initcall simpledrm_platform_driver_init [ 0.000230] printk: legacy console [tty0] enabled [ 0.367747] msm_mdp 1a01000.display-controller: bound 1a98000.dsi (ops 0xffff800080c19a38) [ 0.370379] msm_mdp 1a01000.display-controller: [drm:mdp5_kms_init] MDP5 version v1.6 [ 0.406922] [drm] Initialized msm 1.13.0 for 1a01000.display-controller on minor 0 [ 0.690698] [drm:mdp5_irq_error_handler] *ERROR* errors: 04000000 ← 仅一次,初始 modeset 正常 [ 0.746648] Console: switching to colour frame buffer device 90x80 ← fbcon 接管屏幕 [ 0.826530] msm_mdp 1a01000.display-controller: [drm] fb0: msmdrmfb frame buffer device ~ connected ~ enabled ~ 720x1280 ~ 0 msmdrmfb