初始化

引入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数据读写出错,搞了很久之后才解决这个问题。

Logo

更多推荐