linux3.18 内核移植记录(Exynos4412)

时间:2022-04-16 16:34:13

初始化

引入Device Tree之后,MACHINE_START变更为DT_MACHINE_START,其中含有一个.dt_compat成员,用于表明相关的machine与.dts中root结点的compatible属性兼容关系。如果Bootloader传递给内核的Device Tree中root结点的compatible属性出现在某machine的.dt_compat表中,相关的machine就与对应的Device Tree匹配,从而引发这一machine的一系列初始化函数被执行。

arch/arm/mach-exynos/exynos.c:

DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
.l2c_aux_val = 0x3c400001,
.l2c_aux_mask = 0xc20fffff,
.smp = smp_ops(exynos_smp_ops),
.map_io = exynos_init_io,
.init_early = exynos_firmware_init,
.init_irq = exynos_init_irq,
.init_machine = exynos_dt_machine_init,
.init_late = exynos_init_late,
.dt_compat = exynos_dt_compat,
.restart = exynos_restart,
.reserve = exynos_reserve,
.dt_fixup = exynos_dt_fixup,
MACHINE_END

若启动时出现“Starting kernel …“后挂掉,可以打开Kernel low-level debugging functions, 并在启动参数中添加earlyprintk。

emmc驱动

内核已经自带了exynos平台的mmc驱动,位于drivers/mmc/host/dw_mmc-exynos.c中,只需在dts文件中打开相应的配置即可。

mmc@12550000 {
num-slots = <1>;
broken-cd;
non-removable;
card-detect-delay = <200>;
//vmmc-supply = <&vemmc_reg>;
clock-frequency = <100000000>;
max-frequency = <100000000>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>;
samsung,dw-mshc-ddr-timing = <1 2>;
pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus8>;
pinctrl-names = "default";
status = "okay";
bus-width = <8>;
cap-mmc-highspeed;
sd-uhs-ddr50;
mmc-ddr-1_8v;
//slot@0{
// reg=<0>;
// bus-width=<8>;
//};
};

移植过程中出现了有时能启动,有时启动不了的情况,

[    2.946761] sdhci: Secure Digital Host Controller Interface driver
[ 2.952011] sdhci: Copyright(c) Pierre Ossman
[ 2.956787] s3c-sdhci 12530000.sdhci: clock source 2: mmc_busclk.2 (100000000 Hz)
[ 2.964198] s3c-sdhci 12530000.sdhci: No vmmc regulator found
[ 2.969557] s3c-sdhci 12530000.sdhci: No vqmmc regulator found
[ 3.002313] mmc0: SDHCI controller on samsung-hsmmc [12530000.sdhci] using ADMA
[ 3.008362] Synopsys Designware Multimedia Card Interface Driver
[ 3.015085] dwmmc_exynos 12550000.mmc: Using internal DMA controller.
[ 3.020629] dwmmc_exynos 12550000.mmc: Version ID is 240a
[ 3.026287] dwmmc_exynos 12550000.mmc: DW MMC controller at irq 109, 32 bit host data width, 128 deep fifo
[ 3.035673] dwmmc_exynos 12550000.mmc: No vmmc regulator found
[ 3.041431] dwmmc_exynos 12550000.mmc: No vqmmc regulator found
[ 3.077404] dwmmc_exynos 12550000.mmc: 1 slots initialized
[ 3.082601] usbcore: registered new interface driver usbhid
[ 3.086971] usbhid: USB HID core driver
[ 3.091464] TCP: cubic registered
[ 3.094146] NET: Registered protocol family 17
[ 3.098621] NET: Registered protocol family 15
[ 3.103116] Registering SWP/SWPB emulation handler
[ 3.109697] isp-power-domain: Power-off latency exceeded, new value 304833 ns
[ 3.115427] gps-alive-power-domain: Power-off latency exceeded, new value 5793625 ns

然后就一直卡在这里,没有任何反应,而且每次卡的位置也不是完全一样。后来打开CONFIG_MMC_DEBUG后,可以输出错误信息,发现是rootfs没有挂载上;查看init/do_mounts.c后发现可以加rootdelay参数延迟挂载。在uboot的启动参数中加入rootdelay=5后,内核启动的时候在等5秒钟之后再挂载rootfs,这样改了之后虽然启动慢了点,但每次都能顺利启动了。

LCD驱动

3.18内核中自带的framebuffer驱动位于drivers/video/fbdev/s3c-fb.c,但是它不支持device tree,后来在网上找相应的补丁加入了对device tree的支持,然后在dts文件中添加相应的node:

    fimd@11c00000 {
pinctrl-0 = <&lcd_clk &lcd_data24 >;
pinctrl-names = "default";
status = "okay";
samsung,fimd-display = <&lcd_fimd0>;
samsung,fimd-vidout-rgb;
samsung,fimd-frame-rate = <60>;

lcd-gpios = <&gpx2 7 0>,
<&gpk3 2 0 >,
<&gpk3 3 0 >;
gpios=<&gpf0 0 2 >,
<&gpf0 1 2 >,
<&gpf0 2 2 >,
<&gpf0 3 2 >,
<&gpf0 4 2 >,
<&gpf0 5 2 >,
<&gpf0 6 2 >,
<&gpf0 7 2 >,
<&gpf1 0 2 >,
<&gpf1 1 2 >,
<&gpf1 2 2 >,
<&gpf1 3 2 >,
<&gpf1 4 2 >,
<&gpf1 5 2 >,
<&gpf1 6 2 >,
<&gpf1 7 2 >,
<&gpf2 0 2 >,
<&gpf2 1 2 >,
<&gpf2 2 2 >,
<&gpf2 3 2 >,
<&gpf2 4 2 >,
<&gpf2 5 2 >,
<&gpf2 6 2 >,
<&gpf2 7 2 >,
<&gpf3 0 2 >,
<&gpf3 1 2 >,
<&gpf3 2 2 >,
<&gpf3 3 2 >;
window0 {
samsung,fimd-win-id = <0>;
samsung,fimd-win-bpp = <32 24>;
samsung,fimd-win-res = <1024 600>;
samsung,fimd-win-vres = <1024 600>;
};

window1 {
samsung,fimd-win-id = <1>;
samsung,fimd-win-bpp = <32 24>;
samsung,fimd-win-res = <1024 600>;
samsung,fimd-win-vres = <1024 600>;
};
};

lcd_fimd0: lcd_fimd0{
lcd-htiming = <120 120 80 1024>;
lcd-vtiming = <22 10 3 600>;
};

对于其中的gpio资源,在驱动中可以通过调用以下两个函数获取:

of_get_gpio(dev->of_node, idx);
of_get_named_gpio(dev->of_node,"lcd-gpios",idx);

这样启动后出现了”failed to get bus clock”的错误,通过修改exynos4.dtsi中的clock-names解决了,对于clk这一块还没完全搞清楚,

--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -640,7 +640,7 @@
interrupt-names = "fifo", "vsync", "lcd_sys";
interrupts = <11 0>, <11 1>, <11 2>;
clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>;
- clock-names = "sclk_fimd", "fimd";
+ clock-names = "sclk_fimd", "lcd";
samsung,power-domain = <&pd_lcd0>;
samsung,sysreg = <&sys_reg>;
status = "disabled";

改完后重新编译发现屏幕终于亮起来了,但是会闪烁,像是扫描过慢的感觉,然后又加了如下代码修改clock频率:

@@ -1413,6 +1644,22 @@ static int s3c_fb_probe(struct platform_device *pdev)
ret = PTR_ERR(sfb->lcd_clk);
goto err_bus_clk;
}
+ printk("lcd_clk: %d\n",clk_get_rate(sfb->lcd_clk));

+ ret=clk_set_rate(sfb->lcd_clk, 50000000);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_set_rate of sclk for fimd\n");
+ }

i2c驱动

电容触摸屏用到了i2c,把触摸屏驱动改成device tree支持后,再在dts文件中加入i2c的node,

i2c@13860000 {
status = "okay";
samsung,i2c-max-bus-freq = <400000>;
samsung,i2c-sda-delay = <100>;
gsl680@40{
compatible = "gsl680-i2c";
reg=<0x40>;
gsl680-gpios = <&gpx1 5 1>,
<&gpx1 6 0xf>;
};
};

其中gsl680驱动的地址为0x40,用到了两个gpio口,其中一个用于中断,在驱动中通过of_get_named_gpio和gpio_to_irq得到对应的irq号,

static int gsl_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct gsl_ts *ts;
int rc;

struct device_node* np=client->dev.of_node;
gpio_ts_wake= of_get_named_gpio(np,"gsl680-gpios", 0);
irq_gpio= of_get_named_gpio(np,"gsl680-gpios", 1);
irq_port= gpio_to_irq(irq_gpio);

”samsung,i2c-max-bus-freq“指定i2c频率为400K,刚开始没有加“samsung,i2c-sda-delay”,导致了i2c数据读写出错,搞了很久之后才解决这个问题。