1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 高通平台device tree生成platform device的过程(MSM8909)

高通平台device tree生成platform device的过程(MSM8909)

时间:2019-03-26 23:13:08

相关推荐

高通平台device tree生成platform device的过程(MSM8909)

点击打开链接

在arch/arm/kernel/setup.c中,通过customize_machine函数中的machine_desc->init_machine();来调用高通平台的machine初始化代码:

static int __init customize_machine(void)

{

/*

* customizes platform devices, or adds new ones

* On DT based machines, we fall back to populating the

* machine from the device tree, if no callback is provided,

* otherwise we would always need an init_machine callback.

*/

if (machine_desc->init_machine)

machine_desc->init_machine();

#ifdef CONFIG_OF

else

of_platform_populate(NULL, of_default_bus_match_table,

NULL, NULL);

#endif

return 0;

}

arch_initcall(customize_machine);

在arch/arm/mach-msm/board-8909.c中:

DT_MACHINE_START(MSM8909_DT,

"Qualcomm Technologies, Inc. MSM 8909 (Flattened Device Tree)")

.map_io = msm8909_map_io,

.init_machine = msm8909_init,

.dt_compat = msm8909_dt_match,

.reserve = msm8909_dt_reserve,

.smp = &msm8916_smp_ops,

MACHINE_END

经过宏替换,最终变为:

static const struct machine_desc __mach_desc_MSM8909_DT __used __attribute__((__section__(".arch.info.init"))) = {

.nr = ~0,

.name = "Qualcomm Technologies, Inc. MSM 8909 (Flattened Device Tree)",

.map_io = msm8909_map_io,

.init_machine = msm8909_init,

.dt_compat = msm8909_dt_match,

.reserve = msm8909_dt_reserve,

.smp = &msm8916_smp_ops,

}

所以,machine_desc->init_machine();调用的实际是msm8909_init函数:

static void __init msm8909_init(void)

{

struct of_dev_auxdata *adata = msm8909_auxdata_lookup;

/*

* populate devices from DT first so smem probe will get called as part

* of msm_smem_init. socinfo_init needs smem support so call

* msm_smem_init before it.

*/

of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);

msm_smem_init();

if (socinfo_init() < 0)

pr_err("%s: socinfo_init() failed\n", __func__);

msm8909_add_drivers();

}

通过of_platform_populate函数来生成platform device,具体调用过程:of_platform_populate->of_platform_bus_create->of_platform_device_create_pdata->of_device_add

以高通GPIO为例,在arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi中关于GPIO的resource描述:

compatible = "qcom,msm-tlmm-8916";

reg = <0x1000000 0x300000>;

在of_platform_device_create_pdata函数中,通过调用of_device_alloc函数来生成platform device,在of_device_alloc函数中,调用of_address_to_resource来解析GPIO的资源:

int of_address_to_resource(struct device_node *dev, int index,

struct resource *r)

{

const __be32 *addrp;

u64 size;

unsigned int flags;

const char *name = NULL;

addrp = of_get_address(dev, index, &size, &flags);

if (addrp == NULL)

return -EINVAL;

/* Get optional "reg-names" property to add a name to a resource */

of_property_read_string_index(dev, "reg-names", index, &name);

return__of_address_to_resource(dev, addrp, size, flags, name, r);

}

在of_get_address中,调用of_match_bus来匹配总线:

static struct of_bus *of_match_bus(struct device_node *np)

{

int i;

for (i = 0; i < ARRAY_SIZE(of_busses); i++)

if (!of_busses[i].match || of_busses[i].match(np))

return &of_busses[i];

BUG();

return NULL;

}

最终会匹配到of_busses数组的最后一项,这里的addresses成员刚好是reg,和dtsi中的reg = <0x1000000 0x300000>;匹配。

static struct of_bus of_busses[] = {

//删除了无关代码

/* Default */

{

.name = "default",

.addresses = "reg",

.match = NULL,

.count_cells = of_bus_default_count_cells,

.map = of_bus_default_map,

.translate = of_bus_default_translate,

.get_flags = of_bus_default_get_flags,

},

};

之后of_get_address会通过*flags = bus->get_flags(prop);来设置resource的标志位,实际上就是调用上述of_bus of_busses的get_flags成员指向的地址,即of_bus_default_get_flags,而函数直接返回IORESOURCE_MEM标志:

static unsigned int of_bus_default_get_flags(const __be32 *addr)

{

return IORESOURCE_MEM;

}

of_get_address会通过prop = of_get_property(dev, bus->addresses, &psize);来返回const __be32 *prop;指针给addrp变量,最后通过调用__of_address_to_resource函数来设置resource的start和end地址以及flags标志:

static int __of_address_to_resource(struct device_node *dev,

const __be32 *addrp, u64 size, unsigned int flags,

const char *name, struct resource *r)

{

u64 taddr;

if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)

return -EINVAL;

taddr = of_translate_address(dev, addrp);

if (taddr == OF_BAD_ADDR)

return -EINVAL;

memset(r, 0, sizeof(struct resource));

if (flags & IORESOURCE_IO) {

unsigned long port;

port = pci_address_to_pio(taddr);

if (port == (unsigned long)-1)

return -EINVAL;

r->start = port;

r->end = port + size - 1;

} else {

r->start = taddr;

r->end = taddr + size - 1;

}

r->flags = flags;

r->name = name ? name : dev->full_name;

return 0;

}

platform device生成之后,就可以调用platform_get_resource(pdev, IORESOURCE_MEM, 0);来获得GPIO的基地址和长度,具体代码可以参考 drivers/pinctrl/pinctrl-msm-tlmm.c文件中的msm_tlmm_probe:

static int msm_tlmm_probe(struct platform_device *pdev)

{

const struct of_device_id *match;

struct msm_tlmm_desc *tlmm_desc;

int irq, ret;

struct resource *res;

int i;

const struct msm_pintype_data **pintype_data;

struct device_node *node = pdev->dev.of_node;

match = of_match_node(msm_tlmm_dt_match, node);

if (IS_ERR(match))

return PTR_ERR(match);

else if (!match)

return -ENODEV;

tlmm_desc = devm_kzalloc(&pdev->dev, sizeof(*tlmm_desc), GFP_KERNEL);

if (!tlmm_desc) {

dev_err(&pdev->dev, "Alloction failed for tlmm desc\n");

return -ENOMEM;

}

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (!res) {

dev_err(&pdev->dev, "cannot find IO resource\n");

return -ENOENT;

}

tlmm_desc->base = devm_ioremap(&pdev->dev, res->start,

resource_size(res));

if (IS_ERR(tlmm_desc->base))

return PTR_ERR(tlmm_desc->base);

tlmm_desc->irq = -EINVAL;

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

if (res) {

irq = res->start;

ret = devm_request_irq(&pdev->dev, irq, msm_tlmm_handle_irq,

IRQF_TRIGGER_HIGH,

dev_name(&pdev->dev),

tlmm_desc);

if (ret) {

dev_err(&pdev->dev, "register for irq failed\n");

return ret;

}

tlmm_desc->irq = irq;

}

pintype_data = (const struct msm_pintype_data **)match->data;

for (i = 0; i < MSM_PINTYPE_MAX; i++)

tlmm_pininfo[i].pintype_data = pintype_data[i];

tlmm_desc->pintypes = tlmm_pininfo;

tlmm_desc->num_pintypes = ARRAY_SIZE(tlmm_pininfo);

return msm_pinctrl_probe(pdev, tlmm_desc);

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。