Merge branch 'for-next/oftree'
Conflicts: drivers/of/base.c
This commit is contained in:
commit
0b12784089
|
@ -138,6 +138,9 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data)
|
|||
|
||||
u32 end;
|
||||
|
||||
if (data->oftree)
|
||||
return -ENXIO;
|
||||
|
||||
header = &__header;
|
||||
ret = read(fd, header, sizeof(*header));
|
||||
if (ret < sizeof(*header))
|
||||
|
@ -402,12 +405,6 @@ static int do_bootm_aimage(struct image_data *data)
|
|||
if (!getenv("aimage_noverwrite_tags"))
|
||||
armlinux_set_bootparams((void*)header->tags_addr);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OFTREE) && data->oftree) {
|
||||
ret = of_fix_tree(data->oftree);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
cmp = &header->second_stage;
|
||||
if (cmp->size) {
|
||||
void (*second)(void);
|
||||
|
|
|
@ -23,7 +23,7 @@ static int do_bootu(int argc, char *argv[])
|
|||
kernel = (void *)simple_strtoul(argv[1], NULL, 0);
|
||||
|
||||
#ifdef CONFIG_OFTREE
|
||||
oftree = of_get_fixed_tree();
|
||||
oftree = of_get_fixed_tree(NULL);
|
||||
#endif
|
||||
|
||||
start_linux(kernel, 0, 0, 0, oftree);
|
||||
|
|
|
@ -109,7 +109,7 @@ static int do_bootz(int argc, char *argv[])
|
|||
|
||||
printf("loaded zImage from %s with size %d\n", argv[1], end);
|
||||
#ifdef CONFIG_OFTREE
|
||||
oftree = of_get_fixed_tree();
|
||||
oftree = of_get_fixed_tree(NULL);
|
||||
#endif
|
||||
|
||||
start_linux(zimage, swap, 0, 0, oftree);
|
||||
|
|
|
@ -481,18 +481,28 @@ config CMD_GO
|
|||
config CMD_OFTREE
|
||||
tristate
|
||||
select OFTREE
|
||||
select OFDEVICE
|
||||
prompt "oftree"
|
||||
help
|
||||
The oftree command has support for dumping devicetrees and, if
|
||||
enabled, to probe devices from the devicetree
|
||||
|
||||
config CMD_OFTREE_PROBE
|
||||
bool
|
||||
depends on CMD_OFTREE
|
||||
config CMD_OF_PROPERTY
|
||||
tristate
|
||||
select OFTREE
|
||||
select OFDEVICE
|
||||
prompt "oftree probe support"
|
||||
prompt "of_property"
|
||||
help
|
||||
This enables the -p option to probe devices from the devicetree
|
||||
The of_property command allows setting and deleting of properties in
|
||||
the currently loaded devicetree.
|
||||
|
||||
config CMD_OF_NODE
|
||||
tristate
|
||||
select OFTREE
|
||||
select OFDEVICE
|
||||
prompt "of_node"
|
||||
help
|
||||
The of_property command allows adding and removing devicetree nodes.
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o
|
|||
obj-$(CONFIG_CMD_USB) += usb.o
|
||||
obj-$(CONFIG_CMD_TIME) += time.o
|
||||
obj-$(CONFIG_CMD_OFTREE) += oftree.o
|
||||
obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o
|
||||
obj-$(CONFIG_CMD_OF_NODE) += of_node.o
|
||||
obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o
|
||||
obj-$(CONFIG_CMD_IOMEM) += iomem.o
|
||||
obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o
|
||||
|
|
|
@ -139,9 +139,7 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu
|
|||
{
|
||||
enum filetype ft;
|
||||
struct fdt_header *fdt, *fixfdt;
|
||||
int ret;
|
||||
size_t size;
|
||||
unsigned int align;
|
||||
|
||||
printf("Loading devicetree from '%s'\n", oftree);
|
||||
|
||||
|
@ -189,36 +187,18 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu
|
|||
file_type_to_string(ft));
|
||||
}
|
||||
|
||||
/*
|
||||
* ARM Linux uses a single 1MiB section (with 1MiB alignment)
|
||||
* for mapping the devicetree, so we are not allowed to cross
|
||||
* 1MiB boundaries.
|
||||
*/
|
||||
align = 1 << fls(size + OFTREE_SIZE_INCREASE - 1);
|
||||
|
||||
fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE);
|
||||
memcpy(fixfdt, fdt, size);
|
||||
|
||||
|
||||
ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE);
|
||||
fixfdt = of_get_fixed_tree(fdt);
|
||||
if (!fixfdt)
|
||||
return -EINVAL;
|
||||
|
||||
free(fdt);
|
||||
|
||||
if (ret) {
|
||||
printf("unable to parse %s\n", oftree);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_fix_tree(fixfdt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bootm_verbose(data) > 1)
|
||||
fdt_print(fixfdt, "/");
|
||||
|
||||
data->oftree = fixfdt;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -420,6 +400,10 @@ static int do_bootm(int argc, char *argv[])
|
|||
ret = bootm_open_oftree(&data, oftree, oftree_num);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
} else {
|
||||
data.oftree = of_get_fixed_tree(NULL);
|
||||
if (bootm_verbose(&data) && data.oftree)
|
||||
printf("using internal devicetree\n");
|
||||
}
|
||||
#endif
|
||||
if (data.os_address == UIMAGE_SOME_ADDRESS)
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* of_node.c - device tree node handling support
|
||||
*
|
||||
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <environment.h>
|
||||
#include <fdt.h>
|
||||
#include <of.h>
|
||||
#include <command.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
#include <libfdt.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <init.h>
|
||||
#include <libgen.h>
|
||||
|
||||
static int do_of_node(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
int delete = 0;
|
||||
int create = 0;
|
||||
char *path = NULL;
|
||||
struct device_node *node = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "cd")) > 0) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
create = 1;
|
||||
break;
|
||||
case 'd':
|
||||
delete = 1;
|
||||
break;
|
||||
default:
|
||||
return COMMAND_ERROR_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
path = argv[optind];
|
||||
}
|
||||
|
||||
if (create) {
|
||||
char *name;
|
||||
|
||||
if (!path)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
name = xstrdup(basename(path));
|
||||
path = dirname(path);
|
||||
|
||||
node = of_find_node_by_path(path);
|
||||
if (!node) {
|
||||
printf("Cannot find nodepath %s\n", path);
|
||||
free(name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
debug("create node \"%s\" \"%s\"\n", path, name);
|
||||
|
||||
of_new_node(node, name);
|
||||
|
||||
free(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
if (!path)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
node = of_find_node_by_path(path);
|
||||
if (!node) {
|
||||
printf("Cannot find nodepath %s\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
of_free(node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(of_node)
|
||||
BAREBOX_CMD_HELP_USAGE("of_node [OPTIONS] [NODE] [NAME]\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-c", "create a new node\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-d", "delete a node\n")
|
||||
BAREBOX_CMD_HELP_END
|
||||
|
||||
BAREBOX_CMD_START(of_node)
|
||||
.cmd = do_of_node,
|
||||
.usage = "handle of nodes",
|
||||
BAREBOX_CMD_HELP(cmd_of_node_help)
|
||||
BAREBOX_CMD_END
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* of_property.c - device tree property handling support
|
||||
*
|
||||
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <environment.h>
|
||||
#include <fdt.h>
|
||||
#include <of.h>
|
||||
#include <command.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
#include <libfdt.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <init.h>
|
||||
|
||||
static int of_parse_prop_cells(char * const *newval, int count, char *data, int *len)
|
||||
{
|
||||
char *cp;
|
||||
unsigned long tmp; /* holds converted values */
|
||||
int stridx = 0;
|
||||
char *newp = newval[0];
|
||||
|
||||
newp++;
|
||||
|
||||
while (1) {
|
||||
if (*newp == '>')
|
||||
return 0;
|
||||
|
||||
if (*newp == '\0') {
|
||||
newp = newval[++stridx];
|
||||
|
||||
if (stridx == count) {
|
||||
printf("missing '>'\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cp = newp;
|
||||
tmp = simple_strtoul(cp, &newp, 0);
|
||||
*(__be32 *)data = __cpu_to_be32(tmp);
|
||||
data += 4;
|
||||
*len += 4;
|
||||
|
||||
/* If the ptr didn't advance, something went wrong */
|
||||
if ((newp - cp) <= 0) {
|
||||
printf("cannot not convert \"%s\"\n", cp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (*newp == ' ')
|
||||
newp++;
|
||||
}
|
||||
}
|
||||
|
||||
static int of_parse_prop_stream(char * const *newval, int count, char *data, int *len)
|
||||
{
|
||||
char *cp;
|
||||
unsigned long tmp; /* holds converted values */
|
||||
int stridx = 0;
|
||||
char *newp = newval[0];
|
||||
|
||||
newp++;
|
||||
|
||||
while (1) {
|
||||
if (*newp == ']')
|
||||
return 0;
|
||||
|
||||
while (*newp == ' ')
|
||||
newp++;
|
||||
|
||||
if (*newp == '\0') {
|
||||
newp = newval[++stridx];
|
||||
|
||||
if (stridx == count) {
|
||||
printf("missing ']'\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cp = newp;
|
||||
tmp = simple_strtoul(newp, &newp, 16);
|
||||
*data++ = tmp & 0xff;
|
||||
*len = *len + 1;
|
||||
|
||||
/* If the ptr didn't advance, something went wrong */
|
||||
if ((newp - cp) <= 0) {
|
||||
printf("cannot not convert \"%s\"\n", cp);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int of_parse_prop_string(char * const *newval, int count, char *data, int *len)
|
||||
{
|
||||
int stridx = 0;
|
||||
char *newp = newval[0];
|
||||
|
||||
/*
|
||||
* Assume it is one or more strings. Copy it into our
|
||||
* data area for convenience (including the
|
||||
* terminating '\0's).
|
||||
*/
|
||||
while (stridx < count) {
|
||||
size_t length = strlen(newp) + 1;
|
||||
|
||||
strcpy(data, newp);
|
||||
data += length;
|
||||
*len += length;
|
||||
newp = newval[++stridx];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the user's input, partially heuristic. Valid formats:
|
||||
* <0x00112233 4 05> - an array of cells. Numbers follow standard
|
||||
* C conventions.
|
||||
* [00 11 22 .. nn] - byte stream
|
||||
* "string" - If the the value doesn't start with "<" or "[", it is
|
||||
* treated as a string. Note that the quotes are
|
||||
* stripped by the parser before we get the string.
|
||||
* newval: An array of strings containing the new property as specified
|
||||
* on the command line
|
||||
* count: The number of strings in the array
|
||||
* data: A bytestream to be placed in the property
|
||||
* len: The length of the resulting bytestream
|
||||
*/
|
||||
static int of_parse_prop(char * const *newval, int count, char *data, int *len)
|
||||
{
|
||||
char *newp; /* temporary newval char pointer */
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
newp = newval[0];
|
||||
|
||||
switch (*newp) {
|
||||
case '<':
|
||||
return of_parse_prop_cells(newval, count, data, len);
|
||||
case '[':
|
||||
return of_parse_prop_stream(newval, count, data, len);
|
||||
default:
|
||||
return of_parse_prop_string(newval, count, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_of_property(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
int delete = 0;
|
||||
int set = 0;
|
||||
int ret;
|
||||
char *path = NULL, *propname = NULL;
|
||||
struct device_node *node = NULL;
|
||||
struct property *pp = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ds")) > 0) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
delete = 1;
|
||||
break;
|
||||
case 's':
|
||||
set = 1;
|
||||
break;
|
||||
default:
|
||||
return COMMAND_ERROR_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
path = argv[optind];
|
||||
node = of_find_node_by_path(path);
|
||||
if (!node) {
|
||||
printf("Cannot find nodepath %s\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 1 < argc) {
|
||||
propname = argv[optind + 1];
|
||||
|
||||
pp = of_find_property(node, propname);
|
||||
if (!set && !pp) {
|
||||
printf("Cannot find property %s\n", propname);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
debug("path: %s propname: %s\n", path, propname);
|
||||
|
||||
if (delete) {
|
||||
if (!node || !pp)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
of_delete_property(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
int num_args = argc - optind - 2;
|
||||
int len;
|
||||
void *data;
|
||||
|
||||
if (!node)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
/*
|
||||
* standard console buffer size. The result won't be bigger than the
|
||||
* string input.
|
||||
*/
|
||||
data = malloc(1024);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_parse_prop(&argv[optind + 2], num_args, data, &len);
|
||||
if (ret) {
|
||||
free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pp) {
|
||||
free(pp->value);
|
||||
/* limit property data to the actual size */
|
||||
data = xrealloc(data, len);
|
||||
pp->value = data;
|
||||
pp->length = len;
|
||||
} else {
|
||||
pp = of_new_property(node, propname, data, len);
|
||||
if (!pp) {
|
||||
printf("Cannot create property %s\n", propname);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(of_property)
|
||||
BAREBOX_CMD_HELP_USAGE("of_property [OPTIONS] [NODE] [PROPERTY] [VALUES]\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-s", "set property to value\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-d", "delete property\n")
|
||||
BAREBOX_CMD_HELP_TEXT ("\nvalid formats for values:\n")
|
||||
BAREBOX_CMD_HELP_TEXT ("<0x00112233 4 05> - an array of cells\n")
|
||||
BAREBOX_CMD_HELP_TEXT ("[00 11 22 .. nn] - byte stream\n")
|
||||
BAREBOX_CMD_HELP_TEXT ("If the value does not start with '<' or '[' it is interpreted as strings\n")
|
||||
BAREBOX_CMD_HELP_END
|
||||
|
||||
BAREBOX_CMD_START(of_property)
|
||||
.cmd = do_of_property,
|
||||
.usage = "handle of properties",
|
||||
BAREBOX_CMD_HELP(cmd_of_property_help)
|
||||
BAREBOX_CMD_END
|
|
@ -36,20 +36,28 @@
|
|||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <init.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int do_oftree(int argc, char *argv[])
|
||||
{
|
||||
struct fdt_header *fdt;
|
||||
struct fdt_header *fdt = NULL;
|
||||
void *fdt_free = NULL;
|
||||
int size;
|
||||
int opt;
|
||||
char *file = NULL;
|
||||
const char *node = "/";
|
||||
int dump = 0;
|
||||
int probe = 0;
|
||||
int load = 0;
|
||||
int save = 0;
|
||||
int free_of = 0;
|
||||
int ret;
|
||||
|
||||
while ((opt = getopt(argc, argv, "dpfn:")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) {
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
load = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dump = 1;
|
||||
break;
|
||||
|
@ -62,73 +70,121 @@ static int do_oftree(int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
case 'f':
|
||||
free(barebox_fdt);
|
||||
barebox_fdt = NULL;
|
||||
return 0;
|
||||
free_of = 1;
|
||||
break;
|
||||
case 'n':
|
||||
node = optarg;
|
||||
break;
|
||||
case 's':
|
||||
save = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (free_of) {
|
||||
struct device_node *root = of_get_root_node();
|
||||
|
||||
if (root)
|
||||
of_free(root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
file = argv[optind];
|
||||
|
||||
if (!dump && !probe)
|
||||
if (!dump && !probe && !load && !save)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
if (save) {
|
||||
if (!file) {
|
||||
printf("no file given\n");
|
||||
ret = -ENOENT;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
fdt = of_get_fixed_tree(NULL);
|
||||
if (!fdt) {
|
||||
printf("no devicetree available\n");
|
||||
ret = -EINVAL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = write_file(file, fdt, fdt_totalsize(fdt));
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
fdt = read_file(file, &size);
|
||||
if (!fdt) {
|
||||
printf("unable to read %s\n", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdt_free = fdt;
|
||||
}
|
||||
|
||||
if (load) {
|
||||
if (!fdt) {
|
||||
printf("no fdt given\n");
|
||||
ret = -ENOENT;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = of_unflatten_dtb(fdt);
|
||||
if (ret) {
|
||||
printf("parse oftree: %s\n", strerror(-ret));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (dump) {
|
||||
if (file) {
|
||||
fdt = read_file(file, &size);
|
||||
if (!fdt) {
|
||||
printf("unable to read %s\n", file);
|
||||
return 1;
|
||||
if (fdt) {
|
||||
ret = fdt_print(fdt, node);
|
||||
} else {
|
||||
struct device_node *n = of_find_node_by_path(node);
|
||||
|
||||
if (!n) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fdt_print(fdt, node);
|
||||
free(fdt);
|
||||
} else {
|
||||
if (barebox_fdt) {
|
||||
fdt_print(barebox_fdt, node);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
of_print_nodes(n, 0);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (probe) {
|
||||
if (!file)
|
||||
return COMMAND_ERROR_USAGE;
|
||||
|
||||
fdt = read_file(file, &size);
|
||||
if (!fdt) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = of_parse_dtb(fdt);
|
||||
if (ret) {
|
||||
printf("parse oftree: %s\n", strerror(-ret));
|
||||
return 1;
|
||||
}
|
||||
|
||||
of_probe();
|
||||
ret = of_probe();
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
free(fdt_free);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BAREBOX_CMD_HELP_START(oftree)
|
||||
BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS]\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-p <FILE>", "probe devices in oftree from <file>\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-d [FILE]", "dump oftree from [FILE] or the parsed tree if no file is given\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-f", "free stored oftree\n")
|
||||
BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS] [DTB]\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-l", "Load [DTB] to internal devicetree\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-p", "probe devices from stored devicetree\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-d", "dump oftree from [DTB] or the parsed tree if no dtb is given\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-f", "free stored devicetree\n")
|
||||
BAREBOX_CMD_HELP_OPT ("-n <node>", "specify root devicenode to dump for -d\n")
|
||||
BAREBOX_CMD_HELP_END
|
||||
|
||||
BAREBOX_CMD_START(oftree)
|
||||
.cmd = do_oftree,
|
||||
.usage = "handle oftrees",
|
||||
.usage = "handle devicetrees",
|
||||
BAREBOX_CMD_HELP(cmd_oftree_help)
|
||||
BAREBOX_CMD_END
|
||||
|
|
|
@ -246,8 +246,6 @@ int fdt_get_path_or_create(struct fdt_header *fdt, const char *path)
|
|||
return nodeoffset;
|
||||
}
|
||||
|
||||
struct fdt_header *barebox_fdt;
|
||||
|
||||
static int of_fixup_bootargs(struct fdt_header *fdt)
|
||||
{
|
||||
int nodeoffset;
|
||||
|
@ -294,6 +292,10 @@ int of_register_fixup(int (*fixup)(struct fdt_header *))
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply registered fixups for the given fdt. The fdt must have
|
||||
* enough free space to apply the fixups.
|
||||
*/
|
||||
int of_fix_tree(struct fdt_header *fdt)
|
||||
{
|
||||
struct of_fixup *of_fixup;
|
||||
|
@ -308,14 +310,55 @@ int of_fix_tree(struct fdt_header *fdt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct fdt_header *of_get_fixed_tree(void)
|
||||
/*
|
||||
* The size by which we increase the dtb to have space for additional
|
||||
* fixups. Ideally this would be done by libfdt automatically
|
||||
*/
|
||||
#define OFTREE_SIZE_INCREASE 0x8000
|
||||
|
||||
/*
|
||||
* Get the fixed fdt. This function uses the fdt input pointer
|
||||
* if provided or the barebox internal devicetree if not.
|
||||
* It increases the size of the tree and applies the registered
|
||||
* fixups.
|
||||
*/
|
||||
struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt)
|
||||
{
|
||||
int ret;
|
||||
void *fixfdt, *internalfdt = NULL;
|
||||
int size, align;
|
||||
|
||||
if (!fdt) {
|
||||
fdt = internalfdt = of_flatten_dtb();
|
||||
if (!fdt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = fdt_totalsize(fdt);
|
||||
|
||||
/*
|
||||
* ARM Linux uses a single 1MiB section (with 1MiB alignment)
|
||||
* for mapping the devicetree, so we are not allowed to cross
|
||||
* 1MiB boundaries.
|
||||
*/
|
||||
align = 1 << fls(size + OFTREE_SIZE_INCREASE - 1);
|
||||
|
||||
fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE);
|
||||
ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE);
|
||||
|
||||
free(internalfdt);
|
||||
|
||||
if (!barebox_fdt)
|
||||
return NULL;
|
||||
ret = of_fix_tree(barebox_fdt);
|
||||
if (ret)
|
||||
return NULL;
|
||||
return barebox_fdt;
|
||||
goto out_free;
|
||||
|
||||
ret = of_fix_tree(fixfdt);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
return fixfdt;
|
||||
|
||||
out_free:
|
||||
free(fixfdt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <malloc.h>
|
||||
#include <init.h>
|
||||
#include <memory.h>
|
||||
#include <sizes.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
/**
|
||||
|
@ -138,6 +139,12 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
|
|||
void of_alias_scan(void)
|
||||
{
|
||||
struct property *pp;
|
||||
struct alias_prop *app, *tmp;
|
||||
|
||||
list_for_each_entry_safe(app, tmp, &aliases_lookup, link)
|
||||
free(app);
|
||||
|
||||
INIT_LIST_HEAD(&aliases_lookup);
|
||||
|
||||
of_aliases = of_find_node_by_path("/aliases");
|
||||
if (!of_aliases)
|
||||
|
@ -485,10 +492,14 @@ struct device_node *of_find_node_by_path(const char *path)
|
|||
{
|
||||
struct device_node *np;
|
||||
|
||||
if (!strcmp(path, "/"))
|
||||
return root_node;
|
||||
|
||||
list_for_each_entry(np, &allnodes, list) {
|
||||
if (np->full_name && (strcmp(np->full_name, path) == 0))
|
||||
return np;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_node_by_path);
|
||||
|
@ -574,22 +585,37 @@ void of_print_nodes(struct device_node *node, int indent)
|
|||
printf("};\n");
|
||||
}
|
||||
|
||||
static struct device_node *new_device_node(struct device_node *parent)
|
||||
struct device_node *of_new_node(struct device_node *parent, const char *name)
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
if (!parent && root_node)
|
||||
return NULL;
|
||||
|
||||
node = xzalloc(sizeof(*node));
|
||||
node->parent = parent;
|
||||
if (parent)
|
||||
list_add_tail(&node->parent_list, &parent->children);
|
||||
else
|
||||
root_node = node;
|
||||
|
||||
INIT_LIST_HEAD(&node->children);
|
||||
INIT_LIST_HEAD(&node->properties);
|
||||
|
||||
if (parent) {
|
||||
node->name = xstrdup(name);
|
||||
node->full_name = asprintf("%s/%s", node->parent->full_name, name);
|
||||
} else {
|
||||
node->name = xstrdup("");
|
||||
node->full_name = xstrdup("");
|
||||
}
|
||||
|
||||
list_add_tail(&node->list, &allnodes);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct property *new_property(struct device_node *node, const char *name,
|
||||
struct property *of_new_property(struct device_node *node, const char *name,
|
||||
const void *data, int len)
|
||||
{
|
||||
struct property *prop;
|
||||
|
@ -606,6 +632,15 @@ static struct property *new_property(struct device_node *node, const char *name,
|
|||
return prop;
|
||||
}
|
||||
|
||||
void of_delete_property(struct property *pp)
|
||||
{
|
||||
list_del(&pp->list);
|
||||
|
||||
free(pp->name);
|
||||
free(pp->value);
|
||||
free(pp);
|
||||
}
|
||||
|
||||
static struct device_d *add_of_device(struct device_node *node)
|
||||
{
|
||||
struct device_d *dev;
|
||||
|
@ -754,6 +789,8 @@ void of_free(struct device_node *node)
|
|||
if (!node)
|
||||
return;
|
||||
|
||||
list_del(&node->list);
|
||||
|
||||
list_for_each_entry_safe(p, pt, &node->properties, list) {
|
||||
list_del(&p->list);
|
||||
free(p->name);
|
||||
|
@ -776,6 +813,11 @@ void of_free(struct device_node *node)
|
|||
free(node->name);
|
||||
free(node->full_name);
|
||||
free(node);
|
||||
|
||||
if (node == root_node)
|
||||
root_node = NULL;
|
||||
|
||||
of_alias_scan();
|
||||
}
|
||||
|
||||
static void __of_probe(struct device_node *node)
|
||||
|
@ -812,11 +854,32 @@ int of_probe(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct device_node *of_find_child(struct device_node *node, const char *name)
|
||||
{
|
||||
struct device_node *_n;
|
||||
|
||||
if (!root_node)
|
||||
return NULL;
|
||||
|
||||
if (!node && !*name)
|
||||
return root_node;
|
||||
|
||||
if (!node)
|
||||
node = root_node;
|
||||
|
||||
list_for_each_entry(_n, &node->children, parent_list) {
|
||||
if (!strcmp(_n->name, name))
|
||||
return _n;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a flat device tree binary blob and store it in the barebox
|
||||
* internal tree format,
|
||||
*/
|
||||
int of_parse_dtb(struct fdt_header *fdt)
|
||||
int of_unflatten_dtb(struct fdt_header *fdt)
|
||||
{
|
||||
const void *nodep; /* property node pointer */
|
||||
int nodeoffset; /* node offset from libfdt */
|
||||
|
@ -827,12 +890,8 @@ int of_parse_dtb(struct fdt_header *fdt)
|
|||
const struct fdt_property *fdt_prop;
|
||||
const char *pathp;
|
||||
int depth = 10000;
|
||||
struct device_node *node = NULL;
|
||||
char buf[1024];
|
||||
int ret;
|
||||
|
||||
if (root_node)
|
||||
return -EBUSY;
|
||||
struct device_node *node = NULL, *n;
|
||||
struct property *p;
|
||||
|
||||
nodeoffset = fdt_path_offset(fdt, "/");
|
||||
if (nodeoffset < 0) {
|
||||
|
@ -853,16 +912,12 @@ int of_parse_dtb(struct fdt_header *fdt)
|
|||
if (pathp == NULL)
|
||||
pathp = "/* NULL pointer error */";
|
||||
|
||||
ret = fdt_get_path(fdt, nodeoffset, buf, 1024);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
node = new_device_node(node);
|
||||
if (!node->parent)
|
||||
root_node = node;
|
||||
node->full_name = xstrdup(buf);
|
||||
node->name = xstrdup(pathp);
|
||||
list_add_tail(&node->list, &allnodes);
|
||||
n = of_find_child(node, pathp);
|
||||
if (n) {
|
||||
node = n;
|
||||
} else {
|
||||
node = of_new_node(node, pathp);
|
||||
}
|
||||
break;
|
||||
case FDT_END_NODE:
|
||||
node = node->parent;
|
||||
|
@ -874,7 +929,15 @@ int of_parse_dtb(struct fdt_header *fdt)
|
|||
fdt32_to_cpu(fdt_prop->nameoff));
|
||||
len = fdt32_to_cpu(fdt_prop->len);
|
||||
nodep = fdt_prop->data;
|
||||
new_property(node, pathp, nodep, len);
|
||||
|
||||
p = of_find_property(node, pathp);
|
||||
if (p) {
|
||||
free(p->value);
|
||||
p->value = xzalloc(len);
|
||||
memcpy(p->value, nodep, len);
|
||||
} else {
|
||||
of_new_property(node, pathp, nodep, len);
|
||||
}
|
||||
break;
|
||||
case FDT_NOP:
|
||||
break;
|
||||
|
@ -892,6 +955,71 @@ int of_parse_dtb(struct fdt_header *fdt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __of_flatten_dtb(void *fdt, struct device_node *node)
|
||||
{
|
||||
struct property *p;
|
||||
struct device_node *n;
|
||||
int ret;
|
||||
|
||||
ret = fdt_begin_node(fdt, node->name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(p, &node->properties, list) {
|
||||
ret = fdt_property(fdt, p->name, p->value, p->length);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_for_each_entry(n, &node->children, parent_list) {
|
||||
ret = __of_flatten_dtb(fdt, n);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fdt_end_node(fdt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DTB_SIZE SZ_128K
|
||||
|
||||
void *of_flatten_dtb(void)
|
||||
{
|
||||
void *fdt;
|
||||
int ret;
|
||||
|
||||
if (!root_node)
|
||||
return NULL;
|
||||
|
||||
fdt = malloc(DTB_SIZE);
|
||||
if (!fdt)
|
||||
return NULL;
|
||||
|
||||
memset(fdt, 0, DTB_SIZE);
|
||||
|
||||
ret = fdt_create(fdt, DTB_SIZE);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
ret = fdt_finish_reservemap(fdt);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
ret = __of_flatten_dtb(fdt, root_node);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
fdt_finish(fdt);
|
||||
|
||||
return fdt;
|
||||
|
||||
out_free:
|
||||
free(fdt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int of_device_is_stdout_path(struct device_d *dev)
|
||||
{
|
||||
struct device_node *dn;
|
||||
|
|
19
fs/fs.c
19
fs/fs.c
|
@ -67,6 +67,25 @@ err_out:
|
|||
|
||||
EXPORT_SYMBOL(read_file);
|
||||
|
||||
int write_file(const char *filename, void *buf, size_t size)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ret = write_full(fd, buf, size);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(write_file);
|
||||
|
||||
char *mkmodestr(unsigned long mode, char *str)
|
||||
{
|
||||
static const char *l = "xwr";
|
||||
|
|
|
@ -166,6 +166,11 @@ char *mkmodestr(unsigned long mode, char *str);
|
|||
*/
|
||||
void *read_file(const char *filename, size_t *size);
|
||||
|
||||
/*
|
||||
* Write a buffer to a file. This file is newly created.
|
||||
*/
|
||||
int write_file(const char *filename, void *buf, size_t size);
|
||||
|
||||
/*
|
||||
* This function turns 'path' into an absolute path and removes all occurrences
|
||||
* of "..", "." and double slashes. The returned string must be freed wit free().
|
||||
|
|
16
include/of.h
16
include/of.h
|
@ -5,11 +5,9 @@
|
|||
#include <errno.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
extern struct fdt_header *barebox_fdt;
|
||||
|
||||
int fdt_print(struct fdt_header *working_fdt, const char *pathp);
|
||||
|
||||
struct fdt_header *of_get_fixed_tree(void);
|
||||
struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt);
|
||||
int of_fix_tree(struct fdt_header *fdt);
|
||||
int of_register_fixup(int (*fixup)(struct fdt_header *));
|
||||
|
||||
|
@ -107,6 +105,12 @@ int of_machine_is_compatible(const char *compat);
|
|||
void of_print_nodes(struct device_node *node, int indent);
|
||||
int of_probe(void);
|
||||
int of_parse_dtb(struct fdt_header *fdt);
|
||||
void of_free(struct device_node *node);
|
||||
int of_unflatten_dtb(struct fdt_header *fdt);
|
||||
struct device_node *of_new_node(struct device_node *parent, const char *name);
|
||||
struct property *of_new_property(struct device_node *node, const char *name,
|
||||
const void *data, int len);
|
||||
void of_delete_property(struct property *pp);
|
||||
|
||||
int of_property_read_string(struct device_node *np, const char *propname,
|
||||
const char **out_string);
|
||||
|
@ -119,6 +123,7 @@ struct device_node *of_get_root_node(void);
|
|||
int of_alias_get_id(struct device_node *np, const char *stem);
|
||||
int of_device_is_stdout_path(struct device_d *dev);
|
||||
const char *of_get_model(void);
|
||||
void *of_flatten_dtb(void);
|
||||
#else
|
||||
static inline int of_parse_partitions(const char *cdevname,
|
||||
struct device_node *node)
|
||||
|
@ -145,6 +150,11 @@ static inline const char *of_get_model(void)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void *of_flatten_dtb(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OF_H */
|
||||
|
|
Loading…
Reference in New Issue