Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
a4485b54
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
a4485b54
编写于
7月 05, 2017
作者:
R
Rob Herring
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'dt/property-move' into dt/next
上级
5e1743c0
b8ba92b1
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
850 addition
and
744 deletion
+850
-744
drivers/of/Makefile
drivers/of/Makefile
+1
-1
drivers/of/base.c
drivers/of/base.c
+2
-733
drivers/of/property.c
drivers/of/property.c
+806
-0
include/linux/of.h
include/linux/of.h
+20
-10
include/linux/of_graph.h
include/linux/of_graph.h
+21
-0
未找到文件。
drivers/of/Makefile
浏览文件 @
a4485b54
obj-y
=
base.o device.o platform.o
obj-y
=
base.o device.o platform.o
property.o
obj-$(CONFIG_OF_DYNAMIC)
+=
dynamic.o
obj-$(CONFIG_OF_FLATTREE)
+=
fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE)
+=
fdt_address.o
...
...
drivers/of/base.c
浏览文件 @
a4485b54
...
...
@@ -1119,458 +1119,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL
(
of_find_node_by_phandle
);
/**
* of_property_count_elems_of_size - Count the number of elements in a property
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @elem_size: size of the individual element
*
* Search for a property in a device node and count the number of elements of
* size elem_size in it. Returns number of elements on sucess, -EINVAL if the
* property does not exist or its length does not match a multiple of elem_size
* and -ENODATA if the property does not have a value.
*/
int
of_property_count_elems_of_size
(
const
struct
device_node
*
np
,
const
char
*
propname
,
int
elem_size
)
{
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
if
(
prop
->
length
%
elem_size
!=
0
)
{
pr_err
(
"size of %s in node %s is not a multiple of %d
\n
"
,
propname
,
np
->
full_name
,
elem_size
);
return
-
EINVAL
;
}
return
prop
->
length
/
elem_size
;
}
EXPORT_SYMBOL_GPL
(
of_property_count_elems_of_size
);
/**
* of_find_property_value_of_size
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @min: minimum allowed length of property value
* @max: maximum allowed length of property value (0 means unlimited)
* @len: if !=NULL, actual length is written to here
*
* Search for a property in a device node and valid the requested size.
* Returns the property value on success, -EINVAL if the property does not
* exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data is too small or too large.
*
*/
static
void
*
of_find_property_value_of_size
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
min
,
u32
max
,
size_t
*
len
)
{
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
ERR_PTR
(
-
EINVAL
);
if
(
!
prop
->
value
)
return
ERR_PTR
(
-
ENODATA
);
if
(
prop
->
length
<
min
)
return
ERR_PTR
(
-
EOVERFLOW
);
if
(
max
&&
prop
->
length
>
max
)
return
ERR_PTR
(
-
EOVERFLOW
);
if
(
len
)
*
len
=
prop
->
length
;
return
prop
->
value
;
}
/**
* of_property_read_u32_index - Find and read a u32 from a multi-value property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the u32 in the list of values
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 32-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u32 value can be decoded.
*/
int
of_property_read_u32_index
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
index
,
u32
*
out_value
)
{
const
u32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
((
index
+
1
)
*
sizeof
(
*
out_value
)),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
be32_to_cpup
(((
__be32
*
)
val
)
+
index
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u32_index
);
/**
* of_property_read_u64_index - Find and read a u64 from a multi-value property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the u64 in the list of values
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 64-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_u64_index
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
index
,
u64
*
out_value
)
{
const
u64
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
((
index
+
1
)
*
sizeof
(
*
out_value
)),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
be64_to_cpup
(((
__be64
*
)
val
)
+
index
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u64_index
);
/**
* of_property_read_variable_u8_array - Find and read an array of u8 from a
* property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 8-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* dts entry of array should be like:
* property = /bits/ 8 <0x50 0x60 0x70>;
*
* The out_values is modified only if a valid u8 value can be decoded.
*/
int
of_property_read_variable_u8_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u8
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
u8
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
*
val
++
;
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u8_array
);
/**
* of_property_read_variable_u16_array - Find and read an array of u16 from a
* property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 16-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* dts entry of array should be like:
* property = /bits/ 16 <0x5000 0x6000 0x7000>;
*
* The out_values is modified only if a valid u16 value can be decoded.
*/
int
of_property_read_variable_u16_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u16
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be16
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
be16_to_cpup
(
val
++
);
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u16_array
);
/**
* of_property_read_variable_u32_array - Find and read an array of 32 bit
* integers from a property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 32-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u32 value can be decoded.
*/
int
of_property_read_variable_u32_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
be32_to_cpup
(
val
++
);
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u32_array
);
/**
* of_property_read_u64 - Find and read a 64 bit integer from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_value: pointer to return value, modified only if return value is 0.
*
* Search for a property in a device node and read a 64-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_u64
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u64
*
out_value
)
{
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
sizeof
(
*
out_value
),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
of_read_number
(
val
,
2
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u64
);
/**
* of_property_read_variable_u64_array - Find and read an array of 64 bit
* integers from a property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 64-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_variable_u64_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u64
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
{
*
out_values
++
=
of_read_number
(
val
,
2
);
val
+=
2
;
}
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u64_array
);
/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_string: pointer to null terminated return string, modified only if
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
* terminated string value (pointer to data, not a copy). Returns 0 on
* success, -EINVAL if the property does not exist, -ENODATA if property
* does not have a value, and -EILSEQ if the string is not null-terminated
* within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
int
of_property_read_string
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
**
out_string
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
if
(
strnlen
(
prop
->
value
,
prop
->
length
)
>=
prop
->
length
)
return
-
EILSEQ
;
*
out_string
=
prop
->
value
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_string
);
/**
* of_property_match_string() - Find string in a list and return index
* @np: pointer to node containing string list property
* @propname: string list property name
* @string: pointer to string to search for in string list
*
* This function searches a string list property and returns the index
* of a specific string value.
*/
int
of_property_match_string
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
*
string
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
size_t
l
;
int
i
;
const
char
*
p
,
*
end
;
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
p
=
prop
->
value
;
end
=
p
+
prop
->
length
;
for
(
i
=
0
;
p
<
end
;
i
++
,
p
+=
l
)
{
l
=
strnlen
(
p
,
end
-
p
)
+
1
;
if
(
p
+
l
>
end
)
return
-
EILSEQ
;
pr_debug
(
"comparing %s with %s
\n
"
,
string
,
p
);
if
(
strcmp
(
string
,
p
)
==
0
)
return
i
;
/* Found it; return index */
}
return
-
ENODATA
;
}
EXPORT_SYMBOL_GPL
(
of_property_match_string
);
/**
* of_property_read_string_helper() - Utility helper for parsing string properties
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
* @skip: Number of strings to skip over at beginning of list.
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.
*/
int
of_property_read_string_helper
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
**
out_strs
,
size_t
sz
,
int
skip
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
int
l
=
0
,
i
=
0
;
const
char
*
p
,
*
end
;
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
p
=
prop
->
value
;
end
=
p
+
prop
->
length
;
for
(
i
=
0
;
p
<
end
&&
(
!
out_strs
||
i
<
skip
+
sz
);
i
++
,
p
+=
l
)
{
l
=
strnlen
(
p
,
end
-
p
)
+
1
;
if
(
p
+
l
>
end
)
return
-
EILSEQ
;
if
(
out_strs
&&
i
>=
skip
)
*
out_strs
++
=
p
;
}
i
-=
skip
;
return
i
<=
0
?
-
ENODATA
:
i
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_string_helper
);
void
of_print_phandle_args
(
const
char
*
msg
,
const
struct
of_phandle_args
*
args
)
{
int
i
;
...
...
@@ -1607,6 +1155,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_phandle_iterator_init
);
int
of_phandle_iterator_next
(
struct
of_phandle_iterator
*
it
)
{
...
...
@@ -1676,6 +1225,7 @@ int of_phandle_iterator_next(struct of_phandle_iterator *it)
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
of_phandle_iterator_next
);
int
of_phandle_iterator_args
(
struct
of_phandle_iterator
*
it
,
uint32_t
*
args
,
...
...
@@ -2217,47 +1767,6 @@ int of_alias_get_highest_id(const char *stem)
}
EXPORT_SYMBOL_GPL
(
of_alias_get_highest_id
);
const
__be32
*
of_prop_next_u32
(
struct
property
*
prop
,
const
__be32
*
cur
,
u32
*
pu
)
{
const
void
*
curv
=
cur
;
if
(
!
prop
)
return
NULL
;
if
(
!
cur
)
{
curv
=
prop
->
value
;
goto
out_val
;
}
curv
+=
sizeof
(
*
cur
);
if
(
curv
>=
prop
->
value
+
prop
->
length
)
return
NULL
;
out_val:
*
pu
=
be32_to_cpup
(
curv
);
return
curv
;
}
EXPORT_SYMBOL_GPL
(
of_prop_next_u32
);
const
char
*
of_prop_next_string
(
struct
property
*
prop
,
const
char
*
cur
)
{
const
void
*
curv
=
cur
;
if
(
!
prop
)
return
NULL
;
if
(
!
cur
)
return
prop
->
value
;
curv
+=
strlen
(
cur
)
+
1
;
if
(
curv
>=
prop
->
value
+
prop
->
length
)
return
NULL
;
return
curv
;
}
EXPORT_SYMBOL_GPL
(
of_prop_next_string
);
/**
* of_console_check() - Test and setup console for DT setup
* @dn - Pointer to device node
...
...
@@ -2331,243 +1840,3 @@ int of_find_last_cache_level(unsigned int cpu)
return
cache_level
;
}
/**
* of_graph_parse_endpoint() - parse common endpoint node properties
* @node: pointer to endpoint device_node
* @endpoint: pointer to the OF endpoint data structure
*
* The caller should hold a reference to @node.
*/
int
of_graph_parse_endpoint
(
const
struct
device_node
*
node
,
struct
of_endpoint
*
endpoint
)
{
struct
device_node
*
port_node
=
of_get_parent
(
node
);
WARN_ONCE
(
!
port_node
,
"%s(): endpoint %s has no parent node
\n
"
,
__func__
,
node
->
full_name
);
memset
(
endpoint
,
0
,
sizeof
(
*
endpoint
));
endpoint
->
local_node
=
node
;
/*
* It doesn't matter whether the two calls below succeed.
* If they don't then the default value 0 is used.
*/
of_property_read_u32
(
port_node
,
"reg"
,
&
endpoint
->
port
);
of_property_read_u32
(
node
,
"reg"
,
&
endpoint
->
id
);
of_node_put
(
port_node
);
return
0
;
}
EXPORT_SYMBOL
(
of_graph_parse_endpoint
);
/**
* of_graph_get_port_by_id() - get the port matching a given id
* @parent: pointer to the parent device node
* @id: id of the port
*
* Return: A 'port' node pointer with refcount incremented. The caller
* has to use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
parent
,
u32
id
)
{
struct
device_node
*
node
,
*
port
;
node
=
of_get_child_by_name
(
parent
,
"ports"
);
if
(
node
)
parent
=
node
;
for_each_child_of_node
(
parent
,
port
)
{
u32
port_id
=
0
;
if
(
of_node_cmp
(
port
->
name
,
"port"
)
!=
0
)
continue
;
of_property_read_u32
(
port
,
"reg"
,
&
port_id
);
if
(
id
==
port_id
)
break
;
}
of_node_put
(
node
);
return
port
;
}
EXPORT_SYMBOL
(
of_graph_get_port_by_id
);
/**
* of_graph_get_next_endpoint() - get next endpoint node
* @parent: pointer to the parent device node
* @prev: previous endpoint node, or NULL to get first
*
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
* of the passed @prev node is decremented.
*/
struct
device_node
*
of_graph_get_next_endpoint
(
const
struct
device_node
*
parent
,
struct
device_node
*
prev
)
{
struct
device_node
*
endpoint
;
struct
device_node
*
port
;
if
(
!
parent
)
return
NULL
;
/*
* Start by locating the port node. If no previous endpoint is specified
* search for the first port node, otherwise get the previous endpoint
* parent port node.
*/
if
(
!
prev
)
{
struct
device_node
*
node
;
node
=
of_get_child_by_name
(
parent
,
"ports"
);
if
(
node
)
parent
=
node
;
port
=
of_get_child_by_name
(
parent
,
"port"
);
of_node_put
(
node
);
if
(
!
port
)
{
pr_err
(
"graph: no port node found in %s
\n
"
,
parent
->
full_name
);
return
NULL
;
}
}
else
{
port
=
of_get_parent
(
prev
);
if
(
WARN_ONCE
(
!
port
,
"%s(): endpoint %s has no parent node
\n
"
,
__func__
,
prev
->
full_name
))
return
NULL
;
}
while
(
1
)
{
/*
* Now that we have a port node, get the next endpoint by
* getting the next child. If the previous endpoint is NULL this
* will return the first child.
*/
endpoint
=
of_get_next_child
(
port
,
prev
);
if
(
endpoint
)
{
of_node_put
(
port
);
return
endpoint
;
}
/* No more endpoints under this port, try the next one. */
prev
=
NULL
;
do
{
port
=
of_get_next_child
(
parent
,
port
);
if
(
!
port
)
return
NULL
;
}
while
(
of_node_cmp
(
port
->
name
,
"port"
));
}
}
EXPORT_SYMBOL
(
of_graph_get_next_endpoint
);
/**
* of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
* @parent: pointer to the parent device node
* @port_reg: identifier (value of reg property) of the parent port node
* @reg: identifier (value of reg property) of the endpoint node
*
* Return: An 'endpoint' node pointer which is identified by reg and at the same
* is the child of a port node identified by port_reg. reg and port_reg are
* ignored when they are -1.
*/
struct
device_node
*
of_graph_get_endpoint_by_regs
(
const
struct
device_node
*
parent
,
int
port_reg
,
int
reg
)
{
struct
of_endpoint
endpoint
;
struct
device_node
*
node
=
NULL
;
for_each_endpoint_of_node
(
parent
,
node
)
{
of_graph_parse_endpoint
(
node
,
&
endpoint
);
if
(((
port_reg
==
-
1
)
||
(
endpoint
.
port
==
port_reg
))
&&
((
reg
==
-
1
)
||
(
endpoint
.
id
==
reg
)))
return
node
;
}
return
NULL
;
}
EXPORT_SYMBOL
(
of_graph_get_endpoint_by_regs
);
/**
* of_graph_get_remote_port_parent() - get remote port's parent node
* @node: pointer to a local endpoint device_node
*
* Return: Remote device node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
)
{
struct
device_node
*
np
;
unsigned
int
depth
;
/* Get remote endpoint node. */
np
=
of_parse_phandle
(
node
,
"remote-endpoint"
,
0
);
/* Walk 3 levels up only if there is 'ports' node. */
for
(
depth
=
3
;
depth
&&
np
;
depth
--
)
{
np
=
of_get_next_parent
(
np
);
if
(
depth
==
2
&&
of_node_cmp
(
np
->
name
,
"ports"
))
break
;
}
return
np
;
}
EXPORT_SYMBOL
(
of_graph_get_remote_port_parent
);
/**
* of_graph_get_remote_port() - get remote port node
* @node: pointer to a local endpoint device_node
*
* Return: Remote port node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_port
(
const
struct
device_node
*
node
)
{
struct
device_node
*
np
;
/* Get remote endpoint node. */
np
=
of_parse_phandle
(
node
,
"remote-endpoint"
,
0
);
if
(
!
np
)
return
NULL
;
return
of_get_next_parent
(
np
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_port
);
/**
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
* @node: pointer to parent device_node containing graph port/endpoint
* @port: identifier (value of reg property) of the parent port node
* @endpoint: identifier (value of reg property) of the endpoint node
*
* Return: Remote device node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_node
(
const
struct
device_node
*
node
,
u32
port
,
u32
endpoint
)
{
struct
device_node
*
endpoint_node
,
*
remote
;
endpoint_node
=
of_graph_get_endpoint_by_regs
(
node
,
port
,
endpoint
);
if
(
!
endpoint_node
)
{
pr_debug
(
"no valid endpoint (%d, %d) for node %s
\n
"
,
port
,
endpoint
,
node
->
full_name
);
return
NULL
;
}
remote
=
of_graph_get_remote_port_parent
(
endpoint_node
);
of_node_put
(
endpoint_node
);
if
(
!
remote
)
{
pr_debug
(
"no valid remote node
\n
"
);
return
NULL
;
}
if
(
!
of_device_is_available
(
remote
))
{
pr_debug
(
"not available for remote node
\n
"
);
return
NULL
;
}
return
remote
;
}
EXPORT_SYMBOL
(
of_graph_get_remote_node
);
drivers/of/property.c
0 → 100644
浏览文件 @
a4485b54
/*
* drivers/of/property.c - Procedures for accessing and interpreting
* Devicetree properties and graphs.
*
* Initially created by copying procedures from drivers/of/base.c. This
* file contains the OF property as well as the OF graph interface
* functions.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
*
* Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
* Grant Likely.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) "OF: " fmt
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/string.h>
#include "of_private.h"
/**
* of_property_count_elems_of_size - Count the number of elements in a property
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @elem_size: size of the individual element
*
* Search for a property in a device node and count the number of elements of
* size elem_size in it. Returns number of elements on sucess, -EINVAL if the
* property does not exist or its length does not match a multiple of elem_size
* and -ENODATA if the property does not have a value.
*/
int
of_property_count_elems_of_size
(
const
struct
device_node
*
np
,
const
char
*
propname
,
int
elem_size
)
{
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
if
(
prop
->
length
%
elem_size
!=
0
)
{
pr_err
(
"size of %s in node %s is not a multiple of %d
\n
"
,
propname
,
np
->
full_name
,
elem_size
);
return
-
EINVAL
;
}
return
prop
->
length
/
elem_size
;
}
EXPORT_SYMBOL_GPL
(
of_property_count_elems_of_size
);
/**
* of_find_property_value_of_size
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @min: minimum allowed length of property value
* @max: maximum allowed length of property value (0 means unlimited)
* @len: if !=NULL, actual length is written to here
*
* Search for a property in a device node and valid the requested size.
* Returns the property value on success, -EINVAL if the property does not
* exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data is too small or too large.
*
*/
static
void
*
of_find_property_value_of_size
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
min
,
u32
max
,
size_t
*
len
)
{
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
ERR_PTR
(
-
EINVAL
);
if
(
!
prop
->
value
)
return
ERR_PTR
(
-
ENODATA
);
if
(
prop
->
length
<
min
)
return
ERR_PTR
(
-
EOVERFLOW
);
if
(
max
&&
prop
->
length
>
max
)
return
ERR_PTR
(
-
EOVERFLOW
);
if
(
len
)
*
len
=
prop
->
length
;
return
prop
->
value
;
}
/**
* of_property_read_u32_index - Find and read a u32 from a multi-value property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the u32 in the list of values
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 32-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u32 value can be decoded.
*/
int
of_property_read_u32_index
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
index
,
u32
*
out_value
)
{
const
u32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
((
index
+
1
)
*
sizeof
(
*
out_value
)),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
be32_to_cpup
(((
__be32
*
)
val
)
+
index
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u32_index
);
/**
* of_property_read_u64_index - Find and read a u64 from a multi-value property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the u64 in the list of values
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 64-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_u64_index
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
index
,
u64
*
out_value
)
{
const
u64
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
((
index
+
1
)
*
sizeof
(
*
out_value
)),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
be64_to_cpup
(((
__be64
*
)
val
)
+
index
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u64_index
);
/**
* of_property_read_variable_u8_array - Find and read an array of u8 from a
* property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 8-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* dts entry of array should be like:
* property = /bits/ 8 <0x50 0x60 0x70>;
*
* The out_values is modified only if a valid u8 value can be decoded.
*/
int
of_property_read_variable_u8_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u8
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
u8
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
*
val
++
;
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u8_array
);
/**
* of_property_read_variable_u16_array - Find and read an array of u16 from a
* property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 16-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* dts entry of array should be like:
* property = /bits/ 16 <0x5000 0x6000 0x7000>;
*
* The out_values is modified only if a valid u16 value can be decoded.
*/
int
of_property_read_variable_u16_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u16
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be16
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
be16_to_cpup
(
val
++
);
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u16_array
);
/**
* of_property_read_variable_u32_array - Find and read an array of 32 bit
* integers from a property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 32-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u32 value can be decoded.
*/
int
of_property_read_variable_u32_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u32
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
*
out_values
++
=
be32_to_cpup
(
val
++
);
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u32_array
);
/**
* of_property_read_u64 - Find and read a 64 bit integer from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_value: pointer to return value, modified only if return value is 0.
*
* Search for a property in a device node and read a 64-bit value from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_u64
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u64
*
out_value
)
{
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
sizeof
(
*
out_value
),
0
,
NULL
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
*
out_value
=
of_read_number
(
val
,
2
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_u64
);
/**
* of_property_read_variable_u64_array - Find and read an array of 64 bit
* integers from a property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 64-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* The out_values is modified only if a valid u64 value can be decoded.
*/
int
of_property_read_variable_u64_array
(
const
struct
device_node
*
np
,
const
char
*
propname
,
u64
*
out_values
,
size_t
sz_min
,
size_t
sz_max
)
{
size_t
sz
,
count
;
const
__be32
*
val
=
of_find_property_value_of_size
(
np
,
propname
,
(
sz_min
*
sizeof
(
*
out_values
)),
(
sz_max
*
sizeof
(
*
out_values
)),
&
sz
);
if
(
IS_ERR
(
val
))
return
PTR_ERR
(
val
);
if
(
!
sz_max
)
sz
=
sz_min
;
else
sz
/=
sizeof
(
*
out_values
);
count
=
sz
;
while
(
count
--
)
{
*
out_values
++
=
of_read_number
(
val
,
2
);
val
+=
2
;
}
return
sz
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_variable_u64_array
);
/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_string: pointer to null terminated return string, modified only if
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
* terminated string value (pointer to data, not a copy). Returns 0 on
* success, -EINVAL if the property does not exist, -ENODATA if property
* does not have a value, and -EILSEQ if the string is not null-terminated
* within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
int
of_property_read_string
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
**
out_string
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
if
(
strnlen
(
prop
->
value
,
prop
->
length
)
>=
prop
->
length
)
return
-
EILSEQ
;
*
out_string
=
prop
->
value
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_string
);
/**
* of_property_match_string() - Find string in a list and return index
* @np: pointer to node containing string list property
* @propname: string list property name
* @string: pointer to string to search for in string list
*
* This function searches a string list property and returns the index
* of a specific string value.
*/
int
of_property_match_string
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
*
string
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
size_t
l
;
int
i
;
const
char
*
p
,
*
end
;
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
p
=
prop
->
value
;
end
=
p
+
prop
->
length
;
for
(
i
=
0
;
p
<
end
;
i
++
,
p
+=
l
)
{
l
=
strnlen
(
p
,
end
-
p
)
+
1
;
if
(
p
+
l
>
end
)
return
-
EILSEQ
;
pr_debug
(
"comparing %s with %s
\n
"
,
string
,
p
);
if
(
strcmp
(
string
,
p
)
==
0
)
return
i
;
/* Found it; return index */
}
return
-
ENODATA
;
}
EXPORT_SYMBOL_GPL
(
of_property_match_string
);
/**
* of_property_read_string_helper() - Utility helper for parsing string properties
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
* @skip: Number of strings to skip over at beginning of list.
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.
*/
int
of_property_read_string_helper
(
const
struct
device_node
*
np
,
const
char
*
propname
,
const
char
**
out_strs
,
size_t
sz
,
int
skip
)
{
const
struct
property
*
prop
=
of_find_property
(
np
,
propname
,
NULL
);
int
l
=
0
,
i
=
0
;
const
char
*
p
,
*
end
;
if
(
!
prop
)
return
-
EINVAL
;
if
(
!
prop
->
value
)
return
-
ENODATA
;
p
=
prop
->
value
;
end
=
p
+
prop
->
length
;
for
(
i
=
0
;
p
<
end
&&
(
!
out_strs
||
i
<
skip
+
sz
);
i
++
,
p
+=
l
)
{
l
=
strnlen
(
p
,
end
-
p
)
+
1
;
if
(
p
+
l
>
end
)
return
-
EILSEQ
;
if
(
out_strs
&&
i
>=
skip
)
*
out_strs
++
=
p
;
}
i
-=
skip
;
return
i
<=
0
?
-
ENODATA
:
i
;
}
EXPORT_SYMBOL_GPL
(
of_property_read_string_helper
);
const
__be32
*
of_prop_next_u32
(
struct
property
*
prop
,
const
__be32
*
cur
,
u32
*
pu
)
{
const
void
*
curv
=
cur
;
if
(
!
prop
)
return
NULL
;
if
(
!
cur
)
{
curv
=
prop
->
value
;
goto
out_val
;
}
curv
+=
sizeof
(
*
cur
);
if
(
curv
>=
prop
->
value
+
prop
->
length
)
return
NULL
;
out_val:
*
pu
=
be32_to_cpup
(
curv
);
return
curv
;
}
EXPORT_SYMBOL_GPL
(
of_prop_next_u32
);
const
char
*
of_prop_next_string
(
struct
property
*
prop
,
const
char
*
cur
)
{
const
void
*
curv
=
cur
;
if
(
!
prop
)
return
NULL
;
if
(
!
cur
)
return
prop
->
value
;
curv
+=
strlen
(
cur
)
+
1
;
if
(
curv
>=
prop
->
value
+
prop
->
length
)
return
NULL
;
return
curv
;
}
EXPORT_SYMBOL_GPL
(
of_prop_next_string
);
/**
* of_graph_parse_endpoint() - parse common endpoint node properties
* @node: pointer to endpoint device_node
* @endpoint: pointer to the OF endpoint data structure
*
* The caller should hold a reference to @node.
*/
int
of_graph_parse_endpoint
(
const
struct
device_node
*
node
,
struct
of_endpoint
*
endpoint
)
{
struct
device_node
*
port_node
=
of_get_parent
(
node
);
WARN_ONCE
(
!
port_node
,
"%s(): endpoint %s has no parent node
\n
"
,
__func__
,
node
->
full_name
);
memset
(
endpoint
,
0
,
sizeof
(
*
endpoint
));
endpoint
->
local_node
=
node
;
/*
* It doesn't matter whether the two calls below succeed.
* If they don't then the default value 0 is used.
*/
of_property_read_u32
(
port_node
,
"reg"
,
&
endpoint
->
port
);
of_property_read_u32
(
node
,
"reg"
,
&
endpoint
->
id
);
of_node_put
(
port_node
);
return
0
;
}
EXPORT_SYMBOL
(
of_graph_parse_endpoint
);
/**
* of_graph_get_port_by_id() - get the port matching a given id
* @parent: pointer to the parent device node
* @id: id of the port
*
* Return: A 'port' node pointer with refcount incremented. The caller
* has to use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
parent
,
u32
id
)
{
struct
device_node
*
node
,
*
port
;
node
=
of_get_child_by_name
(
parent
,
"ports"
);
if
(
node
)
parent
=
node
;
for_each_child_of_node
(
parent
,
port
)
{
u32
port_id
=
0
;
if
(
of_node_cmp
(
port
->
name
,
"port"
)
!=
0
)
continue
;
of_property_read_u32
(
port
,
"reg"
,
&
port_id
);
if
(
id
==
port_id
)
break
;
}
of_node_put
(
node
);
return
port
;
}
EXPORT_SYMBOL
(
of_graph_get_port_by_id
);
/**
* of_graph_get_next_endpoint() - get next endpoint node
* @parent: pointer to the parent device node
* @prev: previous endpoint node, or NULL to get first
*
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
* of the passed @prev node is decremented.
*/
struct
device_node
*
of_graph_get_next_endpoint
(
const
struct
device_node
*
parent
,
struct
device_node
*
prev
)
{
struct
device_node
*
endpoint
;
struct
device_node
*
port
;
if
(
!
parent
)
return
NULL
;
/*
* Start by locating the port node. If no previous endpoint is specified
* search for the first port node, otherwise get the previous endpoint
* parent port node.
*/
if
(
!
prev
)
{
struct
device_node
*
node
;
node
=
of_get_child_by_name
(
parent
,
"ports"
);
if
(
node
)
parent
=
node
;
port
=
of_get_child_by_name
(
parent
,
"port"
);
of_node_put
(
node
);
if
(
!
port
)
{
pr_err
(
"graph: no port node found in %s
\n
"
,
parent
->
full_name
);
return
NULL
;
}
}
else
{
port
=
of_get_parent
(
prev
);
if
(
WARN_ONCE
(
!
port
,
"%s(): endpoint %s has no parent node
\n
"
,
__func__
,
prev
->
full_name
))
return
NULL
;
}
while
(
1
)
{
/*
* Now that we have a port node, get the next endpoint by
* getting the next child. If the previous endpoint is NULL this
* will return the first child.
*/
endpoint
=
of_get_next_child
(
port
,
prev
);
if
(
endpoint
)
{
of_node_put
(
port
);
return
endpoint
;
}
/* No more endpoints under this port, try the next one. */
prev
=
NULL
;
do
{
port
=
of_get_next_child
(
parent
,
port
);
if
(
!
port
)
return
NULL
;
}
while
(
of_node_cmp
(
port
->
name
,
"port"
));
}
}
EXPORT_SYMBOL
(
of_graph_get_next_endpoint
);
/**
* of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
* @parent: pointer to the parent device node
* @port_reg: identifier (value of reg property) of the parent port node
* @reg: identifier (value of reg property) of the endpoint node
*
* Return: An 'endpoint' node pointer which is identified by reg and at the same
* is the child of a port node identified by port_reg. reg and port_reg are
* ignored when they are -1.
*/
struct
device_node
*
of_graph_get_endpoint_by_regs
(
const
struct
device_node
*
parent
,
int
port_reg
,
int
reg
)
{
struct
of_endpoint
endpoint
;
struct
device_node
*
node
=
NULL
;
for_each_endpoint_of_node
(
parent
,
node
)
{
of_graph_parse_endpoint
(
node
,
&
endpoint
);
if
(((
port_reg
==
-
1
)
||
(
endpoint
.
port
==
port_reg
))
&&
((
reg
==
-
1
)
||
(
endpoint
.
id
==
reg
)))
return
node
;
}
return
NULL
;
}
EXPORT_SYMBOL
(
of_graph_get_endpoint_by_regs
);
/**
* of_graph_get_remote_endpoint() - get remote endpoint node
* @node: pointer to a local endpoint device_node
*
* Return: Remote endpoint node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
)
{
/* Get remote endpoint node. */
return
of_parse_phandle
(
node
,
"remote-endpoint"
,
0
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_endpoint
);
/**
* of_graph_get_port_parent() - get port's parent node
* @node: pointer to a local endpoint device_node
*
* Return: device node associated with endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
)
{
unsigned
int
depth
;
/* Walk 3 levels up only if there is 'ports' node. */
for
(
depth
=
3
;
depth
&&
node
;
depth
--
)
{
node
=
of_get_next_parent
(
node
);
if
(
depth
==
2
&&
of_node_cmp
(
node
->
name
,
"ports"
))
break
;
}
return
node
;
}
EXPORT_SYMBOL
(
of_graph_get_port_parent
);
/**
* of_graph_get_remote_port_parent() - get remote port's parent node
* @node: pointer to a local endpoint device_node
*
* Return: Remote device node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
)
{
struct
device_node
*
np
;
/* Get remote endpoint node. */
np
=
of_graph_get_remote_endpoint
(
node
);
return
of_graph_get_port_parent
(
np
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_port_parent
);
/**
* of_graph_get_remote_port() - get remote port node
* @node: pointer to a local endpoint device_node
*
* Return: Remote port node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_port
(
const
struct
device_node
*
node
)
{
struct
device_node
*
np
;
/* Get remote endpoint node. */
np
=
of_graph_get_remote_endpoint
(
node
);
if
(
!
np
)
return
NULL
;
return
of_get_next_parent
(
np
);
}
EXPORT_SYMBOL
(
of_graph_get_remote_port
);
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
)
{
struct
device_node
*
endpoint
;
int
num
=
0
;
for_each_endpoint_of_node
(
np
,
endpoint
)
num
++
;
return
num
;
}
EXPORT_SYMBOL
(
of_graph_get_endpoint_count
);
/**
* of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
* @node: pointer to parent device_node containing graph port/endpoint
* @port: identifier (value of reg property) of the parent port node
* @endpoint: identifier (value of reg property) of the endpoint node
*
* Return: Remote device node associated with remote endpoint node linked
* to @node. Use of_node_put() on it when done.
*/
struct
device_node
*
of_graph_get_remote_node
(
const
struct
device_node
*
node
,
u32
port
,
u32
endpoint
)
{
struct
device_node
*
endpoint_node
,
*
remote
;
endpoint_node
=
of_graph_get_endpoint_by_regs
(
node
,
port
,
endpoint
);
if
(
!
endpoint_node
)
{
pr_debug
(
"no valid endpoint (%d, %d) for node %s
\n
"
,
port
,
endpoint
,
node
->
full_name
);
return
NULL
;
}
remote
=
of_graph_get_remote_port_parent
(
endpoint_node
);
of_node_put
(
endpoint_node
);
if
(
!
remote
)
{
pr_debug
(
"no valid remote node
\n
"
);
return
NULL
;
}
if
(
!
of_device_is_available
(
remote
))
{
pr_debug
(
"not available for remote node
\n
"
);
return
NULL
;
}
return
remote
;
}
EXPORT_SYMBOL
(
of_graph_get_remote_node
);
include/linux/of.h
浏览文件 @
a4485b54
...
...
@@ -148,18 +148,28 @@ extern raw_spinlock_t devtree_lock;
#ifdef CONFIG_OF
void
of_core_init
(
void
);
static
inline
bool
is_of_node
(
struct
fwnode_handle
*
fwnode
)
static
inline
bool
is_of_node
(
const
struct
fwnode_handle
*
fwnode
)
{
return
!
IS_ERR_OR_NULL
(
fwnode
)
&&
fwnode
->
type
==
FWNODE_OF
;
}
static
inline
struct
device_node
*
to_of_node
(
struct
fwnode_handle
*
fwnode
)
{
return
is_of_node
(
fwnode
)
?
container_of
(
fwnode
,
struct
device_node
,
fwnode
)
:
NULL
;
}
#define of_fwnode_handle(node) (&(node)->fwnode)
#define to_of_node(__fwnode) \
({ \
typeof(__fwnode) __to_of_node_fwnode = (__fwnode); \
\
is_of_node(__to_of_node_fwnode) ? \
container_of(__to_of_node_fwnode, \
struct device_node, fwnode) : \
NULL; \
})
#define of_fwnode_handle(node) \
({ \
typeof(node) __of_fwnode_handle_node = (node); \
\
__of_fwnode_handle_node ? \
&__of_fwnode_handle_node->fwnode : NULL; \
})
static
inline
bool
of_have_populated_dt
(
void
)
{
...
...
@@ -533,12 +543,12 @@ static inline void of_core_init(void)
{
}
static
inline
bool
is_of_node
(
struct
fwnode_handle
*
fwnode
)
static
inline
bool
is_of_node
(
const
struct
fwnode_handle
*
fwnode
)
{
return
false
;
}
static
inline
struct
device_node
*
to_of_node
(
struct
fwnode_handle
*
fwnode
)
static
inline
struct
device_node
*
to_of_node
(
const
struct
fwnode_handle
*
fwnode
)
{
return
NULL
;
}
...
...
include/linux/of_graph.h
浏览文件 @
a4485b54
...
...
@@ -43,11 +43,15 @@ struct of_endpoint {
#ifdef CONFIG_OF
int
of_graph_parse_endpoint
(
const
struct
device_node
*
node
,
struct
of_endpoint
*
endpoint
);
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
);
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
node
,
u32
id
);
struct
device_node
*
of_graph_get_next_endpoint
(
const
struct
device_node
*
parent
,
struct
device_node
*
previous
);
struct
device_node
*
of_graph_get_endpoint_by_regs
(
const
struct
device_node
*
parent
,
int
port_reg
,
int
reg
);
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
);
struct
device_node
*
of_graph_get_remote_port
(
const
struct
device_node
*
node
);
...
...
@@ -61,6 +65,11 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
return
-
ENOSYS
;
}
static
inline
int
of_graph_get_endpoint_count
(
const
struct
device_node
*
np
)
{
return
0
;
}
static
inline
struct
device_node
*
of_graph_get_port_by_id
(
struct
device_node
*
node
,
u32
id
)
{
...
...
@@ -80,6 +89,18 @@ static inline struct device_node *of_graph_get_endpoint_by_regs(
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_remote_endpoint
(
const
struct
device_node
*
node
)
{
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_port_parent
(
struct
device_node
*
node
)
{
return
NULL
;
}
static
inline
struct
device_node
*
of_graph_get_remote_port_parent
(
const
struct
device_node
*
node
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录