高通平台device tree生成platform device的过程(MSM8909)
生活随笔
收集整理的這篇文章主要介紹了
高通平台device tree生成platform device的过程(MSM8909)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
點擊打開鏈接
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
經(jīng)過宏替換,最終變?yōu)?
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();調(diào)用的實際是msm8909_init函數(shù):
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函數(shù)來生成platform device,具體調(diào)用過程:of_platform_populate->of_platform_bus_create->of_platform_device_create_pdata->of_device_add
以高通GPIO為例,在arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi中關(guān)于GPIO的resource描述:
compatible = "qcom,msm-tlmm-8916";
reg = <0x1000000 0x300000>;
在of_platform_device_create_pdata函數(shù)中,通過調(diào)用of_device_alloc函數(shù)來生成platform device,在of_device_alloc函數(shù)中,調(diào)用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中,調(diào)用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數(shù)組的最后一項,這里的addresses成員剛好是reg,和dtsi中的reg = <0x1000000 0x300000>;匹配。
static struct of_bus of_busses[] = {
??? //刪除了無關(guān)代碼
??? /* 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);來設(shè)置resource的標(biāo)志位,實際上就是調(diào)用上述of_bus of_busses的get_flags成員指向的地址,即of_bus_default_get_flags,而函數(shù)直接返回IORESOURCE_MEM標(biāo)志:
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變量,最后通過調(diào)用__of_address_to_resource函數(shù)來設(shè)置resource的start和end地址以及flags標(biāo)志:
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生成之后,就可以調(diào)用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);
}
總結(jié)
以上是生活随笔為你收集整理的高通平台device tree生成platform device的过程(MSM8909)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android bootloader阶段
- 下一篇: Android中APK直接通过JNI访问