Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
a4485b54
Commit
a4485b54
authored
Jul 05, 2017
by
Rob Herring
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dt/property-move' into dt/next
parents
5e1743c0
b8ba92b1
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
850 additions
and
744 deletions
+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
No files found.
drivers/of/Makefile
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment