mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
Merge branch 'next'
This commit is contained in:
commit
2a7abdd3d3
7 changed files with 461 additions and 28 deletions
11
README
11
README
|
@ -2602,6 +2602,17 @@ FIT uImage format:
|
|||
-150 common/cmd_nand.c Incorrect FIT image format
|
||||
151 common/cmd_nand.c FIT image format OK
|
||||
|
||||
- FIT image support:
|
||||
CONFIG_FIT
|
||||
Enable support for the FIT uImage format.
|
||||
|
||||
CONFIG_FIT_BEST_MATCH
|
||||
When no configuration is explicitly selected, default to the
|
||||
one whose fdt's compatibility field best matches that of
|
||||
U-Boot itself. A match is considered "best" if it matches the
|
||||
most specific compatibility entry of U-Boot's fdt's root node.
|
||||
The order of entries in the configuration's fdt is ignored.
|
||||
|
||||
- Standalone program support:
|
||||
CONFIG_STANDALONE_LOAD_ADDR
|
||||
|
||||
|
|
|
@ -949,8 +949,19 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
|
|||
* node
|
||||
*/
|
||||
bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME);
|
||||
#ifdef CONFIG_FIT_BEST_MATCH
|
||||
if (fit_uname_config)
|
||||
cfg_noffset =
|
||||
fit_conf_get_node(fit_hdr,
|
||||
fit_uname_config);
|
||||
else
|
||||
cfg_noffset =
|
||||
fit_conf_find_compat(fit_hdr,
|
||||
gd->fdt_blob);
|
||||
#else
|
||||
cfg_noffset = fit_conf_get_node(fit_hdr,
|
||||
fit_uname_config);
|
||||
#endif
|
||||
if (cfg_noffset < 0) {
|
||||
bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME);
|
||||
return NULL;
|
||||
|
|
127
common/image.c
127
common/image.c
|
@ -3049,6 +3049,133 @@ int fit_check_format(const void *fit)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fit_conf_find_compat
|
||||
* @fit: pointer to the FIT format image header
|
||||
* @fdt: pointer to the device tree to compare against
|
||||
*
|
||||
* fit_conf_find_compat() attempts to find the configuration whose fdt is the
|
||||
* most compatible with the passed in device tree.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* / o image-tree
|
||||
* |-o images
|
||||
* | |-o fdt@1
|
||||
* | |-o fdt@2
|
||||
* |
|
||||
* |-o configurations
|
||||
* |-o config@1
|
||||
* | |-fdt = fdt@1
|
||||
* |
|
||||
* |-o config@2
|
||||
* |-fdt = fdt@2
|
||||
*
|
||||
* / o U-Boot fdt
|
||||
* |-compatible = "foo,bar", "bim,bam"
|
||||
*
|
||||
* / o kernel fdt1
|
||||
* |-compatible = "foo,bar",
|
||||
*
|
||||
* / o kernel fdt2
|
||||
* |-compatible = "bim,bam", "baz,biz"
|
||||
*
|
||||
* Configuration 1 would be picked because the first string in U-Boot's
|
||||
* compatible list, "foo,bar", matches a compatible string in the root of fdt1.
|
||||
* "bim,bam" in fdt2 matches the second string which isn't as good as fdt1.
|
||||
*
|
||||
* returns:
|
||||
* offset to the configuration to use if one was found
|
||||
* -1 otherwise
|
||||
*/
|
||||
int fit_conf_find_compat(const void *fit, const void *fdt)
|
||||
{
|
||||
int ndepth = 0;
|
||||
int noffset, confs_noffset, images_noffset;
|
||||
const void *fdt_compat;
|
||||
int fdt_compat_len;
|
||||
int best_match_offset = 0;
|
||||
int best_match_pos = 0;
|
||||
|
||||
confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
|
||||
images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
|
||||
if (confs_noffset < 0 || images_noffset < 0) {
|
||||
debug("Can't find configurations or images nodes.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdt_compat = fdt_getprop(fdt, 0, "compatible", &fdt_compat_len);
|
||||
if (!fdt_compat) {
|
||||
debug("Fdt for comparison has no \"compatible\" property.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop over the configurations in the FIT image.
|
||||
*/
|
||||
for (noffset = fdt_next_node(fit, confs_noffset, &ndepth);
|
||||
(noffset >= 0) && (ndepth > 0);
|
||||
noffset = fdt_next_node(fit, noffset, &ndepth)) {
|
||||
const void *kfdt;
|
||||
const char *kfdt_name;
|
||||
int kfdt_noffset;
|
||||
const char *cur_fdt_compat;
|
||||
int len;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
if (ndepth > 1)
|
||||
continue;
|
||||
|
||||
kfdt_name = fdt_getprop(fit, noffset, "fdt", &len);
|
||||
if (!kfdt_name) {
|
||||
debug("No fdt property found.\n");
|
||||
continue;
|
||||
}
|
||||
kfdt_noffset = fdt_subnode_offset(fit, images_noffset,
|
||||
kfdt_name);
|
||||
if (kfdt_noffset < 0) {
|
||||
debug("No image node named \"%s\" found.\n",
|
||||
kfdt_name);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Get a pointer to this configuration's fdt.
|
||||
*/
|
||||
if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) {
|
||||
debug("Failed to get fdt \"%s\".\n", kfdt_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
len = fdt_compat_len;
|
||||
cur_fdt_compat = fdt_compat;
|
||||
/*
|
||||
* Look for a match for each U-Boot compatibility string in
|
||||
* turn in this configuration's fdt.
|
||||
*/
|
||||
for (i = 0; len > 0 &&
|
||||
(!best_match_offset || best_match_pos > i); i++) {
|
||||
int cur_len = strlen(cur_fdt_compat) + 1;
|
||||
|
||||
if (!fdt_node_check_compatible(kfdt, 0,
|
||||
cur_fdt_compat)) {
|
||||
best_match_offset = noffset;
|
||||
best_match_pos = i;
|
||||
break;
|
||||
}
|
||||
len -= cur_len;
|
||||
cur_fdt_compat += cur_len;
|
||||
}
|
||||
}
|
||||
if (!best_match_offset) {
|
||||
debug("No match found.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return best_match_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* fit_conf_get_node - get node offset for configuration of a given unit name
|
||||
* @fit: pointer to the FIT format image header
|
||||
|
|
102
common/main.c
102
common/main.c
|
@ -30,6 +30,7 @@
|
|||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <version.h>
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
|
@ -40,6 +41,14 @@
|
|||
#include <hush.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
#include <fdtdec.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
#include <fdt_support.h>
|
||||
#endif /* CONFIG_OF_LIBFDT */
|
||||
|
||||
#include <post.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <menu.h>
|
||||
|
@ -274,6 +283,73 @@ int abortboot(int bootdelay)
|
|||
# endif /* CONFIG_AUTOBOOT_KEYED */
|
||||
#endif /* CONFIG_BOOTDELAY >= 0 */
|
||||
|
||||
/*
|
||||
* Runs the given boot command securely. Specifically:
|
||||
* - Doesn't run the command with the shell (run_command or parse_string_outer),
|
||||
* since that's a lot of code surface that an attacker might exploit.
|
||||
* Because of this, we don't do any argument parsing--the secure boot command
|
||||
* has to be a full-fledged u-boot command.
|
||||
* - Doesn't check for keypresses before booting, since that could be a
|
||||
* security hole; also disables Ctrl-C.
|
||||
* - Doesn't allow the command to return.
|
||||
*
|
||||
* Upon any failures, this function will drop into an infinite loop after
|
||||
* printing the error message to console.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \
|
||||
defined(CONFIG_OF_CONTROL)
|
||||
static void secure_boot_cmd(char *cmd)
|
||||
{
|
||||
cmd_tbl_t *cmdtp;
|
||||
int rc;
|
||||
|
||||
if (!cmd) {
|
||||
printf("## Error: Secure boot command not specified\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Disable Ctrl-C just in case some command is used that checks it. */
|
||||
disable_ctrlc(1);
|
||||
|
||||
/* Find the command directly. */
|
||||
cmdtp = find_cmd(cmd);
|
||||
if (!cmdtp) {
|
||||
printf("## Error: \"%s\" not defined\n", cmd);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Run the command, forcing no flags and faking argc and argv. */
|
||||
rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
|
||||
|
||||
/* Shouldn't ever return from boot command. */
|
||||
printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
|
||||
|
||||
err:
|
||||
/*
|
||||
* Not a whole lot to do here. Rebooting won't help much, since we'll
|
||||
* just end up right back here. Just loop.
|
||||
*/
|
||||
hang();
|
||||
}
|
||||
|
||||
static void process_fdt_options(const void *blob)
|
||||
{
|
||||
ulong addr;
|
||||
|
||||
/* Add an env variable to point to a kernel payload, if available */
|
||||
addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
|
||||
if (addr)
|
||||
setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
|
||||
|
||||
/* Add an env variable to point to a root disk, if available */
|
||||
addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
|
||||
if (addr)
|
||||
setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
|
||||
}
|
||||
#endif /* CONFIG_OF_CONTROL */
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void main_loop (void)
|
||||
|
@ -284,7 +360,10 @@ void main_loop (void)
|
|||
int rc = 1;
|
||||
int flag;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \
|
||||
defined(CONFIG_OF_CONTROL)
|
||||
char *env;
|
||||
#endif
|
||||
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
|
||||
char *s;
|
||||
int bootdelay;
|
||||
|
@ -380,6 +459,23 @@ void main_loop (void)
|
|||
else
|
||||
#endif /* CONFIG_BOOTCOUNT_LIMIT */
|
||||
s = getenv ("bootcmd");
|
||||
#ifdef CONFIG_OF_CONTROL
|
||||
/* Allow the fdt to override the boot command */
|
||||
env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
|
||||
if (env)
|
||||
s = env;
|
||||
|
||||
process_fdt_options(gd->fdt_blob);
|
||||
|
||||
/*
|
||||
* If the bootsecure option was chosen, use secure_boot_cmd().
|
||||
* Always use 'env' in this case, since bootsecure requres that the
|
||||
* bootcmd was specified in the FDT too.
|
||||
*/
|
||||
if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
|
||||
secure_boot_cmd(env);
|
||||
|
||||
#endif /* CONFIG_OF_CONTROL */
|
||||
|
||||
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
|
||||
|
||||
|
@ -404,6 +500,10 @@ void main_loop (void)
|
|||
#endif /* CONFIG_MENUKEY */
|
||||
#endif /* CONFIG_BOOTDELAY */
|
||||
|
||||
#if defined CONFIG_OF_CONTROL
|
||||
set_working_fdt_addr((void *)gd->fdt_blob);
|
||||
#endif /* CONFIG_OF_CONTROL */
|
||||
|
||||
/*
|
||||
* Main Loop for Monitor Command Processing
|
||||
*/
|
||||
|
|
112
include/fdtdec.h
112
include/fdtdec.h
|
@ -40,10 +40,12 @@
|
|||
typedef u64 fdt_addr_t;
|
||||
#define FDT_ADDR_T_NONE (-1ULL)
|
||||
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
|
||||
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
|
||||
#else
|
||||
typedef u32 fdt_addr_t;
|
||||
#define FDT_ADDR_T_NONE (-1U)
|
||||
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
|
||||
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
|
||||
#endif
|
||||
|
||||
/* Information obtained about memory from the FDT */
|
||||
|
@ -87,6 +89,22 @@ struct fdt_gpio_state {
|
|||
/* This tells us whether a fdt_gpio_state record is valid or not */
|
||||
#define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE)
|
||||
|
||||
/**
|
||||
* Read the GPIO taking into account the polarity of the pin.
|
||||
*
|
||||
* @param gpio pointer to the decoded gpio
|
||||
* @return value of the gpio if successful, < 0 if unsuccessful
|
||||
*/
|
||||
int fdtdec_get_gpio(struct fdt_gpio_state *gpio);
|
||||
|
||||
/**
|
||||
* Write the GPIO taking into account the polarity of the pin.
|
||||
*
|
||||
* @param gpio pointer to the decoded gpio
|
||||
* @return 0 if successful
|
||||
*/
|
||||
int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val);
|
||||
|
||||
/**
|
||||
* Find the next numbered alias for a peripheral. This is used to enumerate
|
||||
* all the peripherals of a certain type.
|
||||
|
@ -107,6 +125,19 @@ struct fdt_gpio_state {
|
|||
int fdtdec_next_alias(const void *blob, const char *name,
|
||||
enum fdt_compat_id id, int *upto);
|
||||
|
||||
/**
|
||||
* Find the compatible ID for a given node.
|
||||
*
|
||||
* Generally each node has at least one compatible string attached to it.
|
||||
* This function looks through our list of known compatible strings and
|
||||
* returns the corresponding ID which matches the compatible string.
|
||||
*
|
||||
* @param blob FDT blob to use
|
||||
* @param node Node containing compatible string to find
|
||||
* @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match
|
||||
*/
|
||||
enum fdt_compat_id fdtdec_lookup(const void *blob, int node);
|
||||
|
||||
/**
|
||||
* Find the next compatible node for a peripheral.
|
||||
*
|
||||
|
@ -166,6 +197,21 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
|
|||
s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
|
||||
s32 default_val);
|
||||
|
||||
/**
|
||||
* Look up a 64-bit integer property in a node and return it. The property
|
||||
* must have at least 8 bytes of data (2 cells). The first two cells are
|
||||
* concatenated to form a 8 bytes value, where the first cell is top half and
|
||||
* the second cell is bottom half.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param node node to examine
|
||||
* @param prop_name name of property to find
|
||||
* @param default_val default value to return if the property is not found
|
||||
* @return integer value, if found, or default_val if not
|
||||
*/
|
||||
uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
|
||||
uint64_t default_val);
|
||||
|
||||
/**
|
||||
* Checks whether a node is enabled.
|
||||
* This looks for a 'status' property. If this exists, then returns 1 if
|
||||
|
@ -342,6 +388,22 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name);
|
|||
int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
|
||||
struct fdt_gpio_state *gpio);
|
||||
|
||||
/**
|
||||
* Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
|
||||
* terminating item.
|
||||
*
|
||||
* @param blob FDT blob to use
|
||||
* @param node Node to look at
|
||||
* @param prop_name Node property name
|
||||
* @param gpio Array of gpio elements to fill from FDT. This will be
|
||||
* untouched if either 0 or an error is returned
|
||||
* @param max_count Maximum number of elements allowed
|
||||
* @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
|
||||
* be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
|
||||
*/
|
||||
int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
|
||||
struct fdt_gpio_state *gpio, int max_count);
|
||||
|
||||
/**
|
||||
* Set up a GPIO pin according to the provided gpio information. At present this
|
||||
* just requests the GPIO.
|
||||
|
@ -354,6 +416,39 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
|
|||
*/
|
||||
int fdtdec_setup_gpio(struct fdt_gpio_state *gpio);
|
||||
|
||||
/**
|
||||
* Look in the FDT for a config item with the given name and return its value
|
||||
* as a 32-bit integer. The property must have at least 4 bytes of data. The
|
||||
* value of the first cell is returned.
|
||||
*
|
||||
* @param blob FDT blob to use
|
||||
* @param prop_name Node property name
|
||||
* @param default_val default value to return if the property is not found
|
||||
* @return integer value, if found, or default_val if not
|
||||
*/
|
||||
int fdtdec_get_config_int(const void *blob, const char *prop_name,
|
||||
int default_val);
|
||||
|
||||
/**
|
||||
* Look in the FDT for a config item with the given name
|
||||
* and return whether it exists.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param prop_name property name to look up
|
||||
* @return 1, if it exists, or 0 if not
|
||||
*/
|
||||
int fdtdec_get_config_bool(const void *blob, const char *prop_name);
|
||||
|
||||
/**
|
||||
* Look in the FDT for a config item with the given name and return its value
|
||||
* as a string.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param prop_name property name to look up
|
||||
* @returns property string, NULL on error.
|
||||
*/
|
||||
char *fdtdec_get_config_string(const void *blob, const char *prop_name);
|
||||
|
||||
/*
|
||||
* Look up a property in a node and return its contents in a byte
|
||||
* array of given length. The property must have at least enough data for
|
||||
|
@ -385,4 +480,21 @@ int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
|
|||
*/
|
||||
const u8 *fdtdec_locate_byte_array(const void *blob, int node,
|
||||
const char *prop_name, int count);
|
||||
|
||||
/**
|
||||
* Look up a property in a node which contains a memory region address and
|
||||
* size. Then return a pointer to this address.
|
||||
*
|
||||
* The property must hold one address with a length. This is only tested on
|
||||
* 32-bit machines.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param node node to examine
|
||||
* @param prop_name name of property to find
|
||||
* @param ptrp returns pointer to region, or NULL if no address
|
||||
* @param size returns size of region
|
||||
* @return 0 if ok, -1 on error (propery not found)
|
||||
*/
|
||||
int fdtdec_decode_region(const void *blob, int node,
|
||||
const char *prop_name, void **ptrp, size_t *size);
|
||||
#endif
|
||||
|
|
|
@ -615,6 +615,7 @@ int fit_image_check_type(const void *fit, int noffset, uint8_t type);
|
|||
int fit_image_check_comp(const void *fit, int noffset, uint8_t comp);
|
||||
int fit_check_format(const void *fit);
|
||||
|
||||
int fit_conf_find_compat(const void *fit, const void *fdt);
|
||||
int fit_conf_get_node(const void *fit, const char *conf_uname);
|
||||
int fit_conf_get_kernel_node(const void *fit, int noffset);
|
||||
int fit_conf_get_ramdisk_node(const void *fit, int noffset);
|
||||
|
|
125
lib/fdtdec.c
125
lib/fdtdec.c
|
@ -52,28 +52,6 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
|
|||
return compat_names[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Look in the FDT for an alias with the given name and return its node.
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param name alias name to look up
|
||||
* @return node offset if found, or an error code < 0 otherwise
|
||||
*/
|
||||
static int find_alias_node(const void *blob, const char *name)
|
||||
{
|
||||
const char *path;
|
||||
int alias_node;
|
||||
|
||||
debug("find_alias_node: %s\n", name);
|
||||
alias_node = fdt_path_offset(blob, "/aliases");
|
||||
if (alias_node < 0)
|
||||
return alias_node;
|
||||
path = fdt_getprop(blob, alias_node, name, NULL);
|
||||
if (!path)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
return fdt_path_offset(blob, path);
|
||||
}
|
||||
|
||||
fdt_addr_t fdtdec_get_addr(const void *blob, int node,
|
||||
const char *prop_name)
|
||||
{
|
||||
|
@ -111,6 +89,19 @@ s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
|
|||
return default_val;
|
||||
}
|
||||
|
||||
uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
|
||||
uint64_t default_val)
|
||||
{
|
||||
const uint64_t *cell64;
|
||||
int length;
|
||||
|
||||
cell64 = fdt_getprop(blob, node, prop_name, &length);
|
||||
if (!cell64 || length < sizeof(*cell64))
|
||||
return default_val;
|
||||
|
||||
return fdt64_to_cpu(*cell64);
|
||||
}
|
||||
|
||||
int fdtdec_get_is_enabled(const void *blob, int node)
|
||||
{
|
||||
const char *cell;
|
||||
|
@ -128,7 +119,7 @@ int fdtdec_get_is_enabled(const void *blob, int node)
|
|||
return 1;
|
||||
}
|
||||
|
||||
enum fdt_compat_id fd_dec_lookup(const void *blob, int node)
|
||||
enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
|
||||
{
|
||||
enum fdt_compat_id id;
|
||||
|
||||
|
@ -171,7 +162,7 @@ int fdtdec_next_alias(const void *blob, const char *name,
|
|||
/* snprintf() is not available */
|
||||
assert(strlen(name) < MAX_STR_LEN);
|
||||
sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
|
||||
node = find_alias_node(blob, str);
|
||||
node = fdt_path_offset(blob, str);
|
||||
if (node < 0)
|
||||
return node;
|
||||
err = fdt_node_check_compatible(blob, node, compat_names[id]);
|
||||
|
@ -426,9 +417,8 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
|
|||
* @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
|
||||
* be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
|
||||
*/
|
||||
static int fdtdec_decode_gpios(const void *blob, int node,
|
||||
const char *prop_name, struct fdt_gpio_state *gpio,
|
||||
int max_count)
|
||||
int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
|
||||
struct fdt_gpio_state *gpio, int max_count)
|
||||
{
|
||||
const struct fdt_property *prop;
|
||||
const u32 *cell;
|
||||
|
@ -475,6 +465,26 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
|
|||
return err == 1 ? 0 : err;
|
||||
}
|
||||
|
||||
int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (!fdt_gpio_isvalid(gpio))
|
||||
return -1;
|
||||
|
||||
val = gpio_get_value(gpio->gpio);
|
||||
return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
|
||||
}
|
||||
|
||||
int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
|
||||
{
|
||||
if (!fdt_gpio_isvalid(gpio))
|
||||
return -1;
|
||||
|
||||
val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
|
||||
return gpio_set_value(gpio->gpio, val);
|
||||
}
|
||||
|
||||
int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
|
||||
{
|
||||
/*
|
||||
|
@ -512,3 +522,64 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node,
|
|||
return NULL;
|
||||
return cell;
|
||||
}
|
||||
|
||||
int fdtdec_get_config_int(const void *blob, const char *prop_name,
|
||||
int default_val)
|
||||
{
|
||||
int config_node;
|
||||
|
||||
debug("%s: %s\n", __func__, prop_name);
|
||||
config_node = fdt_path_offset(blob, "/config");
|
||||
if (config_node < 0)
|
||||
return default_val;
|
||||
return fdtdec_get_int(blob, config_node, prop_name, default_val);
|
||||
}
|
||||
|
||||
int fdtdec_get_config_bool(const void *blob, const char *prop_name)
|
||||
{
|
||||
int config_node;
|
||||
const void *prop;
|
||||
|
||||
debug("%s: %s\n", __func__, prop_name);
|
||||
config_node = fdt_path_offset(blob, "/config");
|
||||
if (config_node < 0)
|
||||
return 0;
|
||||
prop = fdt_get_property(blob, config_node, prop_name, NULL);
|
||||
|
||||
return prop != NULL;
|
||||
}
|
||||
|
||||
char *fdtdec_get_config_string(const void *blob, const char *prop_name)
|
||||
{
|
||||
const char *nodep;
|
||||
int nodeoffset;
|
||||
int len;
|
||||
|
||||
debug("%s: %s\n", __func__, prop_name);
|
||||
nodeoffset = fdt_path_offset(blob, "/config");
|
||||
if (nodeoffset < 0)
|
||||
return NULL;
|
||||
|
||||
nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
|
||||
if (!nodep)
|
||||
return NULL;
|
||||
|
||||
return (char *)nodep;
|
||||
}
|
||||
|
||||
int fdtdec_decode_region(const void *blob, int node,
|
||||
const char *prop_name, void **ptrp, size_t *size)
|
||||
{
|
||||
const fdt_addr_t *cell;
|
||||
int len;
|
||||
|
||||
debug("%s: %s\n", __func__, prop_name);
|
||||
cell = fdt_getprop(blob, node, prop_name, &len);
|
||||
if (!cell || (len != sizeof(fdt_addr_t) * 2))
|
||||
return -1;
|
||||
|
||||
*ptrp = (void *)fdt_addr_to_cpu(*cell);
|
||||
*size = fdt_size_to_cpu(cell[1]);
|
||||
debug("%s: size=%zx\n", __func__, *size);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue