mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
Merge tag 'devicetree-fixes-for-5.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree fixes from Rob Herring: - Fix fw_devlink failure with ".*,nr-gpios" properties - Doc link reference fixes from Mauro - Fixes for unaligned FDT handling found on OpenRisc. First, avoid crash with better error handling when unflattening an unaligned FDT. Second, fix memory allocations for FDTs to ensure alignment. * tag 'devicetree-fixes-for-5.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: of: property: fw_devlink: do not link ".*,nr-gpios" dt-bindings:iio:adc: update motorola,cpcap-adc.yaml reference dt-bindings: fix references for iio-bindings.txt dt-bindings: don't use ../dir for doc references of: unittest: overlay: ensure proper alignment of copied FDT of: properly check for error returned by fdt_get_name()
This commit is contained in:
@@ -32,7 +32,7 @@ Optional node properties:
|
|||||||
- "#thermal-sensor-cells" Used to expose itself to thermal fw.
|
- "#thermal-sensor-cells" Used to expose itself to thermal fw.
|
||||||
|
|
||||||
Read more about iio bindings at
|
Read more about iio bindings at
|
||||||
Documentation/devicetree/bindings/iio/iio-bindings.txt
|
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
ncp15wb473@0 {
|
ncp15wb473@0 {
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ description: >
|
|||||||
Industrial I/O subsystem bindings for ADC controller found in
|
Industrial I/O subsystem bindings for ADC controller found in
|
||||||
Ingenic JZ47xx SoCs.
|
Ingenic JZ47xx SoCs.
|
||||||
|
|
||||||
ADC clients must use the format described in iio-bindings.txt, giving
|
ADC clients must use the format described in
|
||||||
a phandle and IIO specifier pair ("io-channels") to the ADC controller.
|
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/iio-consumer.yaml,
|
||||||
|
giving a phandle and IIO specifier pair ("io-channels") to the ADC controller.
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ properties:
|
|||||||
description: >
|
description: >
|
||||||
List of phandle and IIO specifier pairs.
|
List of phandle and IIO specifier pairs.
|
||||||
Each pair defines one ADC channel to which a joystick axis is connected.
|
Each pair defines one ADC channel to which a joystick axis is connected.
|
||||||
See Documentation/devicetree/bindings/iio/iio-bindings.txt for details.
|
See
|
||||||
|
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/iio-consumer.yaml
|
||||||
|
for details.
|
||||||
|
|
||||||
'#address-cells':
|
'#address-cells':
|
||||||
const: 1
|
const: 1
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ Required properties:
|
|||||||
- compatible: must be "resistive-adc-touch"
|
- compatible: must be "resistive-adc-touch"
|
||||||
The device must be connected to an ADC device that provides channels for
|
The device must be connected to an ADC device that provides channels for
|
||||||
position measurement and optional pressure.
|
position measurement and optional pressure.
|
||||||
Refer to ../iio/iio-bindings.txt for details
|
Refer to
|
||||||
|
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/iio-consumer.yaml
|
||||||
|
for details
|
||||||
|
|
||||||
- iio-channels: must have at least two channels connected to an ADC device.
|
- iio-channels: must have at least two channels connected to an ADC device.
|
||||||
These should correspond to the channels exposed by the ADC device and should
|
These should correspond to the channels exposed by the ADC device and should
|
||||||
have the right index as the ADC device registers them. These channels
|
have the right index as the ADC device registers them. These channels
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ Required child device properties:
|
|||||||
pwm|regulator|rtc|sysctrl|usb]";
|
pwm|regulator|rtc|sysctrl|usb]";
|
||||||
|
|
||||||
A few child devices require ADC channels from the GPADC node. Those follow the
|
A few child devices require ADC channels from the GPADC node. Those follow the
|
||||||
standard bindings from iio/iio-bindings.txt and iio/adc/adc.txt
|
standard bindings from
|
||||||
|
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/iio-consumer.yaml
|
||||||
|
and Documentation/devicetree/bindings/iio/adc/adc.yaml
|
||||||
|
|
||||||
abx500-temp : io-channels "aux1" and "aux2" for measuring external
|
abx500-temp : io-channels "aux1" and "aux2" for measuring external
|
||||||
temperatures.
|
temperatures.
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ Optional subnodes:
|
|||||||
The sub-functions of CPCAP get their own node with their own compatible values,
|
The sub-functions of CPCAP get their own node with their own compatible values,
|
||||||
which are described in the following files:
|
which are described in the following files:
|
||||||
|
|
||||||
- ../power/supply/cpcap-battery.txt
|
- Documentation/devicetree/bindings/power/supply/cpcap-battery.txt
|
||||||
- ../power/supply/cpcap-charger.txt
|
- Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
|
||||||
- ../regulator/cpcap-regulator.txt
|
- Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
|
||||||
- ../phy/phy-cpcap-usb.txt
|
- Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt
|
||||||
- ../input/cpcap-pwrbutton.txt
|
- Documentation/devicetree/bindings/input/cpcap-pwrbutton.txt
|
||||||
- ../rtc/cpcap-rtc.txt
|
- Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
|
||||||
- ../leds/leds-cpcap.txt
|
- Documentation/devicetree/bindings/leds/leds-cpcap.txt
|
||||||
- ../iio/adc/cpcap-adc.txt
|
- Documentation/devicetree/bindings/iio/adc/motorola,cpcap-adc.yaml
|
||||||
|
|
||||||
The only exception is the audio codec. Instead of a compatible value its
|
The only exception is the audio codec. Instead of a compatible value its
|
||||||
node must be named "audio-codec".
|
node must be named "audio-codec".
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ static void populate_properties(const void *blob,
|
|||||||
*pprev = NULL;
|
*pprev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool populate_node(const void *blob,
|
static int populate_node(const void *blob,
|
||||||
int offset,
|
int offset,
|
||||||
void **mem,
|
void **mem,
|
||||||
struct device_node *dad,
|
struct device_node *dad,
|
||||||
@@ -214,24 +214,24 @@ static bool populate_node(const void *blob,
|
|||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
const char *pathp;
|
const char *pathp;
|
||||||
unsigned int l, allocl;
|
int len;
|
||||||
|
|
||||||
pathp = fdt_get_name(blob, offset, &l);
|
pathp = fdt_get_name(blob, offset, &len);
|
||||||
if (!pathp) {
|
if (!pathp) {
|
||||||
*pnp = NULL;
|
*pnp = NULL;
|
||||||
return false;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocl = ++l;
|
len++;
|
||||||
|
|
||||||
np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
|
np = unflatten_dt_alloc(mem, sizeof(struct device_node) + len,
|
||||||
__alignof__(struct device_node));
|
__alignof__(struct device_node));
|
||||||
if (!dryrun) {
|
if (!dryrun) {
|
||||||
char *fn;
|
char *fn;
|
||||||
of_node_init(np);
|
of_node_init(np);
|
||||||
np->full_name = fn = ((char *)np) + sizeof(*np);
|
np->full_name = fn = ((char *)np) + sizeof(*np);
|
||||||
|
|
||||||
memcpy(fn, pathp, l);
|
memcpy(fn, pathp, len);
|
||||||
|
|
||||||
if (dad != NULL) {
|
if (dad != NULL) {
|
||||||
np->parent = dad;
|
np->parent = dad;
|
||||||
@@ -295,6 +295,7 @@ static int unflatten_dt_nodes(const void *blob,
|
|||||||
struct device_node *nps[FDT_MAX_DEPTH];
|
struct device_node *nps[FDT_MAX_DEPTH];
|
||||||
void *base = mem;
|
void *base = mem;
|
||||||
bool dryrun = !base;
|
bool dryrun = !base;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (nodepp)
|
if (nodepp)
|
||||||
*nodepp = NULL;
|
*nodepp = NULL;
|
||||||
@@ -322,9 +323,10 @@ static int unflatten_dt_nodes(const void *blob,
|
|||||||
!of_fdt_device_is_available(blob, offset))
|
!of_fdt_device_is_available(blob, offset))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!populate_node(blob, offset, &mem, nps[depth],
|
ret = populate_node(blob, offset, &mem, nps[depth],
|
||||||
&nps[depth+1], dryrun))
|
&nps[depth+1], dryrun);
|
||||||
return mem - base;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (!dryrun && nodepp && !*nodepp)
|
if (!dryrun && nodepp && !*nodepp)
|
||||||
*nodepp = nps[depth+1];
|
*nodepp = nps[depth+1];
|
||||||
@@ -372,6 +374,10 @@ void *__unflatten_device_tree(const void *blob,
|
|||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
void *mem;
|
void *mem;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mynodes)
|
||||||
|
*mynodes = NULL;
|
||||||
|
|
||||||
pr_debug(" -> unflatten_device_tree()\n");
|
pr_debug(" -> unflatten_device_tree()\n");
|
||||||
|
|
||||||
@@ -392,7 +398,7 @@ void *__unflatten_device_tree(const void *blob,
|
|||||||
|
|
||||||
/* First pass, scan for size */
|
/* First pass, scan for size */
|
||||||
size = unflatten_dt_nodes(blob, NULL, dad, NULL);
|
size = unflatten_dt_nodes(blob, NULL, dad, NULL);
|
||||||
if (size < 0)
|
if (size <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
size = ALIGN(size, 4);
|
size = ALIGN(size, 4);
|
||||||
@@ -410,12 +416,16 @@ void *__unflatten_device_tree(const void *blob,
|
|||||||
pr_debug(" unflattening %p...\n", mem);
|
pr_debug(" unflattening %p...\n", mem);
|
||||||
|
|
||||||
/* Second pass, do actual unflattening */
|
/* Second pass, do actual unflattening */
|
||||||
unflatten_dt_nodes(blob, mem, dad, mynodes);
|
ret = unflatten_dt_nodes(blob, mem, dad, mynodes);
|
||||||
|
|
||||||
if (be32_to_cpup(mem + size) != 0xdeadbeef)
|
if (be32_to_cpup(mem + size) != 0xdeadbeef)
|
||||||
pr_warn("End of tree marker overwritten: %08x\n",
|
pr_warn("End of tree marker overwritten: %08x\n",
|
||||||
be32_to_cpup(mem + size));
|
be32_to_cpup(mem + size));
|
||||||
|
|
||||||
if (detached && mynodes) {
|
if (ret <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (detached && mynodes && *mynodes) {
|
||||||
of_node_set_flag(*mynodes, OF_DETACHED);
|
of_node_set_flag(*mynodes, OF_DETACHED);
|
||||||
pr_debug("unflattened tree is detached\n");
|
pr_debug("unflattened tree is detached\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
* Copyright (C) 1996-2005 Paul Mackerras.
|
* Copyright (C) 1996-2005 Paul Mackerras.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FDT_ALIGN_SIZE 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct alias_prop - Alias property in 'aliases' node
|
* struct alias_prop - Alias property in 'aliases' node
|
||||||
* @link: List node to link the structure in aliases_lookup list
|
* @link: List node to link the structure in aliases_lookup list
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ struct fragment {
|
|||||||
* struct overlay_changeset
|
* struct overlay_changeset
|
||||||
* @id: changeset identifier
|
* @id: changeset identifier
|
||||||
* @ovcs_list: list on which we are located
|
* @ovcs_list: list on which we are located
|
||||||
* @fdt: FDT that was unflattened to create @overlay_tree
|
* @fdt: base of memory allocated to hold aligned FDT that was unflattened to create @overlay_tree
|
||||||
* @overlay_tree: expanded device tree that contains the fragment nodes
|
* @overlay_tree: expanded device tree that contains the fragment nodes
|
||||||
* @count: count of fragment structures
|
* @count: count of fragment structures
|
||||||
* @fragments: fragment nodes in the overlay expanded device tree
|
* @fragments: fragment nodes in the overlay expanded device tree
|
||||||
@@ -719,8 +719,8 @@ static struct device_node *find_target(struct device_node *info_node)
|
|||||||
/**
|
/**
|
||||||
* init_overlay_changeset() - initialize overlay changeset from overlay tree
|
* init_overlay_changeset() - initialize overlay changeset from overlay tree
|
||||||
* @ovcs: Overlay changeset to build
|
* @ovcs: Overlay changeset to build
|
||||||
* @fdt: the FDT that was unflattened to create @tree
|
* @fdt: base of memory allocated to hold aligned FDT that was unflattened to create @tree
|
||||||
* @tree: Contains all the overlay fragments and overlay fixup nodes
|
* @tree: Contains the overlay fragments and overlay fixup nodes
|
||||||
*
|
*
|
||||||
* Initialize @ovcs. Populate @ovcs->fragments with node information from
|
* Initialize @ovcs. Populate @ovcs->fragments with node information from
|
||||||
* the top level of @tree. The relevant top level nodes are the fragment
|
* the top level of @tree. The relevant top level nodes are the fragment
|
||||||
@@ -873,7 +873,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
|
|||||||
* internal documentation
|
* internal documentation
|
||||||
*
|
*
|
||||||
* of_overlay_apply() - Create and apply an overlay changeset
|
* of_overlay_apply() - Create and apply an overlay changeset
|
||||||
* @fdt: the FDT that was unflattened to create @tree
|
* @fdt: base of memory allocated to hold the aligned FDT
|
||||||
* @tree: Expanded overlay device tree
|
* @tree: Expanded overlay device tree
|
||||||
* @ovcs_id: Pointer to overlay changeset id
|
* @ovcs_id: Pointer to overlay changeset id
|
||||||
*
|
*
|
||||||
@@ -953,7 +953,9 @@ static int of_overlay_apply(const void *fdt, struct device_node *tree,
|
|||||||
/*
|
/*
|
||||||
* after overlay_notify(), ovcs->overlay_tree related pointers may have
|
* after overlay_notify(), ovcs->overlay_tree related pointers may have
|
||||||
* leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree;
|
* leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree;
|
||||||
* and can not free fdt, aka ovcs->fdt
|
* and can not free memory containing aligned fdt. The aligned fdt
|
||||||
|
* is contained within the memory at ovcs->fdt, possibly at an offset
|
||||||
|
* from ovcs->fdt.
|
||||||
*/
|
*/
|
||||||
ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
|
ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -1014,10 +1016,11 @@ out:
|
|||||||
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
|
int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
|
||||||
int *ovcs_id)
|
int *ovcs_id)
|
||||||
{
|
{
|
||||||
const void *new_fdt;
|
void *new_fdt;
|
||||||
|
void *new_fdt_align;
|
||||||
int ret;
|
int ret;
|
||||||
u32 size;
|
u32 size;
|
||||||
struct device_node *overlay_root;
|
struct device_node *overlay_root = NULL;
|
||||||
|
|
||||||
*ovcs_id = 0;
|
*ovcs_id = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -1036,11 +1039,14 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
|
|||||||
* Must create permanent copy of FDT because of_fdt_unflatten_tree()
|
* Must create permanent copy of FDT because of_fdt_unflatten_tree()
|
||||||
* will create pointers to the passed in FDT in the unflattened tree.
|
* will create pointers to the passed in FDT in the unflattened tree.
|
||||||
*/
|
*/
|
||||||
new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL);
|
new_fdt = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);
|
||||||
if (!new_fdt)
|
if (!new_fdt)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root);
|
new_fdt_align = PTR_ALIGN(new_fdt, FDT_ALIGN_SIZE);
|
||||||
|
memcpy(new_fdt_align, overlay_fdt, size);
|
||||||
|
|
||||||
|
of_fdt_unflatten_tree(new_fdt_align, NULL, &overlay_root);
|
||||||
if (!overlay_root) {
|
if (!overlay_root) {
|
||||||
pr_err("unable to unflatten overlay_fdt\n");
|
pr_err("unable to unflatten overlay_fdt\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|||||||
@@ -1262,7 +1262,16 @@ DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL)
|
|||||||
DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL)
|
DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL)
|
||||||
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
|
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
|
||||||
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
|
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
|
||||||
DEFINE_SUFFIX_PROP(gpios, "-gpios", "#gpio-cells")
|
|
||||||
|
static struct device_node *parse_gpios(struct device_node *np,
|
||||||
|
const char *prop_name, int index)
|
||||||
|
{
|
||||||
|
if (!strcmp_suffix(prop_name, ",nr-gpios"))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return parse_suffix_prop_cells(np, prop_name, index, "-gpios",
|
||||||
|
"#gpio-cells");
|
||||||
|
}
|
||||||
|
|
||||||
static struct device_node *parse_iommu_maps(struct device_node *np,
|
static struct device_node *parse_iommu_maps(struct device_node *np,
|
||||||
const char *prop_name, int index)
|
const char *prop_name, int index)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/i2c-mux.h>
|
#include <linux/i2c-mux.h>
|
||||||
@@ -1408,7 +1409,8 @@ static void attach_node_and_children(struct device_node *np)
|
|||||||
static int __init unittest_data_add(void)
|
static int __init unittest_data_add(void)
|
||||||
{
|
{
|
||||||
void *unittest_data;
|
void *unittest_data;
|
||||||
struct device_node *unittest_data_node, *np;
|
void *unittest_data_align;
|
||||||
|
struct device_node *unittest_data_node = NULL, *np;
|
||||||
/*
|
/*
|
||||||
* __dtb_testcases_begin[] and __dtb_testcases_end[] are magically
|
* __dtb_testcases_begin[] and __dtb_testcases_end[] are magically
|
||||||
* created by cmd_dt_S_dtb in scripts/Makefile.lib
|
* created by cmd_dt_S_dtb in scripts/Makefile.lib
|
||||||
@@ -1417,21 +1419,29 @@ static int __init unittest_data_add(void)
|
|||||||
extern uint8_t __dtb_testcases_end[];
|
extern uint8_t __dtb_testcases_end[];
|
||||||
const int size = __dtb_testcases_end - __dtb_testcases_begin;
|
const int size = __dtb_testcases_end - __dtb_testcases_begin;
|
||||||
int rc;
|
int rc;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
pr_warn("%s: No testcase data to attach; not running tests\n",
|
pr_warn("%s: testcases is empty\n", __func__);
|
||||||
__func__);
|
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* creating copy */
|
/* creating copy */
|
||||||
unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
|
unittest_data = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);
|
||||||
if (!unittest_data)
|
if (!unittest_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
|
unittest_data_align = PTR_ALIGN(unittest_data, FDT_ALIGN_SIZE);
|
||||||
|
memcpy(unittest_data_align, __dtb_testcases_begin, size);
|
||||||
|
|
||||||
|
ret = of_fdt_unflatten_tree(unittest_data_align, NULL, &unittest_data_node);
|
||||||
|
if (!ret) {
|
||||||
|
pr_warn("%s: unflatten testcases tree failed\n", __func__);
|
||||||
|
kfree(unittest_data);
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
if (!unittest_data_node) {
|
if (!unittest_data_node) {
|
||||||
pr_warn("%s: No tree to attach; not running tests\n", __func__);
|
pr_warn("%s: testcases tree is empty\n", __func__);
|
||||||
kfree(unittest_data);
|
kfree(unittest_data);
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user