DM 3730的MMC控制器框架如图7-11所示。图7-11DM 3730 MMC框架图从图7-11可见,MMC控制器中有复杂的命令和数据管理,控制器内部带有buffer用于数据缓冲,数据主要通过DMA读写。关于DM 3730 MMC的驱动部分,主要分析其相关的初始化和总线传输以及card状态变化的操作。......
2023-11-22
下面以4.1.1节所介绍的系统初始化流程为例,来看看不同的处理器启动流程的区别。图4-4和图4-5分别是DM 816X和DM 3730的启动流程。
从图4-4和图4-5可见,DM 816X和DM 3730启动流程还是有区别的。主要区别在于:DM816X的boot loader阶段只是u-boot,而DM 3730的boot loader阶段则分为x-loader和u-boot。其中原因是芯片内部片内内存大小。DM 3730中只有64KB的片内内存,而DM816X有512KB,这样DM 816X就可以直接将u-boot的image放入片内内存中,而DM 3730的片内内存空间不够,就需要通过一个mini boot loader来过渡。可见资源对于系统的设计还是有很大影响的。
接下来以TI芯片为基础进行整个系统的初始化过程详解。从这个过程中可以了解到系统移植的信息。
1.image文件生成
Linux内核的编译过程,首先会将各个模块单独编译,然后链接并最终生成一个很大的文件,这个文件就是vmlinux。其中当然包括初始化的代码,而整个Linux系统的起始地址这一重要信息在vmlinux.lds内(此文件是体系结构相关的)。以ARM为例,该文件是由arch/arm/kernel/vmlinux.lds.S在编译链接时生成。下面先看看DM 3730编译链接生成的该文件的部分内容。
图4-4 DM 816X启动流程
图4-5 DM 3730启动流程
从这部分链接脚本可见Linux内核的起始位置是0xC0008000,这个地址可以保证整个系统转入虚拟地址后,内核代码的地址映射仍然是一致的。0xC0008000的位置是通过如下vm-linux.lds.S语句生成的。注意通常CONFIG_XIP_KERNEL都是不被配置的,另外宏PAGE_OFFSET和TEXT_OFFSET都是和体系结构相关的。一般的PAGE_OFFSET是0x80000000,而TEXT_OFFSET是0x8000。
另外从生成的链接脚本可见,除了具体的处理器和体系结构信息(如.proc.info.init)外,还有一些init的信息(主要是各种init的段),这些信息还是很重要的。之前讨论内核初始化需求的时候,提到初始化代码应该在初始化之后释放相应的内存空间,这里可以看出Linux内核已经将初始化相关的代码统一存放并管理,一方面方便初始化时调用,另一方面可以在系统初始化之后将这部分空间释放。这个文件还是很重要的,一个文件就解决了几个问题。
内核生成的vmlinux文件实在太大、不适合引导加载,所以需要进行压缩,Linux内核压缩后为zImage,可以说zImage是将可执行Linux内核vmlinux压缩后作为数据包含在自身中,图4-6展示了vmlinux到zImage的生成流程。
图4-6 zImage生成流程
zImage的生成过程有一个问题,就是zImage究竟放在哪里,zImage需要知道这个位置。因为它不能对这个位置进行任何的假设,并且需要该位置信息来判断解压后的空间是否会对自身有影响。另外对于具体的memory空间,地址信息是和具体处理器相关的,需要一个方式让与体系结构相关的zImage中包含这些信息,这样就可以自给自足了。下面看看Linux内核是如何实现的。
从图4-6中可见,压缩后的vmlinux会增加arch/arm/boot/compressed的代码作为头,然后生成zImage,先来看看zImage头中head.S的代码,这里只是摘录了一部分:
这部分代码会保存处理器架构ID信息和atags信息(用于传送启动参数等信息)。另外有个符号zreladdr,该符号就是zImage最终被加载到内存中的地址。这个符号在哪里生成的呢?来看看compressed目录下的Makefile文件,其中有这么一段:
这里直接通过链接工具创建符号zreladdr,但数据是通过ZRELADDR参数传递的。这个参数又是如何来的呢?继续追踪boot目录下的Makefile:
这里可以看到ZRELADDR是由zreladdr-y定义的,又出来一个变量。为什么不直接定义呢?这样设计是为什么呢?之前提到内存地址在具体的处理器之间是有差别的,如何屏蔽这种差别?这种差别的配置还是要放入具体的处理器代码目录中。Linux内核也是这个思路,这段代码的开始include一个文件Makefile.boot,而且该文件是在一个具体的处理器目录中的,就是它进行了处理器差异的配置。具体到DM3730等之前介绍的TI处理器都是引用自mach-omap2目录下的Makefile.boot,其内容如下:
查看一下芯片手册会发现,第一段内存的地址空间就是从0x80000000起始的地址,这样就对应上了。可见新的处理器只要在对应的目录中定义自己的Makefile.boot(其中包括上面的定义)就能自动生成正确的zImage。
到这里算是告一段落,但是嵌入式开发工程师通常比较熟悉uImage,为什么不是zImage呢?这个和u-boot的Boot loader功能相关,主要是因为zImage知道自己所存放的地址,但是它还是需要u-boot将其放入合适的位置。u-boot是通过uImage的开始一段的内容知道这个信息的,也就是说uImage实际是给zImage封装了一个简单的头,这个头中包括一些u-boot需要的信息。这就要求Linux内核能直接生成uImage。来看看uImage是如何生成的?同样是在arch/arm/boot目录下的Makefile:
这里的cmd_uimage是kbuild用来定义客户自定义的编译命令,该命令的名字就是uimage,实际调用u-boot的mkimage命令生成uImage。在DM 3730等TI处理器中最终会将ZRELADDR即0x80008000作为参数传入,这样就正确地生成uImage,完成了Linux内核im-age生成的全过程。
2.处理器启动至boot loader
先来看看芯片的启动时序,以DM 3730为例,上电时序如图4-7所示。
图4-7 DM 3730上电时序
图4-7引自《DM 3730芯片手册》中第266页框图。从该图中可以看到整个芯片上电的硬件信号流程,这对了解整个系统的正常启动至关重要。另外可以看出系统的启动是从外部的供电和时钟信号开始,以主处理器的复位信号(MPU_RST)信号拉高为结束,之后就开始执行启动代码了。硬件启动时序正常的重要因素就是保证供电和时钟的稳定,要符合芯片的参数要求。
处理器上电启动代码的执行是和体系结构相关的,以ARM为核心的处理器,上电启动执行的第一个代码是reset向量的代码,reset向量上电默认为0x00000000地址。指令执行需要XIP存储器,除了ROM、RAM之外,NOR Flash也是XIP存储器,所以处理器是可以从NOR启动的。不同的处理器如何选择启动指令执行,比如转到ROM Code执行,就各有各的实现方式。下面是《DM 3730芯片手册》中第203页的一段话:
The system has a 1-MB boot space in the on-chip boot ROM or on the GPMC memory space.When booting from the on-chip ROM with the appropriate external sys_boot5 pin configura-tion,the 1-MB memory space is redirected to the on-chip boot ROM memory address space[0x4000 0000–0x400FFFFF].When booting from the GPMC with the appropriate external sys_boot5 pin configuration,the memory space is part of the GPMC memory space.For more information about sys_boot5 pin configuration,see Chapter 10,Memory Subsystem,and Chapter 26,Initialization.
根据这段话可以明确DM 3730芯片设计时是如何解决该问题的。DM 3730在系统启动时将0x0开始的1MB空间直接映射到ROM Code中,当启动时检查sys_boot5引脚来决定地址是否重定向,然后再reset ARM核心,这样使得ARM可以执行正确的代码来进行启动。
系统启动后,ARM就开始执行ROM Code的代码。ROM Code支持的启动设备称为启动能力,具体的启动能力是不同的处理器根据需求实现的。图4-8和图4-9分别是DM 816X和DM 3730的ROM Code框架。
图4-8 DM 816X芯片ROM Code框架
图4-9 DM 3730芯片ROM Code框架
从图4-8和图4-9中可见,DM 816X的启动能力要比DM 3730强得多。DM 816X支持网络启动和PCIe启动,这些都是DM 3730不具备的,也是符合DM 816X服务器以及PCIe板卡这些功能需求的。注意DM 3730中的ROM Code有clock detection模块,主要用来检测外部高速晶振的频率。通常ROM Code运行时,主处理器的时钟频率为外部高速晶振的频率(如26MHz)。这里ROM Code的检测模块确认时钟频率,可以为后续boot load-er以及Linux内核设置各个不同模块的时钟提供基础时钟,进而明确如何进行配置才能得到需要的时钟频率。
ROM Code的主要任务就是到其支持的设备中查找boot loader,并加载到片内RAM中执行。这个过程中涉及两部分:
其一,识别正确的boot loader并加载,通常ROM Code会通过image增加特定的头标记,来识别并正确加载。芯片厂商会提供相应的生成和烧写工具代码以供使用。
其二,boot loader编译的时候还是要以片内RAM的地址空间为基础,这就要在boot loader中进行设置。
先看看DM 3730是如何操作的。
x-loader需要在片内内存中执行,其板级相关代码对应的目录中有config.mk文件,其中会设置代码的起始地址:
而在链接的时候会通过参数-Ttext $(TEXT_BASE)指定代码的起始地址为TEXT_BASE定义的地址。这样整个代码就是在片内内存空间。x-loader加载到片内RAM后其内存布局如图4-10所示。
图4-10 DM 3730 x-loader执行片内RAM布局
x-loader的最终image要加入特殊的头信息,具体说明如图4-11所示,图4-11引自《DM 3730芯片手册》。其中包含加载的地址和image的大小信息。
图4-11 DM 3730 x-loader image头信息说明
这个头信息是通过工具signGP生成的,相应信息如下:
又见到TEXT_ BASE,这就要求加载的地址和编译的地址一一对应。
u-boot则是在内存中执行,其地址应该是从0x80000000开始的空间。u-boot中对应的config.mk的设置:
可见其设置在内存的地址空间。这样代码所在空间的问题就解决了。但又出现一个问题,代码被加载到什么地址了呢?对于x-loader,这个问题没办法回答,原因在于ROMCode并不公开这些信息。u-boot则是通过x-loader加载的,来看看相应的设置,在相应的板级配置文件中包含如下的信息:
这个就是加载的地址,为什么和代码的地址不同呢?这个就无从考究了。这种不同会有问题吗?答案是不会的,主要是因为在跳转到加载地址执行代码(开始处为汇编代码),是使用的是相对地址即地址无关来执行,而一般跳转指令(如b、bl等)都是相对地址跳转,所以没有问题。但是如果u-boot中跳转到start_armboot,该C函数使用的是ldr pc直接加载指令寄存器这种绝对地址跳转方式,此时代码的地址必须一一对应,否则这个跳转就会出现问题。至于为什么一定要进行这个绝对跳转,因为这是开发者设置的,只有开发者才最了解其内存布局。boot loader会留出该接口给开发者设置,这样才能保证后续的内核加载等操作的正确进行。在绝对跳转之前,u-boot和x-loader的start.S中都包含的搬移代码的重定向功能能保证代码地址和在地址空间中的位置一一对应。相应的重定向代码如下:
这些代码主要实现将代码移动到TEXT_BASE开始的地址,x-loader也采用同样的办法解决加载地址和编译链接地址不匹配的问题。需要注意的是:这段代码还是比较简单的实现,其中并没有考虑一些特殊情况的覆盖问题(比如拷贝过程中的局部覆盖),所以加载代码的地址和编译链接的地址要有比较大的间隔,才能保证正确的结果。
再来看看DM 816X是如何操作的。
由于DM 816X片内RAM有512KB,完全可以加载并执行u-boot,所以在该阶段只需要一次boot loader。而boot loader同样是加载到片内RAM中执行。
DM 816X由ROM Code加载的image的格式同DM 3730,具体见《DM 816X芯片手册》中第2400页的说明。在生成image方面,DM 816X与DM 3730不同,DM 3730使用的是单独的signGP工具,而DM 816X使用的是u-boot中的mkimage工具。在u-boot中的tools目录下可以看到tiimage的C文件,这就是定义了TI特殊的image头及其生成方式,用于生成符合DM 816X处理器的image文件。生成代码是在Makefile文件中,具体内容如下:
该命令通过mkimage添加必要的头信息,如加载地址、设备信息,并生成TI_IMAGE定义名字的image。
这里可见,除了TI_IMAGE之外,还有TI_LOAD_ADDR和TI_DEVICE两个变量需要明确。它们都是在哪里定义的呢?这些信息和板级信息相关,还记得之前提到的板级配置文件config.mk吧,就是在其中定义的,来看看具体内容:
这里定义了板级特殊的变量,其中image的加载地址是0x40400000,即在片内内存的地址区域中。这里TEXT_BASE是在0x80700000,且为内存地址,这又如何操作呢?后续会进行说明。另外有一部分就是加载了特别的配置文件config.tmp,其中的原因又是什么呢?主要是因为DM 816X支持从不同的设备启动,就要有不同的u-boot的image,其中会有一些特殊的设置,这些特殊的设置可以通过config.tmp将这些变量重定义来实现。这样就开放一个重定义的接口文件来实现差异化。
具体的设置是在Makefile中通过不同的配置实现,具体内容如下:
从中可见,针对不同启动设备的image,会有两个配置文件需要进行相应的设置。一个是include/config.h,另一个就是板级的config.tmp。通过这两个文件,就可以生成各种不同启动设备的image了。
从整个过程可见,不同的处理器的启动思路基本是相同的,相应的差别主要在设备地址以及不同设备的启动能力上。
通常在该部分并没有信息输出到控制台,一般的输出都是要在boot loader阶段才开始的。
3.boot loader至内核image
在ROM Code将boot loader加载到片内内存之后,就会跳转到相应的地址执行boot loader的代码。之前已经提到,boot loader被加载的地址和编译的地址可能不同,需要有个重定向的过程。而重定向需要从片内RAM重定向到内存的空间,而这时内存控制器等并没有进行初始化,要求在重定向之前对内存控制器进行初始化。这样就会将整个boot loader的流程实际分割成两个阶段,即重定向之前的阶段和重定向之后的阶段。相应的分割点就是之前提到的start.S中的实际地址跳转指令,内容如下:
DM 3730的x-loader其实是基于u-boot进行的精简,所以框架和u-boot是一致的。后面都是以u-boot为例进行说明。
第一阶段的主要工作流程如图4-12所示。
首先,注意第一阶段由于其所在的空间并不是实际编译的空间,所以跳转指令必须使用相对跳转。在这一阶段主要初始化的硬件就是内存。对于u-boot框架来说,如果处理器有特别的底层初始化操作需要进行,通常会实现lowlevel_init。这一阶段的最终内存初始化操作一般都是通过定义s_init函数实现的。在这一阶段都会有汇编指令相对跳转到C函数s_init中执行。分别看看DM 3730和DM 816X中相应函数都进行了哪些操作。
图4-12 boot loader第一阶段流程
DM 3730的x-loader相应代码如下:
DM 816X的u-boot相应的代码如下:
(www.chuimin.cn)
从中可见,这部分初始化主要进行引脚设置、电源和时钟设置,以及内存控制器的设置。当然不同处理器的内存控制器设置是不同的,通常芯片厂商会提供相应的工具,如图4-13所示,根据内存手册的参数得到对应寄存器的值,在相应的函数中对控制寄存器写入即可。上述的操作执行完毕,外部内存就可以访问了。
图4-13 DM 3730内存控制器寄存器计算工具
内存可以访问之后,就能够进行代码搬移重定向操作,进入第二阶段。
第二阶段的基本流程如图4-14所示。
第二阶段主要进行外部设备初始化操作,这些设备可以进行kernel以及初始文件系统加载,所以究竟初始化什么设备是可以定制的。之前介绍的配置文件,就可以通过宏来进行这部分定制。相应的设备初始化后,boot loader就进入主循环,等待命令执行,或者直接执行设置好的命令。相应的命令主要用于通过设备加载内核image文件。不要忘记boot loader有一个重要的任务就是为内核传递参数,这就要求可以在boot loader中设置参数,boot loader主要通过其bootargs为内核传递启动参数。u-boot中具体的命令和参数在此就不做详细地介绍了。
图4-14 boot loader第二阶段流程
第二阶段最终会通过bootm命令跳转到内核执行。在跳转进内核image执行之前,还要进行一些必要的准备操作,主要如下:
这些准备操作是准备参数、关中断、清理cache等,最终通过theKernel这一指针跳转到内核image执行。为什么一定要进行这些操作呢?这些操作的前世今生又是怎样的呢?其实这些操作都是Linux内核规定boot loader在进入内核之前必须做的事情,毕竟boot loader和Linux内核之间统一的接口是有规定的。而Linux内核需要对处理器进行很多操作,这些操作是在特权级别并且对系统初始化很重要,自然会对处理器所处的状态等有严格的规定。关于ARM体系结构处理器的相关限制在内核的Documentation/arm/Booting文件中进行了详细的说明。从如下内容中可见对上述操作的要求。
以上部分摘自Linux内核中的文档,其中对新的技术(如虚拟化和设备树)进行了详细规定。这些规定在做实际的内核移植是需要注意的。
除了对处理器状态等的规定之外,有一点比较重要的就是boot loader和Linux内核之间如何进行参数的交互。这部分主要是通过tagged list来完成的。对于tagged list来说,也是由Linux内核进行规定的,同样是在Booting文件中有相关的描述。具体的解释如下(这里直接进行了翻译):
通过这段说明,回答了之前并没有解答的疑问zImage的起始地址设置为0x80008000,并没有从内存的首地址开始,而是从32KB开始,这样为boot loader和参数的传递留下足够的空间,另外后面也会看到内核在这32KB空间中还有需要保存的数据。
具体的参数及其传递的内容可以通过u-boot中include/asm-arm/setup.h文件获得,主要的标签信息如下:
从中可见,为扩展留出一定的余地,只是要进行参数的扩展还是需要在Linux内核侧做特别的定制工作。
通常该阶段结束会输出如下信息:
接下来就进入Linux内核了。
4.内核image至start_kernel
在介绍Linux内核image生成中,已经介绍了压缩image的生成。所以要进入Linux内核image,首先要做的就是将压缩的image进行解压缩操作。这部分是从boot/compressed目录下head.S文件中start处开始的,详细的流程如图4-15所示。
解压缩的过程控制台会输出如下信息:
解压缩结束后,最终通过__enter_kernel加载PC指针进入真正的内核,进行后续的操作。
这个入口在arch/arm/kernel/head.S中,该文件就是Linux内核真正启动的地方,是初始化部分的开始,用汇编写成,为后面的C代码初始化做好准备。其中有一些宏定义需要明确它们的含义,具体见表4-1。
表4-1 重要的宏定义
图4-15 Linux内核解压缩流程
这些宏定义之前也见过一些,这里进行详细说明也凸显出它们的重要性。这个阶段和移植相关的操作,主要就是这些宏定义的设置了。
注意这里主要是进行体系结构相关的初始化操作,主要的操作如下:
首先,检查处理器类型,通过__lookup_processor_type实现(arch/arm/kernel/head-common.S中),具体读取processor ID寄存器,并查找image中支持的体系结构列表;然后,通过__lookup_machine_type(arch/arm/kernel/head-common.S中)查找image中支持的处理器架构列表;最后,初始化页表,该页表在16KB~32KB之间(ARM体系结构下主页表的大小就是16KB,这样内存的前32KB就都有用处了)通过__create_page_tables实现,该页表足够内核进行后续初始化操作。
处理器特别的操作通常是__switch_data和__enable_mmu(arch/arm/mm/proc- *.S中实现)。后续还有初始化TLB、caches,最终使能MMU。紧接着就跳转到虚拟地址执行。下面来看看如何实现这个跳转的。注意在跳转到虚拟地址之前通常还是用相对跳转进行函数调用的。
这一阶段的具体流程如图4-16所示。
Linux内核到这里,就要进入start_kernel来进行C代码级别的初始化操作了。DM 3730的流程中调用和地址关系如图4-17所示。
5.start_kernel至rest_init
start_kernel函数是在Linux内核的init目录下的main.c文件中。看到文件名就知道,这其中包含了Linux内核初始化的主要函数,而start_kernel则是重中之重,如此重要的函数有必要完整读一遍。这里以2.6.37内核对应函数为例,并会将解释说明和代码混合在一起(直接在每行代码之前以注释的形式),这样可以结合代码一起理解。该函数也是了解Linux内核各个模块一个非常好的入口。
图4-16 Linux内核进入C代码之前的初始化流程
图4-17 DM 3730初始化流程调用和地址关系
通过start_kernel,可以对Linux内核的各个模块的功能有一个基本的了解。可以看到Linux内核还是提供了丰富的工具来帮助开发者调试和管理整个系统。
6.rest_init和kernel_init
基本的系统功能都已经初始化好,而且中断已经使能,下面就可以准备接收外部事件了。但是不要忘了,内核抢占还是disable的,并没有使能。此时系统中只有一个进程,其他进程是在rest_init中创建的,图4-18是rest_init的主要框架。
从图4-18中可见,Linux内核中有三个最基本的任务进程,分别为PID=0(只是相当于并没有该PID)的idle任务(就是之前提到的需要处理器进行特殊标记的任务);PID=1的任务,负责初始化所有用户系统相关进程的init任务;以及PID=2任务,负责产生内核线程的kthreadd任务。
当使用ps查看Linux所有进程时,会有如下信息。从中可见PID是从1开始的,而头两个任务就是在rest_init中创建的。
图4-18 rest_init框架图
接下来看看rest_init的代码:
对Linux内核初始化讲到现在,仍然没有看到设备相关的初始化,各种设备的初始化是在哪里执行的呢?接下来看看kernel_init会有些什么发现。
初始化时的initcall是比较繁杂的,涉及操作系统中的各个层面和功能,还和体系结构相关。为了方便查找和理解,笔者以DM 3730系列芯片内核为基础,列出了相应initcall的宏定义以及函数位置供读者参考。
从这些initcall中可以看出,很多功能模块、设备驱动框架和设备驱动的初始化操作都集中在这里进行了。当然这些初始化并不都执行,这和内核的配置相关,但是对了解明确各个模块的初始化流程还是很有帮助的。后面讲到具体驱动的时候会详细介绍相应的初始化操作。
7.体系结构和板级相关的初始化
对Linux系统初始化有了整体的认识之后,现在回过头来看看体系结构相关和板级相关的初始化操作setup_arch(ARM体系结构下在arch/arm/kernel/setup.c中)。这其中的细节对于做系统移植还是十分重要的。以下是DM3730内核2.6.37版本的相关setup_ arch代码,虽然版本有些老,但相应的机制是相同的。
最后,再来看看板级相关的初始化接口的定义。以DM 3730 EVM板的代码为例,在mach-omap2目录下的board-omap3evm.c中实现。详细内容如下:
这里的接口都是板级相关的接口,对于其中的说明以及在初始化中的使用,之前的内容已经说明,具体的实现这里就暂时放一放,会在对应的功能中进行详细介绍。需要说明的是init_machine接口,这个接口对于开发板是十分重要的。因为板子上所有的设备信息初始化都是通过该接口来实现的,其会在arch_initcall中被调用,通常早于设备驱动初始化。这样驱动初始化后就能正常使用设备了。函数具体的信息如下:
从中可见初始化涉及芯片的封装类型、引脚复用和各种设备(包括I2C、SPI、电源、USB等)。每种初始化细节留到相应功能和设备驱动部分时详述。
至此,包括核心处理器和板级的设备初始化的框架都进行了说明,整个初始化部分就比较完整了。
有关深入剖析Linux内核与设备驱动的文章
DM 3730的MMC控制器框架如图7-11所示。图7-11DM 3730 MMC框架图从图7-11可见,MMC控制器中有复杂的命令和数据管理,控制器内部带有buffer用于数据缓冲,数据主要通过DMA读写。关于DM 3730 MMC的驱动部分,主要分析其相关的初始化和总线传输以及card状态变化的操作。......
2023-11-22
对DM 3730的开发板,相关的输入设备是电源管理芯片中的键盘矩阵,这里对相关的输入设备驱动进行分析。在硬件介绍中已经见到DM 3730与电源管理芯片是通过I2C总线进行连接的,所以该键盘驱动需要建立在I2C总线操作之上。具体获得相关信息的方法都是通过类似twl4030_read_kp_matrix_state的操作完成的,其中会进行实际的I2C总线操作,具体的细节会在总线部分进行介绍。在驱动获得硬件的信息后就是向输入设备框架汇报相应的事件,框架会上传给even than-dler,最终被用户读取。......
2023-11-22
实际音频驱动的分析会以DM 3730的相关驱动为例进行说明。图6-17引自《DM 3730芯片手册》中第3096页框图。下面来看看dai相关的实现细节。4codec模块对codec模块部分,之前在codec的注册函数snd_soc_register_codec定义可见其会将co-dec driver和codec侧的dai同时注册,因为这两者都是与codec相关的。这里以DM3 730板上的twl4030为例,介绍相关的框架。对于codec主要是由codec driver来提供控制接口,而由codec dai来提供数据传输能力。......
2023-11-22
图4-24DM 3730物理空间设置IO空间映射的目的就是将这些物理地址映射到整个内核的地址空间中。首先来看ioremap虚拟地址返回是如何实现的。DM 3730等TI芯片就是通过该方法来实现该功能的。注意__arm_ioremap_caller使用的是vmalloc的空间进行映射,在相应版本内核中vmalloc的空间和TI芯片的IO映射空间是完全分开的,所以这里要直接返回相应的虚拟地址。......
2023-11-22
图6-10DM3730显示子系统软件整体架构从图6-10可见,在驱动框架部分,DSS的设计支持frame buffer和V4L2两种架构,这是由于两种类型的设备都是通过硬件的display子系统进行显示,它们之间可以通过叠加子系统进行叠加,这样相当于在硬件层进行了硬件加速,可以实现良好的显示效果。开放的sys接口如下:图6-11DSS软件模块与硬件对应关系图通过以上的设置就可以实现显示的切换、叠加等复杂的功能。TI frame buffer驱动的核心管理实体是omapfb2_device。驱动应对这种修改通过mapfb_apply_changes来实现。......
2023-11-22
要了解具体芯片的DMA使用和管理,首先要看一下硬件的设计。图4-44DM 3730 SDMA与其他模块联系系统框图从图4-44可见,SDMA共有96个DMA请求,用于设备请求DMA进行数据传输处理。SDMA可以访问到外设并可以响应芯片外部的DMA请求。为了提高整个的DMA性能,DMA提供多个中断信号给处理器,来加速系统对DMA处理数据过程的响应。DMA是很多驱动都需要使用的基础功能之一,以上进行了详细的代码级分析。......
2023-11-22
1芯片片内内存使用TI芯片相关的内存管理,对片外内存来说,可以通过启动参数将需要内核管理的内存进行设置。这样做的原因是由于需要连续的物理内存空间,并且对内核的物理内存管理影响最小。3独立cmem管理之前简单说明芯片厂商的独立内存管理,针对于TI的视频芯片,TI提供了cmem的内存管理驱动,主要是连续内存管理。有了该内存管理功能,TI的多媒体框架和编解码库就可以使用连续的物理内存空间,高效地完成多媒体处理相关的功能。......
2023-11-22
相关推荐