ILD

port latest linux 6.6 to mediatek mt7981b soc from scratch, part 2
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2024-10-25 站点:Inside Linux Development

上篇part 1https://linuxdev.cc/article/a0gtfe.html ,本篇继续进行内核的导入,争取可以看到内核启动日志。


1 Fix boot error: Synchronous Abort

part1完成了fit image的编译和启动测试,发现出现了Synchronous Abort。从打印中可以得到出异常的指令为0000005d。

Code: 49840010 600a4908 14501415 002b0122 (0000005d)


先hexudmp Image.lzma看看异常指令在哪里:

$ hexdump -n 100 -X Image.lzma
0000000  5d  00  00  00  04  ff  ff  ff  ff  ff  ff  ff  ff  00  0f  88
0000010  c2  80  c7  c1  2b  b6  82  60  d4  a7  35  f5  13  8c  d0  23
0000020  67  16  37  36  b8  5f  3a  e2  c2  a5  4d  fb  99  fc  9b  61
0000030  aa  aa  5b  42  e0  0e  66  64  13  2f  ea  10  bf  2f  f5  bf
0000040  03  ce  34  7b  49  23  e1  5b  41  27  f6  95  09  85  16  d0
0000050  f5  4d  b8  6c  9b  1b  68  cb  20  bd  4d  f0  bd  1c  18  b9
0000060  2e  e1  5d  9e                                                
0000064


$ file Image
Image: Linux kernel ARM64 boot executable Image, little-endian, 4K pages


小端系统,5d在前,所以一条指令就出错了。这就很明显了,Image.lzma不是一个自解压的可执行镜像。


使用file看看:

$ file Image.lzma
Image.lzma: LZMA compressed data, streamed


可见Image.lzma是一个纯压缩文件,所以没办法直接执行,需要uboot进行解压,因此我们将fit.its中的compression修改成lzma:

compression = "lzma";


重新用编译后,用uboot启动,异常消失。但是串口没任何输出。


2 没有走到start_kernel()

通过直接读写寄存器,亮灯和写uart的方式调试,发现卡在汇编代码里,经过漫长的调试和对比,发现是一个ARM选项没开:

CONFIG_ARM64_ERRATUM_843419=y


开启后,貌似启动到start_kernel() c代码了,但是仍然串口仍然没有任何输出。


3 Enable console

先开启SOC基本配置:

Platform Selection -> MediaTek SoC Family

开启 CONFIG_ARCH_MEDIATEK

会对应开启 ARM_GIC/PINCTRL/MTK_TIMER 这3个配置,这3个选项又会select很多选项。

它会把MTK其它SOC的相关选项也选上,如下:

+CONFIG_PINCTRL_MT6765=y
+CONFIG_PINCTRL_MT6779=y
+CONFIG_PINCTRL_MT6795=y
+CONFIG_PINCTRL_MT6797=y
+CONFIG_PINCTRL_MT7622=y
+CONFIG_PINCTRL_MT7981=y
+CONFIG_PINCTRL_MT7986=y

去掉非MT7981的。


开启tty

Device Drivers > Character devices -> [*] Enable TTY

开启对应驱动

Serial drivers  --->


怎么知道是哪个驱动呢,查看device tree

206                 uart0: serial@11002000 {
207                         compatible = "mediatek,mt6577-uart";


然后去驱动目录drivers/tty/serial搜索:

$ grep -nr "mediatek,mt6577-uart" .
./8250/8250_mtk.c:643:    { .compatible = "mediatek,mt6577-uart" },


查看8250/Makefile,是哪个配置对应

obj-$(CONFIG_SERIAL_8250_MT6577)        += 8250_mtk.o


因此开启CONFIG_SERIAL_8250_MT6577配置即可,


开启TTY后,会select INPUT,又对应会看其Keyboards/Mice等,需要手动关闭


最后还要开启 printk支持

General setup > Configure standard kernel features (expert users) -> [*]   Enable support for printk

 

上述编译后,启动还是没有输出,

还需要开启CONFIG_SERIAL_8250_CONSOLE,这个选项是将8250作为system console。

虽然开启了,但是内核默认还是使用虚拟console /dev/tty0。需要使用内核命令行选项,例如console=ttyS1来传递。

很遗憾,还是没有任何输出


4 Fix no boot message on console

上面进行了开启配置的尝试,但是串口仍然没有任何启动日志。


首先添加自己的调试函数,直接读写寄存器的方式,输出到串口,见:

read/write device register at kernel boot stage

https://linuxdev.cc/article/a0hsch.html


然后添加调试,发现是串口驱动的probe函数mtk8250_probe()没有被调用,在正常的内核中添加栈打印,如下:

[    0.861741]  dump_backtrace+0x9c/0xd8
[    0.865401]  show_stack+0x14/0x1c
[    0.868708]  dump_stack_lvl+0x44/0x58
[    0.872365]  dump_stack+0x14/0x1c
[    0.875672]  register_console+0x208/0x484
[    0.879672]  serial_core_register_port+0x6e8/0x724
[    0.884456]  serial_ctrl_register_port+0xc/0x14
[    0.888975]  uart_add_one_port+0xc/0x14
[    0.892800]  serial8250_register_8250_port+0x2e0/0x480
[    0.897926]  mtk8250_probe+0x16c/0x24c
[    0.901666]  platform_probe+0x64/0xbc
[    0.905321]  really_probe+0x140/0x2a8
[    0.908972]  __driver_probe_device+0x74/0x124
[    0.913318]  driver_probe_device+0x3c/0x110
[    0.917491]  __driver_attach+0x88/0x18c
[    0.921316]  bus_for_each_dev+0x60/0xa0
[    0.925145]  driver_attach+0x20/0x28
[    0.928710]  bus_add_driver+0xe0/0x1ec
[    0.932448]  driver_register+0x58/0x114
[    0.936273]  __platform_driver_register+0x24/0x2c
[    0.940967]  mtk8250_platform_driver_init+0x18/0x20
[    0.945837]  do_one_initcall+0x68/0x1e8
[    0.949662]  kernel_init_freeable+0x200/0x2d8
[    0.954012]  kernel_init+0x20/0x1cc
[    0.957490]  ret_from_fork+0x10/0x20


接着,就是慢慢添加调试,找到问题原因:

1 定位到依赖的驱动10001000.clock-controller没ok,导致内核基础模块返回EPROBE_DEFER。

init mtk8250_platform_driver_init+0x0/0x20
=== __platform_driver_register mt6577-uart
=== mt6577-uart driver_register
supplier 10001000.clock-controller not ready
device_links_check_suppliers failed
=== mt6577-uart probe -517
=== mt6577-uart defer


2 再看10001000.clock-controller模块的驱动,它注册失败了,失败的原因是:

mtk_clk_register_muxes()->device_node_to_regmap()

调用device_node_to_regmap()失败了。

看了下,是CONFIG_MFD_SYSCON配置项没打开,打开后,正常了。


init clk_mt7981_infracfg_drv_init+0x0/0x20
=== __platform_driver_register clk-mt7981-infracfg
=== clk-mt7981-infracfg driver_register
Cannot find regmap for /soc/clock-controller@10001000: -524
=== mtk_clk_register_muxes failed
call_driver_probe failed


int mtk_clk_register_muxes(struct device *dev,
                           const struct mtk_mux *muxes,
                           int num, struct device_node *node,
                           spinlock_t *lock,
                           struct clk_hw_onecell_data *clk_data)
{
        struct regmap *regmap;
        struct clk_hw *hw;
        int i;

        regmap = device_node_to_regmap(node);
        if (IS_ERR(regmap)) {
                char buf[128];
                pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
                sprintf(buf, "Cannot find regmap for %pOF: %pe\n", node, regmap);
                myputs(buf);
                return PTR_ERR(regmap);
        } 



串口ok了:


Starting kernel ...

Booting Linux on physical CPU 0x0000000000 [0x410fd034]
Linux version 6.6.31+ (yuanjp@fedora) (aarch64-linux-gnu-gcc (crosstool-NG 1.26.0) 13.2.0, GNU ld (crosstool-NG 1.26.0) 2.40) #1 SMP Fri Oct 25 23:34:40 CST 2024
Machine model: Xiaomi Mi Router WR30U (stock layout)
OF: reserved mem: 0x0000000042ff0000..0x0000000042ffffff (64 KiB) map non-reusable ramoops@42ff0000
OF: reserved mem: 0x0000000043000000..0x000000004302ffff (192 KiB) nomap non-reusable secmon@43000000
OF: reserved mem: 0x0000000047c80000..0x0000000047d7ffff (1024 KiB) nomap non-reusable wmcpu-reserved@47c80000
OF: reserved mem: 0x0000000047d80000..0x0000000047dbffff (256 KiB) nomap non-reusable wo-emi@47d80000
OF: reserved mem: 0x0000000047dc0000..0x0000000047ffffff (2304 KiB) nomap non-reusable wo-data@47dc0000

参考

[1] Linux Kernel Tinification,https://tiny.wiki.kernel.org/

[2] Linux tinyconfig and Qemu,https://z49x2vmq.github.io/2020/12/24/linux-tiny-qemu/

[3] Building a tiny linux kernel,https://weeraman.com/building-a-tiny-linux-kernel/



Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.