Linux AMBA 驱动:DMA 控制器 PL330 驱动简析

news2024/11/26 2:41:49

文章目录

  • 1. 前言
  • 2. 背景
  • 3. PL330 简介
  • 4. PL330 驱动加载流程
    • 4.1 PL330 设备注册流程
    • 4.2 PL330 驱动加载流程
  • 5. 小结
  • 6. 参考资料

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 背景

本文基于 ARMv8 架构Linux 5.10 进行分析,DMA 控制器(DMAC: DMA Controller)ARM 的 PL330。

3. PL330 简介

PL330ARM 设计的 DMA 控制器(DMAC: DMA Controller),支持 Scatter/Gather 和 LLI(Linked-List Item) 特性。

在这里插入图片描述
上图是 PL330 的接口图,其中:

. AXI master 接口,用于 DMA 传输。
. APB slave 接口,用于配置/控制 DMAC PL330。
. Peripheral request interface [x:0],外设通过它发起 DMA 传输请求。
. Interrupts[x:0] 接口,用于发送中断给 CPU。

PL330 的典型应用框图如下:

在这里插入图片描述

更详细的 PL330 框图如下:

在这里插入图片描述

本文对 PL330 的介绍,就到此为止,更多关于 PL330 的细节,可参考 ARM 官方文档 DDI0424A_dmac_pl330_r0p0_trm.pdf

4. PL330 驱动加载流程

章节 3. 简单的介绍了 PL330 的功能和接口,本节将着重介绍 PL330 驱动的加载过程。首先看一下 PL330DTS 配置:

4.1 PL330 设备注册流程

dmac0: dma-controller@ff2c0000 {
	compatible = "arm,pl330", "arm,primecell";
	reg = <0x0 0xff2c0000 0x0 0x4000>;
	interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
		     <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
	arm,pl330-periph-burst;
	clocks = <&cru ACLK_DMAC0>;
	clock-names = "apb_pclk";
	#dma-cells = <1>;
};

系统启动过程中,解析 DMAC PL330DTS 配置:

kernel_init()
	kernel_init_freeable()
		...
		do_one_initcall()
			// arch_initcall_sync(of_platform_default_populate_init);
			of_platform_default_populate_init()
				of_platform_default_populate(NULL, NULL, NULL)
					of_platform_populate(root, of_default_bus_match_table, lookup, parent)
						rc = of_platform_bus_create(child, matches, lookup, parent, true)

/* drivers/of/platform.c */

static int of_platform_bus_create(struct device_node *bus,
				  const struct of_device_id *matches, 
				  const struct of_dev_auxdata *lookup, 
				  struct device *parent, bool strict)
{
	...

	if (of_device_is_compatible(bus, "arm,primecell")) {
		/*
		 * Don't return an error here to keep compatibility with older
		 * device tree files.
		 */
		of_amba_device_create(bus, bus_id, platform_data, parent);
		return 0;
	}
 
	...
}

#ifdef CONFIG_ARM_AMBA
static struct amba_device *of_amba_device_create(struct device_node *node,
						 const char *bus_id, 
						 void *platform_data,
						 struct device *parent)
{
	struct amba_device *dev;
	...

	/* 1. 创建 AMBA 设备: DMA PL330 */
	dev = amba_device_alloc(NULL, 0, 0);
	...

	/* 2. AMBA 设备初始化 */
	/* AMBA devices only support a single DMA mask */
	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
	dev->dev.dma_mask = &dev->dev.coherent_dma_mask;

	/* setup generic device info */
	dev->dev.of_node = of_node_get(node);
	dev->dev.fwnode = &node->fwnode;
	dev->dev.parent = parent ? : &platform_bus;
	dev->dev.platform_data = platform_data;
	if (bus_id)
		dev_set_name(&dev->dev, "%s", bus_id);
	else
		of_device_make_bus_id(&dev->dev);
	
	...

	/* Decode the IRQs and address ranges */
	for (i = 0; i < AMBA_NR_IRQS; i++)
		dev->irq[i] = irq_of_parse_and_map(node, i);

	...

	/* 3. 注册 AMBA 设备到系统 */
	ret = amba_device_add(dev, &iomem_resource);

	...
}
#else /* CONFIG_ARM_AMBA */
static struct amba_device *of_amba_device_create(struct device_node *node,
						 const char *bus_id,
						 void *platform_data,
						 struct device *parent)
{
	return NULL;
}
#endif /* CONFIG_ARM_AMBA */

上面 amba_device_alloc() 创建设备过程中,绑定设备总线类型为 amba_bustype,是 PL330 驱动匹配加载的重要一环:

amba_device_alloc()
	struct amba_device *dev;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (dev) {
		amba_device_initialize(dev, name);
			...
			dev->dev.bus = &amba_bustype; /* 绑定 设备 的 总线类型 为 amba_bustype */
			...
		...
	}

	return dev;

amba_device_add() 在注册设备到系统前,扫描读取 AMBA(Advanced Microcontroller Bus Architecture) 设备的 {periphid, cid},是 PL330 驱动匹配加载的另一重要环节:

amba_device_add()
	amba_device_try_add()

static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
{
	...
	/* 扫描读取 AMBA 设备的 {periph_id,cid} */
	ret = amba_get_enable_pclk(dev);
	if (ret == 0) {
		u32 pid, cid;
		...

		/*
		 * Read pid and cid based on size of resource
		 * they are located at end of region
		 */
		/* 读取 {periph_id,cid} */
		for (pid = 0, i = 0; i < 4; i++)
			pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
		for (cid = 0, i = 0; i < 4; i++)
			cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
		
		...
		
		amba_put_disable_pclk(dev);

		/* 记录 {periphid, cid} 到设备对象 */
		if (cid == AMBA_CID || cid == CORESIGHT_CID) {
			dev->periphid = pid;
			dev->cid = cid;
		}

		if (!dev->periphid)
			ret = -ENODEV;
	}

	...
 skip_probe:
 	/* 注册 AMBA 设备到系统 */
 	ret = device_add(&dev->dev);
 	...
}

读取到的 PL330periphid0x00241330cid0xb105f00d

4.2 PL330 驱动加载流程

/* drivers/dma/pl330.c */

static const struct amba_id pl330_ids[] = {
	{
		.id = 0x00041330,
		.mask = 0x000fffff,
	},
	{ 0, 0 },
};

MODULE_DEVICE_TABLE(amba, pl330_ids);

static struct amba_driver pl330_driver = {
	.drv = {
		.owner = THIS_MODULE,
		.name = "dma-pl330",
		.pm = &pl330_pm,
	},
	.id_table = pl330_ids,
	.probe = pl330_probe,
	.remove = pl330_remove,
};

module_amba_driver(pl330_driver);
/* include/linux/amba/bus.h */

#define module_amba_driver(__amba_drv) \
	module_driver(__amba_drv, amba_driver_register, amba_driver_unregister)
/* drivers/amba/bus.c */

int amba_driver_register(struct amba_driver *drv)
{
	if (!drv->probe)
		return -EINVAL;
	
	drv->drv.bus = &amba_bustype; /* 绑定 驱动 的 总线类型 为 amba_bustype */
	drv->drv.probe = amba_probe;
	drv->drv.remove = amba_remove;
	drv->drv.shutdown = amba_shutdown;

	return driver_register(&drv->drv);
}
driver_register()
	bus_add_driver()
		driver_attach()
			__driver_attach()
				...
				/* 驱动匹配 */
				ret = driver_match_device(drv, dev);
					amba_match()
						amba_lookup()
				...
				/* 驱动绑定 */
				device_driver_attach(drv, dev);
					driver_probe_device(drv, dev);
						really_probe(dev, drv);
							drv->probe(dev); /* pl330_probe() */
				...

static const struct amba_id *
amba_lookup(const struct amba_id *table, struct amba_device *dev)
{
	while (table->mask) {
		if (((dev->periphid & table->mask) == table->id) &&
			((dev->cid != CORESIGHT_CID) ||
			(amba_cs_uci_id_match(table, dev))))
			return table;
		table++;
	}
	return NULL;
}

从上面的分析中,可以看到 AMBA 设备 (PL330) 的匹配是通过 {periphid, cid} 进行匹配的。前面读到的 正好匹配到 pl330_ids[0],驱动加载流程进入了 pl330_probe()

pl330_probe()
	...
	/* 注册 DMA 中断处理接口 */
	for (i = 0; i < AMBA_NR_IRQS; i++) {
		irq = adev->irq[i];
		if (irq) {
			ret = devm_request_irq(&adev->dev, irq,
						pl330_irq_handler, 0, 
						dev_name(&adev->dev), pl330);
			...
		} else {
			break;
		}
	}
	...
	/* 注册 DMA 控制器设备到 DMA 子系统 */
	ret = dma_async_device_register(pd);
	...

5. 小结

虽然本文分析的 DMAC(DMA Controller) 设备的设备驱动注册加载,但其主干流程也适用于其它 AMBA(Advanced Microcontroller Bus Architecture) 设备驱动。

6. 参考资料

[1] DDI0424A_dmac_pl330_r0p0_trm.pdf
[2] 102202_0100_01_Introduction_to_AMBA_AXI.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1962471.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么牌子的骨传导耳机好?这五款骨传导耳机用过都是好评!

骨传导耳机&#xff0c;作为听音设备的创新之作&#xff0c;以其独特的传音方式赢得了市场的广泛认可。它不仅让日常听音更加健康舒适&#xff0c;还完美契合了运动场景的需求&#xff0c;让用户在享受音乐的同时&#xff0c;保持对周围环境的敏锐感知。这种设计上的巧思&#…

【QT串口助手】

首先非常感谢CSDN吾爱技术圈分享的QT初体验&#xff1a;手把手带你写一个自己的串口助手&#xff0c;本教程重点参考 1. 前言 由于qt应用项目需求&#xff0c;前期也安装过QT&#xff08;参考博客&#xff1a;【Qt安装与简易串口控制Arduino开发板小灯教程】&#xff09;&…

守护线程(Daemon Threads)详解:与非守护线程的区别

守护线程&#xff08;Daemon Threads&#xff09;详解&#xff1a;与非守护线程的区别 1、守护线程是什么&#xff1f;2、守护线程与非守护线程的区别2.1 JVM关闭行为2.2 任务性质2.3 线程设置2.4 示例代码 3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

人工智能学习笔记 - 初级篇Ⅱ - 图形可视化 - 第11节: 绘制带填充区域的图表

微信公众号&#xff1a;御风研墨 关注可了解更多。问题或建议&#xff0c;请公众号留言 文章目录 绘制带填充区域的图表应用背景准备工作操作步骤工作原理补充说明最后 绘制带填充区域的图表 应用背景 在数据可视化中&#xff0c;带填充区域的图表可以有效地表示数据范围、趋…

创客项目秀 | 基于 XIAO 开发板的语音向导

背景 柴火创客空间作为大湾区科技创新的窗口&#xff0c;每年到访空间的社区伙伴众多&#xff0c;为了更好的进行空间信息交互&#xff0c;我们希望有一个装置是可以解决&#xff1a;当空间管理员不在现场的时候&#xff0c;到访者可以通过装置获得清晰的介绍与引导。 为了解…

APP逆向 day24unidbg上

一.前言 今天开始讲app逆向最后一个也是最重要的unidbg&#xff0c;这已经是从初级进阶到中级的了&#xff0c;我会讲unidbg&#xff0c;讲三节课&#xff0c;分为上中下来和大家讲&#xff08;由简单到难逐步&#xff09;&#xff0c;这节课主要是和大家讲unidbg的介绍并且会…

详解工厂模式与抽象工厂模式有什么区别?【图解+代码】

目录 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 两种设计模式的流程&#xff1a; 1、工厂模式 2、抽象工厂模式 两种模式的对比 共同点&#xff1a; 不同点&#xff1a; 总结 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 我已经具体的写了这两种模…

我的「Java全栈高级架构师高薪就业课」适合什么样的人群学习?

我的《Java全栈高级架构师高薪就业课》上线了~ 这是一套Java全栈微服务架构、以实战项目驱动的课程&#xff01;包含34个模块&#xff0c;1514课时。对标阿里P7级别技术栈而研发&#xff0c;有着循序渐进的学习体系&#xff0c;助你开启Java进阶之旅。 我的这套《Java全栈高级…

海域感知与岸线监控实施方案:总体技术架构

文章目录 引言I 总体架构1.1 物理结构图1.2 功能逻辑结构图1.3 系统架构1.4 雷达光电船只检测系统拓扑图1.5 雷达光电船只联动跟踪效果图II 技术架构存储Geoserver视频see also引言 利用渔船现有的定位导航通讯设备等资源,实现岸线和近岸海域内违法船舶和可疑船舶预警、抓拍、…

系统学习渗透测试:从零到精通的全面指南

渗透测试&#xff0c;作为网络安全领域的一项重要技术&#xff0c;旨在通过模拟黑客攻击来评估计算机系统的安全性。对于想要系统学习渗透测试的人来说&#xff0c;这既是一条充满挑战的道路&#xff0c;也是一次深入了解网络安全的宝贵机会。本文将从基础知识、技能提升、实战…

怎麼使用ixbrowser指紋流覽器?

ixBrowser是一款指紋流覽器流覽器&#xff0c;利用指紋隔離技術確保在與Pixelscan等第三方檢測網站進行測試時具有出色的通過率&#xff0c;能夠輕鬆管理多個獨立帳戶。此外&#xff0c;ixBrowser能夠創建無限的獨立個人資料並邀請團隊成員。簡化了運營&#xff0c;降低了運營成…

转行要趁早!网络安全岗人才稀缺,前景广阔,收藏这一篇就够了

1 网络安全从业人员能力基本要求&#xff0c;您达标了吗&#xff1f; 引导 根据国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2023年第1号&#xff09;&#xff0c;由全国信息安全标准化技术委员会归口的《信息安全技术 网络安全从业…

设计模式15-门面模式

设计模式15-门面模式 "接口隔离"模式典型模式1. 适配器模式&#xff08;Adapter Pattern&#xff09;2. 装饰模式&#xff08;Decorator Pattern&#xff09;3. 桥接模式&#xff08;Bridge Pattern&#xff09;4. 代理模式&#xff08;Proxy Pattern&#xff09;5. …

分布式日志分析系统--ELK

文章目录 ELK概述ELK主要特点ELK应用架构 Elasticsearch原理JSON格式倒排索引 ES与关系型数据库ES相关概念ES安装说明1.环境初始化2.优化系统资源限制配置3.编辑ES服务文件elasticsearch. yml 优化ELK集群安装脚本scp的使用集群安装成功 Shell命令API使用创建索引创建Type创建分…

yocto系列讲解[实战篇]95 - 使用外部第三方交叉编译器toolchain

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述下载toolchain包部署toolchain下载yocto下载toolchain layer添加toolchain layer配置toolchain变量编译和测试验证返回总目录:Yo…

中控屏UI设计全解析:布局与交互技巧

在现代科技的浪潮中&#xff0c;中控屏已成为智能系统不可或缺的交互界面。无论是智能家居、车载系统还是工业控制&#xff0c;一个直观、易用且美观的中控屏 UI 设计对于提升用户体验至关重要。本教程将带领你深入探索中控屏UI设计的精髓&#xff0c;指导你如何打造出既专业又…

一些Kafka面试题

Kafka是如何保证消息不丢失&#xff1f; 1.生产者发送消息到Broker丢失&#xff1a; 设置异步发送&#xff1a;发送失败则使用回调进行记录或者重发 消息重试&#xff1a;参数配置&#xff0c;可以设置重试次数 2.消息在broker中存储丢失 发送确认机制acks acks0&#xf…

创新突破 | OpenCSG发布StarShip CodeReview v1.0.0 Beta版

1. 代码审查很关键但耗时耗力 在软件开发过程中&#xff0c;代码审查是确保代码质量的关键环节。代码审查有助于维护代码标准和发现潜在错误&#xff0c;但也常常耗费大量时间和精力。审查者不仅需要深入理解代码逻辑&#xff0c;还要在繁复的逻辑中识别Bug&#xff0c;这个过…

如何使用 Odoo 16 主生产调度程序规划生产

为了优化运营并提高生产力&#xff0c;企业需要生产管理软件。在当今竞争激烈的经济环境中&#xff0c;有效的资源管理对企业至关重要。为制造业务设计的软件经常用于控制收入增长和盈利能力。ERP&#xff08;企业资源规划&#xff09;系统是专门为制造业创建的&#xff0c;可以…

Java刷题: 丑数判断

题目 丑数 就是只包含质因数 2、3 和 5 的正整数。 给你一个整数 n &#xff0c;请你判断 n 是否为 丑数 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 解题思路 我觉得刷题是为了扩宽思考的广度。看到这题的时候&#xff0c;我的大脑是发懵的…