风河驱动在7.0后,也引入了设备树,和linux一样,通过设备树来设置驱动的相关参数信息。通过vxwroks源码分析设备树相关源码。
例1:设备树部分代码:
nandflash@0x30000000
{
compatible = "ti,emif16-nand";
clocks = <&internaldiv_6>;
clock-names = "internaldiv_6";
chip-select = <0>;
ale-offset = <0x2000>;
cle-offset = <0x4000>;
reg = <0x21000a00 0x0000100>, /@ emif16 control @/
<0x30000000 0x4000000>; /@ chip access window @/
/@ below timing values are in nanoseconds @/
acr-wsetup = <8>;
acr-wstrobe = <23>;
acr-whold = <8>;
acr-rsetup = <9>;
acr-rstrobe = <23>;
acr-rhold = <6>;
acr-ta = <12>;
};
1.1 数据结构
typedef struct vxbFdtDev
{
char name[FDT_NODE_NAME_LEN + 1];
int offset;
} VXB_FDT_DEV;
typedef struct vxbDevList {
SL_LIST list;
} VXB_RESOURCE_LIST;
1.2 API函数
1.2.1 vxbFdtDevMatch
函数功能:
此函数将FDT类型的设备与其驱动程序匹配。FDT用“compatible”字符串描述设备。驱动程序有列出支持的设备的表。这个例程将兼容字符串与驱动表进行比较,并返回匹配的兼容字符串的个数。
函数原型:
STATUS vxbFdtDevMatch
(
VXB_DEV_ID pDev, /* device to do match */
const VXB_FDT_DEV_MATCH_ENTRY * pMatchTbl, /* pointer to match table */
VXB_FDT_DEV_MATCH_ENTRY ** pMatchedEntry /* best matched entry */
)
例2:
LOCAL const VXB_FDT_DEV_MATCH_ENTRY vxbEmif16Match[] =
{
{
"ti,emif16-nand", /* compatible */
(void *)NULL
},
{}
};
LOCAL STATUS vxbEmif16Probe ( VXB_DEV_ID pDev )
{
//调用此函数vxbEmif16Match和设备树中compatible = "ti,emif16-nand";是否匹配
return vxbFdtDevMatch (pDev, vxbEmif16Match, NULL);
}
1.2.2 vxbFdtDevGet
函数功能: 获取FDT总线设备信息
函数原型:VXB_FDT_DEV * vxbFdtDevGet
(
VXB_DEV_ID pDev /* device identifier */
)
1.2.3 vxbFdtDevSetup
函数功能: 设置FDT总线设备名称和偏移量
函数原型:void vxbFdtDevSetup
(
int offset, /* device offset */
VXB_FDT_DEV * pFdtDev /* pointer to FDT device structure */
)
1.2.4 vxbFdtIntGet
函数功能:获取设备中断信息,为设备创建中断资源。
函数原型:STATUS vxbFdtIntGet
(
VXB_RESOURCE_LIST * pResList, /* resource list */
VXB_FDT_DEV * pFdtDev /* FDT device */
)
1.2.5 vxbFdtIntParentOffsetGetByDev
函数功能: 获取父中断控制器偏移量
函数原型:int vxbFdtIntParentOffsetGetByDev
(
VXB_FDT_DEV * pFdtDev
)
1.2.6 vxbFdtIoGet
函数功能: 此函数获取设备I/O信息,并为设备创建IO类型资源。
函数原型: STATUS vxbFdtIoGet
(
VXB_RESOURCE_LIST * pResList,
VXB_FDT_DEV * pFdtDev
)
1.2.7 vxbFdtRegGet
函数功能: 这个函数获取设备注册信息,并为设备创建内存/IO类型资源。注意:这个函数只被简单总线用来创建内存/IO资源,fdtBus不应该调用这个例程。
函数原型:STATUS vxbFdtRegGet
(
VXB_RESOURCE_LIST * pResList, /* resource list */
VXB_FDT_DEV * pFdtDev /* FDT device */
)
1.2.8 vxbFdtResFree
函数功能: 从资源列表中释放所有资源。
函数原型:void vxbFdtResFree
(
VXB_RESOURCE_LIST * pResList /* resource list */
)
1.2.9 vxbFdtUnitAddrGet
函数功能: 返回FDT节点的单位地址字符串;
这个助手函数从FDT设备节点名中获取单元地址字段。设备节点名称可以指定为name@unit-address,其中@字符后面的部分是16进制值。这个函数将解析节点名以找到单元地址字段的开头,以便它可以用作设备路径元素。注意,在VxWorks .dts文件中,单位地址字段的使用有些不一致。理想情况下,这个值应该始终存在,但有时却不是。而且,当它出现时,格式有时会不同。为了避免混淆,尽量返回一个统一的值。
VxWorks对单位地址字段的使用不一致。这些值通常是十六进制的,但格式不同。可以有以下任何一种: device@a000
device@0xa000
device@0000a000
device@0x0000a000
device@0
希望保持一致。最简单的事情是采用使用十六进制值的惯例,没有前导0和0x前缀,因此我们去掉这些字符。
函数原型:char * vxbFdtUnitAddrGet
(
UINT32 offset,
char * name,
UINT32 len
)
1.2.10 vxbFdtDevAcquireByOffset
函数功能: 使用VxBus节点的DTB偏移量查找VxBus节点。这个函数在VxBus树中搜索指定DTB 值对应的节点。这个偏移量必须是扁平设备树blob中的设备定义的位置,FDT总线代码使用它在VxBus设备树中创建一个节点。这个函数在核心vxbLib库之外实现,因为FDT在技术上是特定于总线的。(核心VxBus库包含可应用于任何VxBus句柄的泛型例程。这个函数只具有FDT总线的子设备的意义。)使用此函数获取的句柄必须通过vxbDevRelease()释放,以减少其引用计数。
函数原型:VXB_DEV_ID vxbFdtDevAcquireByOffset
(
int offset
)
1.2.11 vxbFdtDevAcquireByPhandle
函数功能: 在VxBus树中查找设备节点的phandle < >指定的设备,它获取对该设备的引用以防止被从树中移除。获得设备节点后,应该使用vxbDevRelease()例程释放对设备节点的引用。
注意:这个API应该只用于这样的情况:一个VxBus节点依赖于树中的另一个节点,而这个节点不容易通过仔细安排设备层次结构来解决。例如,在一些目标上,访问以太网PHY芯片的管理寄存器需要结合MDIO和GPIO寄存器访问。这意味着MDIO驱动程序可能需要向GPIO驱动程序发出请求,为此它需要GPIO设备的句柄。然而,MDIO和GPIO设备通常是兄弟节点,而不是父/子节点,因此,如果没有使用此API,就没有一种简单的方法来引用另一种。
应用程序代码应该避免使用这个API。理想情况下,设备驱动程序应该在附加阶段向应用程序库注册自己(例如,END驱动程序应该调用muxDevLoad()将自己绑定到MUX),而不是库代码试图将自己附加到设备上。
函数原型:VXB_DEV_ID vxbFdtDevAcquireByPhandle
(
UINT32 pHandle /* node property handle (phandle) */
)
1.2.12 vxbFdtMsiParentParse
函数功能: 为指定的VxBus设备查找MSI父节点,使用MSI -parent属性。msi-parent可以与任何类型的FDT设备一起使用。这个属性的应用方式有一些变化:一个单一的MSI -parent属性可以指定多个phandle,一个给定的MSI -parent模式可以有一个# MSI -cells属性,允许MSI -parent属性包含额外的包含MSI指定符数据的单元格。如果# MSI -cells是0或者不包含,那么MSI -parent属性只包含作为设备的MSI父节点的phandle。同样,任何作为MSI父节点的节点必须包含MSI -controller属性。
这意味着我们必须能够处理以下场景:
简单的si-parent情况:
msi-parent = <&mii>;
-简单的msi-parent情况,但带有#msi-cells > 0:
msi-parent = <&mii 0x1234>;
-复杂的msi-parent案例中有多个实例:
msi-parent = <&mii0>, <&mii1>, <&mii2>;
-复杂的msi-parent情况,带有#msi-cells > 0:
msi-parent = <&mii0 0x1234>, <&mii1 0x5678>, <&mii2 0x9abc>;
需要注意的是,复杂情况也可以表示为:
msi-parent = <&mii0 0x1234>;
msi-parent = <&mii1 0x5678>;
msi-parent = <&mii2 0x9abc>;
尽管这在语法上是不同的,但它们在功能上是等价的,因为它们在设备树blob中以相同的方式编码。还要注意,该语法允许每个MSI父节点为# MSI -cells定义不同的值。这意味着你可以有这样的东西:
msi-parent = <&mii0 0x1234>;
msi-parent = <&mii1 0x5678 0x9abc>;
在有多个phandl的复杂的si-parent情况下,调用者可以使用参数来选择返回哪个条目(index == 0是第一个)。如果指定了一个不存在的表项(例如index == 1,但只有一个表项),那么将返回一个NULL指针。
函数原型:STATUS vxbFdtMsiParentParse
(
VXB_DEV_ID pDev,
int index,
VXB_DEV_ID * pMsiParent,
int * pArgCnt,
UINT32 ** ppArgs
)
1.2.13 vxbFdtRidMap
函数功能: FdtRidMap——在VxBus节点上执行RID转换
这是一个helper函数,用于在VxBus设备节点上使用MSI -map或IOMMU -map属性执行请求者ID翻译和IOMMU/MSI父查询。在设备树,某些节点可能包含以下属性:
msi-map / msi-map-mask
iommu-map / iommu-map-mask
由于这两组属性以相同的方式格式化并使用相同的解码规则,所以我们可以使用一个函数来解析它们,尽管结果调用者可能会根据不同的情况进行不同的解析。
总线控制器使用IOMMU -map属性将设备的请求者ID转换为IOMMU隔离说明符,IOMMU隔离说明符用于限制设备执行DMA传输的方式,并提供到树中关联IOMMU设备的链接(通过phandle)。
msi-map属性定义专门为PCI控制器,用于设备的请求ID转化为MSI边带说明符用于限制设备如何实现动态的中断,并提供相关的链接(通过phandle)到一个MSI中断控制器装置内的树。
在一些例子中,总线控制器同时在IOMMU隔离和MSI边带转换中使用IOMMU -map属性。然而,同时使用IOMMU隔离和MSI边带数据的PCI控制器必须同时使用IOMMU -map和MSI -map属性,即使值在很大程度上相同。在这两种情况下,map属性包含4个单元:
- A base requester ID
- A parent phandle
- A base specifier ID (MSI specifier or IOMMU specifier)
- A length (which defines the translation range)
PCI总线的请求者ID是一个16位的字,它对PCI总线进行编码,给定设备的设备和函数号。一个示例msi-map条目看起来像:
Msi-map = <0x0 &msi0 0x110000 0x10000>;
其效果是将前缀0x110000添加到设备的16位中请求ID。
iommu-map属性的rid将取决于应用它的总线。
可以有多个msi-map或iommu-map条目,每个条目仅为总线上的设备子集提供转换。也可能有重叠的地图规则,尽管只有在可能的情况下,两个MSI或IOMMU父母可能服务于同一设备。换句话说,单个节点可以有这样的规则:
Msi-map = <0x0000 &msi_a 0x8000 0x08000>,
<0x8000 &msi_a 0x0000 0x08000>
<0x0000 &msi_b 0x0000 0x10000>;
可以包含一个附加的iommu-map-mask/msi-map-mask属性,以屏蔽指示符值中ORing之前的请求者ID中的位。请注意,虽然可以有多个映射属性,但只能有一个map-mask属性。因此,相同的map-mask值应用于所有map条目。
函数原型:STATUS vxbFdtRidMap
(
VXB_DEV_ID pDev,
int index,
VXB_DEV_ID * pMsiParent,
char * pPropName,
char * pPropMaskName,
UINT32 ridIn,
UINT32 * ridOut
)
1.2.14 vxbFdtBusIoctl
函数功能: fdtBus设备的ioctl方法
函数原型:STATUS vxbFdtBusIoctl
(
VXB_DEV_ID pDev, /* FDT bus device */
int cmd, /* ioctl commands for FDT bus device */
void * pArg /* command parameter for FDT bus device */
)
1.2.15 vxbFdtChildScan
函数功能: 扫描子设备
函数原型:STATUS vxbFdtChildScan
(
VXB_DEV_ID pDev /* device to scan */
)
1.2.16 vxFdtPropGet
函数功能: 获取给定属性的值;在offset nodeoffset处获取一个指向节点名为'pPropName'属性值的指针。
函数原型:const void * vxFdtPropGet
(
int offset, /* node offset */
char * pPropName, /* contains property name */
int * pLen /* on return, contains length, in bytes, */
/* of property value */
)
pVal = vxFdtPropGet (pFdtDev->offset, "data-scl-frequency", NULL);
1.2.17 vxFdtFirstPropGet
函数功能: 获取节点的第一个属性及其名称。
函数原型:const void * vxFdtFirstPropGet
(
int offset, /* node offset */
char ** pPropName, /* property name */
int * pLen, /* length of property value */
int * propOffset /* new property offset */
)
1.2.18 vxFdtNextPropGet
函数功能: 根据当前提供的节点获取指向节点下一个属性的指针。
函数原型:const void * vxFdtNextPropGet
(
int offset, /* property offset */
char ** pPropName, /* property name */
int * pLen, /* length of property value */
int * propOffset /* new property offset */
)
1.2.19 vxFdtGetName
函数功能: 返回一个指向结构块offset 处的设备树节点的名称(包括unit地址)的指针。如果非null,则通过更新所指向的整数值来返回该名称的长度。
函数原型:const void * vxFdtGetName
(
int offset, /* node offset */
int * pLen /* location to update length, in bytes, of name */
)
1.2.20 vxFdtIsEnabled
函数功能: 当节点被启用或“status”属性不存在时,这个函数将FDT节点状态返回TRUE,否则返回FALSE。
函数原型:BOOL vxFdtIsEnabled
(
int offset /* node offset */
)
主要判断status=“okay”还是“disabled”
if (vxFdtIsEnabled (offset) == FALSE) go err;
1.2.21 vxFdtNodeOffsetByPhandle
函数功能: 获取具有给定值的节点的偏移量。如果在给定(无效树)的树中有多个节点,则结果是未定义的。
函数原型:int vxFdtNodeOffsetByPhandle
(
UINT32 phandle / node property handle (phandle) /
)
phyOffset = vxFdtNodeOffsetByPhandle (phandle);
1.2.22 vxFdtNodeOffsetByCompatible
函数功能: 查找具有给定'compatible'值的节点; 例程返回之后第一个节点的偏移量,该节点有一个名为'compatible'的属性,其值匹配给定的字符串;或者如果 = -1,表示树中第一个匹配的节点。
如果成功,返回结构块偏移量。
-FDT_ERR_BADOFFSET如果没有找到或兼容是NULL
-FDT_ERR_INTERNAL如果FDT库内部错误
函数原型:int vxFdtNodeOffsetByCompatible
(
int startoffset, /* starting node offset */
char *compatible /* node compatibility string */
)
offset = vxFdtNodeOffsetByCompatible (0, "fsl,ls2-isc");
isc: isc@1f70000
{
compatible = "fsl,ls2-isc";
reg = <0x0 0x1f70000 0x0 0x10000>;
};
1.2.23 vxFdtNodeCheckCompatible
函数功能: 检查节点的compatible属性;返回一个指示,表明对于指定的节点,存在一个名为'compatible'的属性,其值与给定的字符串匹配。返回:0当兼容性匹配,1当不匹配,和-FDT_ERR_INTERNAL如果FDT库内部错误。
函数原型:int vxFdtNodeCheckCompatible
(
int offset, /* node's offset */
char *compatible /* compatibility string */
)
if ((vxFdtNodeCheckCompatible (pFdtDev->offset, "vxsim,intc")) == 0)
intc: interrupt-controller@0 {
compatible = "vxsim,intc";
interrupt-controller;
#interrupt-cells = <1>;
};
1.2.24 vxFdtCellGet
函数功能: 获取寄存器cell大小
函数原型:STATUS vxFdtCellGet
(
int offset, /* node offset */
int *pAdrsCell, /* on return, contains register address cell */
int *pSizeCell /* on return, contains register size cell */
)
ret = vxFdtCellGet (parOffset, &addressCells, &sizeCells);
DEBUG_MSG ("vxFdtCellGet addressCells = %d, sizeCells = %d\n", addressCells, sizeCells);
1.2.25 vxFdtDefRegGet
函数功能: 找到DTB的注册bar
函数原型:STATUS vxFdtDefRegGet
(
int offset, /* start node offset */
UINT32 barIndx, /* bar index */
PHYS_ADDR * pRegBarAddr, /* on return, contains register address */
size_t * pRegBarSize /* on return, contains register size, in bytes */
)
if (vxFdtDefRegGet (offset, 0, &phyAddr, &len) != OK)
{
phyAddr = (PHYS_ADDR)NULL;
DEBUG_MSG ("%s: get fsl,kinetis-sio BAR failed.\n",__FUNCTION__);
}
1.2.26 vxFdtStdoutGet
函数功能: 获取stdout节点ID
函数原型:int vxFdtStdoutGet(void)
//主要判断stdout-path属性
prop = (char *) fdt_getprop (gpDtb, offset, "stdout-path", &propLen);
chosen
{
stdout-path = "serial0";
};
1.2.27 vxFdtPhysMemInfoGet
函数功能: 从DTB获取物理内存信息;获取物理内存信息,并使用不超过的物理内存描述符初始化表。
注意:1. 每个物理内存的起始地址必须与ARCH所需的TLB页大小对齐;
2. 内核映像必须位于第一个物理内存描述符中;注意,这个例程只能在EarlyInit()中使用。
函数原型:int vxFdtPhysMemInfoGet
(
PHYS_MEM_DESC * pPhysMemDesc, /* address contains mem descriptor on return */
int physMemDescNum, /* maximum number of memory descriptors to get */
UINT uState /* memory attributes (state) */
)
regNum = vxFdtPhysMemInfoGet (pPhysMemDesc, physMemDescNum, uState);
memory@80000000
{
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x7be00000>,
<0x20 0x80000000 0x0 0x80000000>;
};
};
1.2.28 vxFdtBootargsGet
函数功能: 从DTB获取boottargs
函数原型:STATUS vxFdtBootargsGet
(
char pString, / where to copy bootargs /
int strLen / maximum number of bytes to copy /
)
if (vxFdtBootargsGet ((char *)BOOT_LINE_ADRS, BOOT_LINE_SIZE) != OK)
chosen
{
bootargs = "enet(0,0)host:vxWorks h=192.168.0.2 e=192.168.0.3:ffffff00 g=192.168.0.1 u=target pw=vxTarget";
};
1.2.29 vxFdtDtbAddressGet
函数功能: 返回全局DTB虚拟地址
函数原型:void vxFdtDtbAddressGet(void)
gpDtb = vxFdtDtbAddressGet();
offset = fdt_path_offset (gpDtb, "/chosen/i8253Config");
1.2.30 vxFdtCtrlNumGet
函数功能: 返回DTS中启用的控制器的编号
函数原型:int vxFdtCtrlNumGet(char compatName)