2. 解析设备树获取GPU资源
任务说明
本案例实现从设备树中解析Mali GPU驱动所需的三种核心资源:寄存器地址与长度、中断号、时钟信息。解析结果以结构体形式输出,供驱动后续的ioremap、request_irq、clk_get等操作直接使用。
设备树节点示例
以下为Mali GPU在设备树中的典型节点(dts片段),本案例代码将针对该节点进行解析:
gpu: mali@13000000 {
compatible = "arm,mali-bifrost";
reg = <0x13000000 0x10000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_gpu &clk_gpu_axi>;
clock-names = "gpu", "axi";
};
核心数据结构
struct mali_gpu_resources {
phys_addr_t reg_start;
u32 reg_size;
int irq;
struct clk *clk_gpu;
struct clk *clk_axi;
};
解析实现
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_clk.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
static int mali_parse_dt_resources(struct platform_device *pdev,
struct mali_gpu_resources *res)
{
struct device_node *np = pdev->dev.of_node;
struct resource r;
int ret;
if (!np)
return -ENODEV;
/* 1. 解析寄存器地址与长度 */
ret = of_address_to_resource(np, 0, &r);
if (ret) {
dev_err(&pdev->dev, "failed to parse reg\n");
return ret;
}
res->reg_start = r.start;
res->reg_size = resource_size(&r);
/* 2. 解析中断号 */
res->irq = irq_of_parse_and_map(np, 0);
if (!res->irq) {
dev_err(&pdev->dev, "failed to parse irq\n");
return -EINVAL;
}
/* 3. 解析时钟(需与clock-names顺序对应) */
res->clk_gpu = of_clk_get_by_name(np, "gpu");
if (IS_ERR(res->clk_gpu)) {
dev_err(&pdev->dev, "failed to get gpu clock\n");
return PTR_ERR(res->clk_gpu);
}
res->clk_axi = of_clk_get_by_name(np, "axi");
if (IS_ERR(res->clk_axi)) {
dev_err(&pdev->dev, "failed to get axi clock\n");
clk_put(res->clk_gpu);
return PTR_ERR(res->clk_axi);
}
return 0;
}
调用与资源释放
static int mali_probe(struct platform_device *pdev)
{
struct mali_gpu_resources res;
int ret;
memset(&res, 0, sizeof(res));
ret = mali_parse_dt_resources(pdev, &res);
if (ret)
return ret;
/* 此处可进行 ioremap(res.reg_start, res.reg_size) 等后续操作 */
dev_info(&pdev->dev, "GPU reg: 0x%llx size: %u irq: %d\n",
(u64)res.reg_start, res.reg_size, res.irq);
return 0;
}
static void mali_resources_release(struct mali_gpu_resources *res)
{
if (!IS_ERR_OR_NULL(res->clk_gpu))
clk_put(res->clk_gpu);
if (!IS_ERR_OR_NULL(res->clk_axi))
clk_put(res->clk_axi);
}
验证方法
将上述代码编译进内核模块,在目标板上加载模块。若解析成功,dmesg中应输出寄存器起始地址0x13000000、长度0x10000及中断号45。若设备树节点缺失或属性错误,应返回对应错误码并打印错误信息。可通过手动修改设备树中reg或interrupts值来验证解析逻辑的健壮性。
判定标准
代码通过编译且加载后满足以下条件即判定为通过:
- dmesg输出中包含"GPU reg: 0x13000000 size: 65536 irq: 45"(数值与设备树一致);
- 当设备树中reg属性被修改为其他地址时,输出随之变化;
- 删除clock-names中的"axi"后,模块加载返回-ENOENT且打印"failed to get axi clock"。