linux设备树-linux内核设备树移植(二)

发布时间:2024-07-10  

----------------------------------------------------------------------------------------------------------------------------

内核版本:linux 5.2.8

根文件系统:busybox 1.25.0

u-boot:2016.05

----------------------------------------------------------------------------------------------------------------------------


回到顶部

一、修改设备树s3c2440.dtsi

s3c2440.dtsi设备树存放的是s3c2440这个SoC跟其他s3c24xx系列不同的一些硬件信息,如clock控制器、串口等等;


修改arch/arm/boot/dts/s3c2440.dtsi文件,将该文件中的2416全部替换成2440,同时移除s3c6410相关的节点,文件内容如下:


 View Code

接着我们需要对该文件进行修改来适配s3c2440。


1.1 修改头文件

修改时钟编号相关宏头文件:


#include

修改为:


#include

1.2 修改根节点compatible 

compatible需要与mach-smdk2440-dt.c文件dt_compat数组数组的compatible匹配,修改为:


model = "Samsung S3C2440 SoC";

compatible = "samsung,s3c2440","samsung,mini2440";

1.3 cpus节点

由于s3c2440内核为arm920t,因此修改cpus为:


cpus {

        cpu {

                compatible = "arm,arm920t";

        };

};

1.4 中断控制器节点

移除s3c2440.dtsi中中断控制器节点,在父级设备树s3c24xx.dtsi文件中定义有:


intc:interrupt-controller@4a000000 {

     compatible = "samsung,s3c2410-irq";

     reg = <0x4a000000 0x100>;

     interrupt-controller;

     #interrupt-cells = <4>;

};

中断控制器节点在上一片博客已经介绍过了,这里不重复介绍了。


关于中断控制器这部分可以参考内核文档:


Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt;

Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml;

Documentation/devicetree/bindings/interrupt-controller/interrupts.txt;

1.4.1 未使用设备树

在内核移植不使用设备树的时候,在arch/arm/mach-s3c24xx/mach-smdk2440.c文件:


MACHINE_START(S3C2440, "SMDK2440")

        /* Maintainer: Ben Dooks */

        .atag_offset    = 0x100,


        .init_irq       = s3c2440_init_irq,

        .map_io         = smdk2440_map_io,

        .init_machine   = smdk2440_machine_init,

        .init_time      = smdk2440_init_time,

MACHINE_END


void __init s3c2440_init_irq(void)

{

        pr_info("S3C2440: IRQ Supportn");


#ifdef CONFIG_FIQ

        init_FIQ(FIQ_START);

#endif


        s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL,    // 初始化32个主中断源相关的中断

                                        0x4a000000);

        if (IS_ERR(s3c_intc[0])) {

                pr_err("irq: could not create main interrupt controllern");

                return;

        }


        s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);      // 初始化外部中断相关的中断、外部中断4~7、8~23分别对应主中断源中的的EINT4~7、EINT8~23

        s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0],         // 初始化带有子中断的内部中断相关的中断

                                        s3c_intc[0], 0x4a000018);

}


这里直接调用s3c24xx_init_intc进行中断控制器初始化,函数位于drivers/irqchip/irq-s3c24xx.c,具体可以参考linux驱动移植-中断子系统执行流程。


1.4.2 使用设备树

在linux内核根路径下搜索samsung,s3c2410-irq:


root@zhengyang:/work/sambashare/linux-5.2.8-dt# grep "samsung,s3c2410-irq" * -nR

drivers/irqchip/irq-s3c24xx.c:1307:IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);

定位到drivers/irqchip/irq-s3c24xx.c文件:


static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {

        {

                .name = "intc",

                .offset = 0,

        }, {

                .name = "subintc",

                .offset = 0x18,

                .parent = &s3c_intc[0],

        }

};


int __init s3c2410_init_intc_of(struct device_node *np,

                        struct device_node *interrupt_parent)

{

        return s3c_init_intc_of(np, interrupt_parent,

                                s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));

}

IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);


IRQCHIP_DECLARE的作用如下所述:用IRQCHIP_DECLARE声明中断控制器驱动,并将其与初始化函数关联。


其中IRQCHIP_DECLARE宏定义在include/linux/irqchip.h中:


#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)

 

#define OF_DECLARE_2(table, name, compat, fn)  

        _OF_DECLARE(table, name, compat, fn, of_init_fn_2)

 

#define _OF_DECLARE(table, name, compat, fn, fn_type)             

    static const struct of_device_id __of_table_##name         

        __used __section(__##table##_of_table)             

         = { .compatible = compat,                 

             .data = (fn == (fn_type)NULL) ? fn : fn  }


展开后,其实就是定义了:


static const struct of_device_id __clk_of_table_s3c2410_irq

__used__section(__irqchip_of_table)

= {

  .compatible = "samsung,s3c2410-irq",

  .data = s3c2410_init_intc_of,

};

定义一个名为__clk_of_table_s3c2410_irq的of_device_id结构体,并将其放置在内核的.__irqchip_of_table节(section)内。 


这样当设备树定义有compatible = "samsung,s3c2410-irq"时,内核匹配到相应的设备时就会直接调用驱动初始化函数s3c2410_init_intc_of了。


 View Code

1.5 时钟控制器节点

s3c2440.dtsi中定义了时钟控制器节点,在内核文档中称之为"Clock providers":


clocks: clock-controller@4c000000 {

        compatible = "samsung,s3c2440-clock";

        reg = <0x4c000000 0x40>;

        #clock-cells = <1>;

};

时钟提供者节点必须有#clock-cells属性,说明该节点是clock provider。它有2种取值:


#clock-cells = <0>,只有一个时钟输出;

#clock-cells = <1>,有多个时钟输出;

设备需要时钟时,它是clock consumer。它描述了使用哪一个clock provider中的哪一个时钟;


每个时钟都分配了一个标识符,设备节点可以使用此标识符来指定它们使用的时钟。其中一些时钟仅在特定的SoC上可用;

所有可用的时钟都定义为预处理器宏并位于dt-bindings/clock/s3c2410.h头文件中,可以在设备树源代码中使用;

比如使用时钟控制器生成的时钟的UART控制器节点:


serial@50004000 {

        compatible = "samsung,s3c2440-uart";

        reg = <0x50004000 0x4000>;

        interrupts = <1 23 3 4>, <1 23 4 4>;

        clock-names = "uart", "clk_uart_baud2";  /* 时钟名,uart、clk_uart_baud2 */

        clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>;  /*  指定uart时钟来自PCLK_UART0; 指定clk_uart_baud2时钟来自PCLK_UART0

                                                       其中PCLK_UART0参考include/dt-bindings/clock/s3c2410.h或者这个clock控制器驱动的实现。 */

};


时钟使用者(clock consumer)的node节点必须有clocks属性,说明该节点是clock consumer。clocks属性由2部分组成:phandle、clock-specifier。


 phandle是@节点名称(例如上个示例中的@clocks);

 clock-specifier怎么理解呢?一个时钟控制器可以控制很多时钟硬件(例如5种基本时钟:fixed-rate、fixed-factor、gate、mux、divider),每种时钟硬件都有对应的ID号。clock-specifier就是这个ID号。例如,s3c2440的时钟硬件编号已经在include/dt-bindings/clock/s3c2410.h中声明了;

clocks-names:用于指定时钟名,调用devm_clk_get获取时钟时,可以传入该名字;比如在s3c24xx_serial_probe中,调用clk_get(&platdev->dev, "uart") 获取时钟;


另外,注意:如果时钟提供者将#clock-cells指定为“0”,则仅会出现该对中的phandle部分。


关于clock这部分可以参考内核文档:


Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt;

Documentation/devicetree/bindings/clock/clock-bindings.txt;

1.5.1 未使用设备树

在内核移植不使用设备树的时候,在arch/arm/mach-s3c24xx/mach-smdk2440.c文件:


MACHINE_START(S3C2440, "SMDK2440")

        /* Maintainer: Ben Dooks */

        .atag_offset    = 0x100,


        .init_irq       = s3c2440_init_irq,

        .map_io         = smdk2440_map_io,

        .init_machine   = smdk2440_machine_init,

        .init_time      = smdk2440_init_time,

MACHINE_END


static void __init smdk2440_init_time(void)

{

        s3c2440_init_clocks(12000000);

        samsung_timer_init();

}


直接调用s3c2440_init_clocks初始化linux内核的时钟,晶振频率为12MHz;


void __init s3c2440_init_clocks(int xtal)

{

        s3c2410_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR);    // 1对应的枚举变量S3C2440

}

这里直接调用s3c2410_common_clk_init进行s3c2440时钟的初始化,具体可以参考linux驱动移植-通用时钟框架子系统。


void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,   // np为NULL、xti_f=12000000、current_soc=1

                                    int current_soc,

                                    void __iomem *base)

{

        ....


        /* Register external clocks only in non-dt cases */

        if (!np)

                s3c2410_common_clk_register_fixed_ext(ctx, xti_f);   // 注册通用的外部固定时钟,即注册晶振


        ...

}


1.5.2 使用设备树

在linux内核根路径下搜索samsung,s3c2440-clock:


root@zhengyang:/work/sambashare/linux-5.2.8-dt# grep "s3c2440-clock" * -nR

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>