Linux内核注册板级硬件信息的过程简述。

本文根据网上资料理解、汇总、整理得到。

1.首先定义某个硬件(以mt6622蓝牙芯片为例)的资源结构体。

static struct mt6622_platform_data mt6622_platdata = {

.power_gpio         =

{

         .io             = RK30_PIN3_PC7,

         .enable         = GPIO_HIGH,

         .iomux          = {

             .name       = NULL,

         },

},

.reset_gpio         =

{

        .io             = RK30_PIN3_PD1,

        .enable         = GPIO_LOW,

        .iomux          = {

            .name       = NULL,

        },

    },

.irq_gpio           =

{

        .io             = RK30_PIN6_PA7,

        .enable         = GPIO_HIGH,

        .iomux          = {

             .name       = NULL,

       },

    }

};

2.将上一步的资源结构体作为platform设备的私有数据,这里是赋值给了platform_device结构体内部的struct device dev,还有一种做法(应该更常见)是把硬件资源信息赋于platform_device结构体内部的struct resource * resource指针变量。

static struct platform_device device_mt6622 = {

    .name   = "mt6622",

    .id     = -1,

    .dev    = {

        .platform_data = &mt6622_platdata,

    },

};

3.用上一步的platform设备结构体填充platform结构体数组以备统一注册。

static struct platform_device *devices[] __initdata = {

&rk29_device_backlight,

&device_fb,

&device_ion,

&rk29_device_vibrator,

&rk29_device_gpio_leds,

&irda_device,

&rk29sdk_wifi_device,

&rk30_device_modem,

&rk29_device_mu509,

&rk29_device_mw100,

&rk29_device_mt6229,

&rk30_device_sew868,

&rk30_device_adc_battery,

&device_rfkill_rk,

&device_mt6622,

&pwm_regulator_device[0],

};

 

4.在板级初始化函数中统一注册platform device结构体,rk30是SOC的名字。

static void __init  machine_rk30_board_init(void)

{

.........................

//板级相关的硬件资源信息都在这里注册。

//申请电源启动引脚,如果被占用会申请失败

gpio_request(POWER_ON_PIN, "poweronpin"); 

//设置电源引脚为输出引脚

gpio_direction_output(POWER_ON_PIN, GPIO_HIGH);

//给电源管理的系统关闭函数赋函数指针

pm_power_off = rk30_pm_power_off;

//注册I2C的板级信息

rk30_i2c_register_board_info();

//注册SPI的板级信息

spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices));

//注册platform的板级信息

platform_add_devices(devices, ARRAY_SIZE(devices));

//初始化USB的检测引脚

board_usb_detect_init(RK30_PIN6_PA3);

......

}

 

5.板级设备函数machine_rk30_board_init( )被赋值给struct  machine_desc的变量,以备在板子启动时候调用该注册函数。

在arch\arm\下的mach或plat开头的文件和文件夹中。

MACHINE_START(RK30, "RK30board")

        .boot_params = PLAT_PHYS_OFFSET + 0x800,

        .fixup = rk30_fixup,

        .reserve = &rk30_reserve,

        .map_io = rk30_map_io,

        .init_irq = rk30_init_irq,

        .timer = &rk30_timer,

        .init_machine = machine_rk30_board_init,//不同电路板用不同函数名标识

MACHINE_END

       其中MACHINE_START、MACHINE_END都是定义的宏,两个宏一起定义了一个类型为struct machine_desc的变量。由宏定义可知struct machine_desc被放置在__section__(".arch.info.init")段。

其中的nr值很关键,它会与bootloader传来的nr做匹配,来获取具体特定板级(即为什么是rk30,而不是rk40 ) 相关硬件资源描述信息。

 

接下来看内核启动过程中是如何注册特定板级的信息,注册的过程也可以看作是内核获取相关板级硬件信息的过程,大致的调用流程:

start_kernel()--->setup_arch()--->setup_machine_tags(),在此函数中已获得板级资源相关的struct machine_desc变量--->do_initcalls()--->customize_machine()--->machine_rk30_board_init()

首先使用mdesc = setup_machine_fdt(__atags_pointer)获取mdesc,__atags_pointer是uboot传递的参数存放位置,这里等于0x80000100,后边会解释。setup_machine_fdt()起作用的话,需要uboot传递的参数是设备树device tree的存放方式,我们实际使用的是tags_list方式,所以这里返回值为NULL。所以是通过mdesc = setup_machine_tags(machine_arch_type)获得的machine desc,machine_arch_type是uboot传递的machid。

在setup_machine_tags( )中有如下代码:

   for_each_machine_desc(p)

   {

             if (nr == p->nr) 

           {

                  printk("Machine: %s\n", p->name);    

                  mdesc = p;  

                  break;  

           }

   }

nr= machid=MACH_TYPE_AM335XEVM=3589是uboot传递过来的,而内核中的MACH_TYPE_AM335XEVM, 在/include/generated/mach-types.h中定义,这个文件是动态产生的。如何确定是哪个machine_desc?从machine_desc存放的段中,选择机器码与从uboot传递过来的机器号nr比较,相等即得到了与板级相关的struct machine_desc。

接下来看这个struct machine_desc类型的变量如何被调用的。

do_initcalls()执行下面的链接脚本指定的段中的函数,这其中有接下来要调用的customize_machine(),在arch/arm/kernel/vmlinux.lds中,

下面先贴上customize_machine()函数,

在include/linux/init.h中:

经过宏定义处理,最后customize_machine()被链接到了 ".initcall3.init" 段,所以会被 do_initcalls()执行。

 

在驱动程序中获取硬件资源信息:

以上就是内核如何注册板级硬件信息过程,以及驱动如何获取相关信息(均未使用设备树)。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值