summaryrefslogtreecommitdiffstats
path: root/configs/platform-v7a/patches
diff options
context:
space:
mode:
authorRobert Schwebel <r.schwebel@pengutronix.de>2016-07-26 22:16:06 +0200
committerRobert Schwebel <r.schwebel@pengutronix.de>2016-07-26 22:16:06 +0200
commit49292bd74f73a260927b7f3f42548e4ee4407237 (patch)
tree3e89c3b02b9d8d9e1114f8f860afb9a1109cc373 /configs/platform-v7a/patches
parentdd2c39349c6e0358cb5dc463cd02e63b0902bcf2 (diff)
downloadDistroKit-49292bd74f73a260927b7f3f42548e4ee4407237.tar.gz
DistroKit-49292bd74f73a260927b7f3f42548e4ee4407237.tar.xz
platform-beaglebone: rename to platform-v7a
In the meantime, in addition to beaglebone, this platform supports the other ARMv7 based boards (rpi2, vexpress), so rename it. Signed-off-by: Robert Schwebel <r.schwebel@pengutronix.de>
Diffstat (limited to 'configs/platform-v7a/patches')
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch1467
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0002-bootstate-Add-kernel-option-containing-the-system-th.patch43
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0003-bootstate-separate-names-from-boot-targets.patch63
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0004-bootstate-set-kernel-option-to-name-of-boot-target.patch119
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0101-beaglebone-add-state-entrie-for-mmc0-and-mmc1.patch35
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0201-rpi2-add-basic-boot-spec-devicetree-support.patch462
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/0301-Release-2016.05.0-customers-pengutronix-multi_v7-201.patch22
-rw-r--r--configs/platform-v7a/patches/barebox-2016.05.0/series22
8 files changed, 2233 insertions, 0 deletions
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch
new file mode 100644
index 0000000..08b17de
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch
@@ -0,0 +1,1467 @@
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Fri, 20 Feb 2015 09:19:14 +0100
+Subject: [PATCH] bootstate: add framework for redundant boot scenarios
+
+There are several use cases where a redundant Linux system is needed. The
+barebox,bootstate framework provides the building blocks to model different
+use cases without the need to start from the scratch over and over again.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ .../bindings/barebox/barebox,bootstate.rst | 236 +++++++
+ arch/sandbox/dts/sandbox.dts | 83 +++
+ commands/Kconfig | 5 +
+ commands/Makefile | 1 +
+ commands/bootchooser.c | 101 +++
+ common/Kconfig | 8 +
+ common/Makefile | 1 +
+ common/bootstate.c | 781 +++++++++++++++++++++
+ drivers/misc/Kconfig | 5 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/bootstate.c | 79 +++
+ include/bootstate.h | 39 +
+ 12 files changed, 1340 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/barebox/barebox,bootstate.rst
+ create mode 100644 commands/bootchooser.c
+ create mode 100644 common/bootstate.c
+ create mode 100644 drivers/misc/bootstate.c
+ create mode 100644 include/bootstate.h
+
+diff --git a/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst b/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst
+new file mode 100644
+index 000000000000..0f7131536798
+--- /dev/null
++++ b/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst
+@@ -0,0 +1,236 @@
++barebox bootstate
++=================
++
++Overview
++--------
++
++There are several use cases where a redundant Linux system is needed.
++The ``barebox,bootstate`` framework provides the building blocks to
++model different use cases without the need to start from the scratch
++over and over again.
++
++The ``barebox,bootstate`` works on abstract boot targets, each with a
++set of properties and implements an algorithm which selects the
++highest priority target to boot.
++
++A set of boot targets can be described in a devicetree node. This
++node could be part of the regular devicetree blob or it could be an
++extra devicetree for the bootstate.
++
++A bootstate node contains a description of a set of boot targets along
++with a place where to store the mutable state. Currently implemented
++backends are :ref:`barebox,state` and ``nv`` (:ref:`command_nv`)
++variables.
++
++Required properties:
++
++* ``compatible``: should be ``barebox,bootstate``;
++* ``backend-type``: should be ``state`` or ``nv``.
++
++Optional properties:
++
++* ``backend``: phandle to the :ref:`barebox,state` backend
++
++
++boot target nodes - immutable description
++-----------------------------------------
++
++These are subnodes of a bootstate node, each describing a boot
++target. The node name may end with ``@<ADDRESS>``, but the suffix is
++stripped from the target name.
++
++Optional properties:
++
++* ``default_attempts``: If the boot attempts counter is reset, this
++ value is used.
++
++Example::
++
++ bootstate: bootstate {
++ compatible = "barebox,bootstate";
++ backend-type = "state";
++ backend = <&state>;
++
++ system0 {
++ default_attempts = <3>;
++ };
++
++ system1 {
++ default_attempts = <3>;
++ };
++ };
++
++In this example a bootstate, using a :ref:`barebox,state` backend with
++two boot target nodes ``system0`` and ``system1`` is defined. When the
++boot attempts counter is reset, the default value of ``3`` is used for
++both targets.
++
++
++boot target nodes - mutable state
++---------------------------------
++
++The above example uses a :ref:`barebox,state` backend, which requires
++some additional configuration to hold the mutable
++state. :ref:`barebox,state` has to be explicidly configured, while
++``nv`` (:ref:`command_nv`) variables are created on the fly.
++
++The state of each boot target consists of the following ``uint32``
++varibles:
++
++* ``remaining_attempts``: holds the number of remaining boot attempts.
++ This variable is changed by the bootstate algorithm during boot.
++* ``priority``: defines the priority of the boot target. Higher number
++ indicate a higher priority, If two boot targets have the same
++ priority the one defined first in the device tree has precedence.
++ The ``priority`` can optionally be changed by the algorithm to 0, if
++ the boot target is decremented to ``0`` remaining boot attempts. A
++ ``priority`` of ``0`` means the boot target is **deactivated** and
++ will not be considered a valid target during further boots. If the
++ remaining attempts counter is reset, a target with priority 0 is
++ **not** changed.
++* ``ok``: this is an opaque value, it's not accessed by the bootstate
++ algorithm. It can be used be the Linux system to track the first
++ boot after an update.
++
++The bootstate can also hold a default watchdog timeout (in seconds),
++which can be activated by the bootstate algorithm.
++
++Example::
++
++ state: state {
++ magic = <0x4d433230>;
++ compatible = "barebox,state";
++ backend-type = "raw";
++ backend = <&backend_state>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootstate {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ system0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ remaining_attempts {
++ reg = <0x0 0x4>;
++ type = "uint32";
++ };
++ priority {
++ reg = <0x4 0x4>;
++ type = "uint32";
++ };
++ ok {
++ reg = <0x8 0x4>;
++ type = "uint32";
++ };
++ };
++
++ system1 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ remaining_attempts {
++ reg = <0x10 0x4>;
++ type = "uint32";
++ };
++ priority {
++ reg = <0x14 0x4>;
++ type = "uint32";
++ };
++ ok {
++ reg = <0x18 0x4>;
++ type = "uint32";
++ };
++ };
++
++ watchdog_timeout {
++ reg = <0x20 0x4>;
++ type = "uint32";
++ default = <60>;
++ };
++ };
++ };
++
++This example defines two boot targets (``system0`` and ``system1``) and
++a watchdog timeout of ``60`` seconds.
++
++
++Backends
++--------
++
++Currently two backends exist. The :ref:`barebox,state` backend is a
++bit more complicated to setup, as all boot target have to be described
++in the referenced :ref:`barebox,state` in the device tree. On the
++upside, the advantages of the (possible redundant storage, etc...) of
++the :ref:`barebox,state` is gained for free.
++
++The :ref:`command_nv` backend is a lot simpler, no special setup is
++needed, it should run on every board, which already implements a
++read/writeable barebox environment.
++
++
++Algorithm
++---------
++
++The low level algorithm is implemented by the
++``bootstate_get_target()`` function. Its job is to iterate over all
++boot sources and return the name (as a string) of the choosen boot
++target.
++
++The algorithm iterates over all boot targets defined under the
++associated device tree node and picks the one with the highest
++``priority`` (higher number have a higher priority) where the
++``remaining_attempts`` is greater than zero. A pointer to the name of
++the boot target is returned, the string should be freed via ``free()``.
++
++The behaviour can be modified with the flags paramter. The following
++flags are currently supported:
++
++* ``BOOTCHOOSER_FLAG_ATTEMPTS_KEEP``: the ``remaining_attempts``
++ counter of the choosen boot target is not changed.
++* ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC``: the ``remaining_attempts``
++ counter of the choosen boot target is decremented by one.
++* ``BOOTCHOOSER_FLAG_ATTEMPTS_RESET``: the ``remaining_attempts``
++ counter of all *active* boot targets (those with ``priority > 0``)
++ are reset to their default values as defined in the immutable
++ description by ``default_attempts``.
++* ``BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS``: if used together
++ with ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC`` and the
++ ``remaining_attempts`` counter of the choosen boot target is
++ decremented to ``0``, the boot target is deactivated for further
++ boot attempts (although *this* boot is attemped as usual). This is
++ done by setting the ``priority`` to ``0``.
++* ``BOOTCHOOSER_FLAG_VERBOSE``: increases the verbosity of the output
++
++
++Frontend
++--------
++
++The shell command ``bootchooser`` (:ref:`command_bootchooser`) can be
++used to choose and start a boot target by a shell one-liner. The
++command picks the boot target with the highest priority and calls the
++``boot`` (:ref:`command_boot`) command with the selected boot target
++as its first and only parameter.
++
++The ``bootchooser`` command implements command line paramter versions
++of the above described flags:
++
++* ``-k``: keep boot attempts
++* ``-d``: decrement boot attempts
++* ``-r``: reset boot attempts
++* ``-z``: deactivate on zero remaining attempts
++* ``-v``: verbose output
++
++Next to the standard parameters, these additional options are
++implemented:
++
++* ``-D``: dryrun - do not boot (all other functionality is active) - a
++ specified watchdog timeout will be activated.
++* ``-R``: retry - if booting fails, then chose next target, but
++ decrement its attempts. Note: if the current target has still the
++ highest priority and remaining attemts, it will be selected again.
++* ``-w <TIMEOUT_IN_SEC>``: activate watchdog - if no parameter is
++ given, the timeout from the device tree is used. A given parameter
++ overwrites the device tree default.
+diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
+index 2595aa13fa62..e2bc8f76c2e3 100644
+--- a/arch/sandbox/dts/sandbox.dts
++++ b/arch/sandbox/dts/sandbox.dts
+@@ -3,5 +3,88 @@
+ #include "skeleton.dtsi"
+
+ / {
++ aliases {
++ state = &state;
++ };
+
++ state: state {
++ magic = <0x4d433230>;
++ compatible = "barebox,state";
++ backend-type = "dtb";
++ backend = "/fd0";
++
++ bootstate {
++ system0 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ remaining_attempts {
++ reg = <0x0 0x4>;
++ type = "uint32";
++ };
++ priority {
++ reg = <0x4 0x4>;
++ type = "uint32";
++ };
++ ok {
++ reg = <0x8 0x4>;
++ type = "uint32";
++ };
++ };
++
++ system1 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ remaining_attempts {
++ reg = <0x10 0x4>;
++ type = "uint32";
++ };
++ priority {
++ reg = <0x14 0x4>;
++ type = "uint32";
++ };
++ ok {
++ reg = <0x18 0x4>;
++ type = "uint32";
++ };
++ };
++
++ factory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ remaining_attempts {
++ reg = <0x20 0x4>;
++ type = "uint32";
++ };
++ priority {
++ reg = <0x24 0x4>;
++ type = "uint32";
++ };
++ ok {
++ reg = <0x28 0x4>;
++ type = "uint32";
++ };
++ };
++ };
++ };
++
++ bootstate: bootstate {
++ compatible = "barebox,bootstate";
++ backend-type = "state"; // or "nv", or "efivar"
++ backend = <&state>;
++
++ system0 {
++ default_attempts = <3>;
++ };
++
++ system1 {
++ default_attempts = <3>;
++ };
++
++ factory {
++ default_attempts = <3>;
++ };
++ };
+ };
+diff --git a/commands/Kconfig b/commands/Kconfig
+index 875c5f4f01ed..603e887b15ec 100644
+--- a/commands/Kconfig
++++ b/commands/Kconfig
+@@ -2189,6 +2189,11 @@ config CMD_SPD_DECODE
+ help
+ decode spd eeprom
+
++config CMD_BOOTCHOOSER
++ tristate
++ depends on BOOTSTATE
++ prompt "bootchooser"
++
+ # end Miscellaneous commands
+ endmenu
+
+diff --git a/commands/Makefile b/commands/Makefile
+index f1b482f04934..bb3b40809af5 100644
+--- a/commands/Makefile
++++ b/commands/Makefile
+@@ -117,3 +117,4 @@ obj-$(CONFIG_CMD_DHRYSTONE) += dhrystone.o
+ obj-$(CONFIG_CMD_SPD_DECODE) += spd_decode.o
+ obj-$(CONFIG_CMD_MMC_EXTCSD) += mmc_extcsd.o
+ obj-$(CONFIG_CMD_NAND_BITFLIP) += nand-bitflip.o
++obj-$(CONFIG_CMD_BOOTCHOOSER) += bootchooser.o
+diff --git a/commands/bootchooser.c b/commands/bootchooser.c
+new file mode 100644
+index 000000000000..06ca5e41d527
+--- /dev/null
++++ b/commands/bootchooser.c
+@@ -0,0 +1,101 @@
++/*
++ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
++ * Copyright (C) 2015 Marc Kleine-Budde <mkl@pengutronix.de>
++ *
++ * 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.
++ *
++ * 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 <bootstate.h>
++#include <command.h>
++#include <common.h>
++#include <getopt.h>
++#include <malloc.h>
++#include <stdio.h>
++
++static int do_bootchooser(int argc, char *argv[])
++{
++ unsigned flags = 0, timeout = 0;
++ char *name = NULL;
++ int opt, ret;
++
++ while ((opt = getopt(argc, argv, "kdrzvDRw::")) > 0) {
++ switch (opt) {
++ case 'k':
++ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_KEEP;
++ break;
++ case 'd':
++ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_DEC;
++ break;
++ case 'r':
++ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_RESET;
++ break;
++ case 'z':
++ flags |= BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS;
++ break;
++ case 'v':
++ flags |= BOOTCHOOSER_FLAG_VERBOSE;
++ break;
++ case 'D':
++ flags |= BOOTCHOOSER_FLAG_DRYRUN;
++ break;
++ case 'R':
++ flags |= BOOTCHOOSER_FLAG_RETRY_WITH_DEC;
++ break;
++ case 'w':
++ if (optarg)
++ timeout = simple_strtoul(optarg, NULL, 0);
++ else
++ flags |= BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE;
++ flags |= BOOTCHOOSER_FLAG_WATCHDOG_ENABLE;
++ break;
++ default:
++ return COMMAND_ERROR_USAGE;
++ }
++ }
++
++ if (optind < argc)
++ name = argv[optind];
++
++ if (!(flags & (BOOTCHOOSER_FLAG_ATTEMPTS_KEEP |
++ BOOTCHOOSER_FLAG_ATTEMPTS_DEC |
++ BOOTCHOOSER_FLAG_ATTEMPTS_RESET))) {
++ bootstate_info();
++ return 0;
++ }
++
++ if ((flags & BOOTCHOOSER_FLAG_ATTEMPTS_KEEP) &&
++ (flags & (BOOTCHOOSER_FLAG_ATTEMPTS_DEC | BOOTCHOOSER_FLAG_ATTEMPTS_RESET)))
++ return COMMAND_ERROR_USAGE;
++
++ ret = bootstate_bootchooser(name, flags, timeout);
++
++ return ret ? COMMAND_ERROR : COMMAND_SUCCESS;
++}
++
++BAREBOX_CMD_HELP_START(bootchooser)
++BAREBOX_CMD_HELP_TEXT("Options:")
++BAREBOX_CMD_HELP_OPT ("-k","keep - boot, don't modify attempts counter")
++BAREBOX_CMD_HELP_OPT ("-d","decrement - boot, but decrement attempts counter by one")
++BAREBOX_CMD_HELP_OPT ("-r","reset - boot, but reset _all_ attempts counters to default")
++BAREBOX_CMD_HELP_OPT ("-z","deactivate chosen target on zero remaining boot attempts")
++BAREBOX_CMD_HELP_OPT ("-v","verbose output")
++BAREBOX_CMD_HELP_OPT ("-D","dryrun - do not boot, but handle watchdog and reset")
++BAREBOX_CMD_HELP_OPT ("-R","retry - boot, retry next boot target and decrement attempts")
++BAREBOX_CMD_HELP_OPT ("-w","activate watchdog, use timeout specified in <BOOTSTATE>.watchdog_timeout")
++BAREBOX_CMD_HELP_END
++
++BAREBOX_CMD_START(bootchooser)
++ .cmd = do_bootchooser,
++ BAREBOX_CMD_DESC("automatically select a boot target and boot")
++ BAREBOX_CMD_OPTS("[-kdrzvDR] -w <TIMEOUT> [BOOTSTATE]")
++ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
++ BAREBOX_CMD_HELP(cmd_bootchooser_help)
++BAREBOX_CMD_END
+diff --git a/common/Kconfig b/common/Kconfig
+index 7c09e8c117f1..f17769661ee6 100644
+--- a/common/Kconfig
++++ b/common/Kconfig
+@@ -792,6 +792,14 @@ config STATE_CRYPTO
+ See Documentation/devicetree/bindings/barebox/barebox,state.rst
+ for more information.
+
++config BOOTSTATE
++ bool "bootstate infrastructure"
++ depends on OF_BAREBOX_DRIVERS
++ select ENVIRONMENT_VARIABLES
++ select OFTREE
++ select PARAMETER
++ select BOOTSTATE_DRV
++
+ config RESET_SOURCE
+ bool "detect Reset cause"
+ depends on GLOBALVAR
+diff --git a/common/Makefile b/common/Makefile
+index d99ca7b7ac74..5505449874ad 100644
+--- a/common/Makefile
++++ b/common/Makefile
+@@ -46,6 +46,7 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o
+ obj-$(CONFIG_SHELL_SIMPLE) += parser.o
+ obj-$(CONFIG_STATE) += state.o
+ obj-$(CONFIG_RATP) += ratp.o
++obj-$(CONFIG_BOOTSTATE) += bootstate.o
+ obj-$(CONFIG_UIMAGE) += image.o uimage.o
+ obj-$(CONFIG_FITIMAGE) += image-fit.o
+ obj-$(CONFIG_MENUTREE) += menutree.o
+diff --git a/common/bootstate.c b/common/bootstate.c
+new file mode 100644
+index 000000000000..3dc18813064d
+--- /dev/null
++++ b/common/bootstate.c
+@@ -0,0 +1,781 @@
++/*
++ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
++ * Copyright (C) 2015 Marc Kleine-Budde <mkl@pengutronix.de>
++ *
++ * 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.
++ *
++ * 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 <bootstate.h>
++#include <common.h>
++#include <envfs.h>
++#include <environment.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <fs.h>
++#include <globalvar.h>
++#include <init.h>
++#include <ioctl.h>
++#include <libbb.h>
++#include <libfile.h>
++#include <malloc.h>
++#include <net.h>
++#include <printk.h>
++#include <state.h>
++#include <stdio.h>
++#include <watchdog.h>
++#include <xfuncs.h>
++
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/mtd/mtd-abi.h>
++#include <linux/mtd/mtd.h>
++
++#include <asm/unaligned.h>
++
++/* list of all registered bootstate instances */
++static LIST_HEAD(bootstate_list);
++
++struct state_backend;
++
++struct bootstate {
++ struct device_d dev;
++ const char *name;
++ struct list_head list;
++ struct list_head targets;
++ struct list_head targets_unsorted;
++ struct bootstate_backend *backend;
++ bool dirty;
++};
++
++struct bootstate_backend {
++ int (*load)(struct bootstate_backend *backend, struct bootstate *bootstate);
++ int (*save)(struct bootstate_backend *backend, struct bootstate *bootstate);
++ const char *name;
++ const char *path;
++};
++
++struct bootstate_target {
++ struct list_head list;
++ struct list_head list_unsorted;
++
++ /* state */
++ unsigned int priority;
++ unsigned int remaining_attempts;
++ bool ok;
++
++ /* spec */
++ const char *name;
++ unsigned int default_attempts;
++};
++
++static void pr_target(struct bootstate *bootstate, struct bootstate_target *target)
++{
++ printf("%s: target: name=%s prio=%u, ok=%d, rem=%u, def=%u\n",
++ bootstate->name, target->name, target->priority, target->ok,
++ target->remaining_attempts, target->default_attempts);
++}
++
++static struct bootstate *bootstate_new(const char *name)
++{
++ struct bootstate *bootstate;
++ int ret;
++
++ bootstate = xzalloc(sizeof(*bootstate));
++ safe_strncpy(bootstate->dev.name, name, MAX_DRIVER_NAME);
++ bootstate->name = bootstate->dev.name;
++ bootstate->dev.id = DEVICE_ID_DYNAMIC;
++ INIT_LIST_HEAD(&bootstate->targets);
++ INIT_LIST_HEAD(&bootstate->targets_unsorted);
++
++ ret = register_device(&bootstate->dev);
++ if (ret) {
++ free(bootstate);
++ return ERR_PTR(ret);
++ }
++
++ list_add_tail(&bootstate->list, &bootstate_list);
++
++ return bootstate;
++}
++
++void bootstate_release(struct bootstate *bootstate)
++{
++ list_del(&bootstate->list);
++ unregister_device(&bootstate->dev);
++ free(bootstate);
++}
++
++static int bootstate_target_compare(struct list_head *a, struct list_head *b)
++{
++ struct bootstate_target *bootstate_a = list_entry(a, struct bootstate_target, list);
++ struct bootstate_target *bootstate_b = list_entry(b, struct bootstate_target, list);
++
++ /* order descending */
++ return bootstate_a->priority >= bootstate_b->priority ? -1 : 1;
++}
++
++static void bootstate_target_add(struct bootstate *bootstate, struct bootstate_target *target)
++{
++ list_del(&target->list);
++ list_add_sort(&target->list, &bootstate->targets, bootstate_target_compare);
++}
++
++static int bootstate_variable_read_u32(const struct bootstate *bootstate,
++ const char *name, uint32_t *out_val)
++{
++ char *var;
++ int ret;
++
++ var = asprintf("%s.%s.%s", bootstate->backend->path, bootstate->name, name);
++ ret = getenv_uint(var, out_val);
++ free(var);
++
++ return ret;
++}
++
++static int bootstate_backend_variable_read_target_u32(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ const struct bootstate_target *target,
++ const char *name, uint32_t *out_val)
++{
++ char *var;
++ int ret;
++
++ var = asprintf("%s.%s.%s.%s", backend->path, bootstate->name,
++ target->name, name);
++ ret = getenv_uint(var, out_val);
++ free(var);
++
++ return ret;
++}
++
++static int bootstate_backend_variable_write_target_u32(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ const struct bootstate_target *target,
++ const char *name, uint32_t in_val)
++{
++ char *var;
++ char *val;
++ int ret;
++
++ var = asprintf("%s.%s.%s.%s", backend->path, bootstate->name,
++ target->name, name);
++ val = asprintf("%d", in_val);
++ ret = setenv(var, val);
++ free(val);
++ free(var);
++
++ return ret;
++}
++
++static int bootstate_variable_nv_init_u32(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ const struct bootstate_target *target,
++ const char *name)
++{
++ char *var;
++ int ret;
++
++ var = asprintf("%s.%s.%s", bootstate->name, target->name, name);
++ ret = nvvar_add(var, "0");
++ free(var);
++
++ return ret;
++}
++
++static struct bootstate_target *bootstate_target_find(const struct bootstate *bootstate,
++ const char *name)
++{
++ struct bootstate_target *target;
++
++ list_for_each_entry(target, &bootstate->targets, list) {
++ if (!strcmp(target->name, name))
++ return target;
++ }
++
++ return ERR_PTR(-ENOENT);
++}
++
++static int bootstate_target_from_node(struct bootstate *bootstate, const struct device_node *node, bool create)
++{
++ struct bootstate_target *target;
++ char *name, *indexs;
++ int ret;
++
++ name = xstrdup(node->name);
++ indexs = strchr(name, '@');
++ if (indexs)
++ *indexs++ = 0;
++
++ if (create) {
++ /* create*/
++ target = xzalloc(sizeof(*target));
++
++ target->name = xstrdup(name);
++ list_add_tail(&target->list, &bootstate->targets);
++ list_add_tail(&target->list_unsorted,
++ &bootstate->targets_unsorted);
++ } else {
++ target = bootstate_target_find(bootstate, name);
++ if (IS_ERR(target)) {
++ int ret = PTR_ERR(target);
++ pr_err("no such boot target: %s: %s\n",
++ name, strerror(-ret));
++ return ret;
++ }
++ }
++
++ /* init */
++ ret = of_property_read_u32(node, "default_attempts",
++ &target->default_attempts);
++ if (ret)
++ return ret;
++
++ free(name);
++
++ return 0;
++}
++
++static int bootstate_from_node(struct bootstate *bootstate,
++ const struct device_node *node, bool create)
++{
++ struct device_node *child;
++ int ret;
++
++ for_each_child_of_node(node, child) {
++ ret = bootstate_target_from_node(bootstate, child, create);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int bootstate_backend_load_one(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ struct bootstate_target *target)
++{
++ uint32_t tmp;
++ int ret;
++
++ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target,
++ "remaining_attempts",
++ &target->remaining_attempts);
++ if (ret)
++ return ret;
++
++ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target,
++ "priority", &target->priority);
++ if (ret)
++ return ret;
++
++ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target,
++ "ok", &tmp);
++ if (ret)
++ return ret;
++
++ target->ok = !!tmp;
++
++ return ret;
++}
++
++static int bootstate_backend_load(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ struct bootstate_target *target;
++ int ret;
++
++ list_for_each_entry(target, &bootstate->targets_unsorted, list_unsorted) {
++ ret = bootstate_backend_load_one(backend, bootstate, target);
++ if (ret)
++ return ret;
++ bootstate_target_add(bootstate, target);
++ }
++
++ return 0;
++}
++
++static int bootstate_backend_save_one(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ struct bootstate_target *target)
++{
++ int ret;
++
++ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target,
++ "remaining_attempts",
++ target->remaining_attempts);
++ if (ret)
++ return ret;
++
++ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target,
++ "priority", target->priority);
++ if (ret)
++ return ret;
++
++ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target,
++ "ok", target->ok);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int bootstate_backend_save(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate)
++{
++ struct bootstate_target *target;
++ int ret;
++
++ list_for_each_entry(target, &bootstate->targets, list) {
++ ret = bootstate_backend_save_one(backend, bootstate, target);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int bootstate_backend_nv_init_one(const struct bootstate_backend *backend,
++ const struct bootstate *bootstate,
++ struct bootstate_target *target)
++{
++ int ret;
++
++ ret = bootstate_variable_nv_init_u32(backend, bootstate, target,
++ "remaining_attempts");
++ if (ret)
++ return ret;
++
++ ret = bootstate_variable_nv_init_u32(backend, bootstate, target,
++ "priority");
++ if (ret)
++ return ret;
++
++ ret = bootstate_variable_nv_init_u32(backend, bootstate, target,
++ "ok");
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int bootstate_backend_nv_init(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ struct bootstate_target *target;
++ int ret;
++
++ list_for_each_entry(target, &bootstate->targets_unsorted, list_unsorted) {
++ ret = bootstate_backend_nv_init_one(backend, bootstate, target);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static int bootstate_backend_nv_save(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ int ret;
++
++ ret = bootstate_backend_save(backend, bootstate);
++ if (ret)
++ return ret;
++
++ return envfs_save(NULL, NULL, 0);
++}
++
++static int bootstate_backend_nv_load(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ return bootstate_backend_load(backend, bootstate);
++}
++
++struct bootstate_backend_nv {
++ struct bootstate_backend backend;
++};
++
++int bootstate_backend_nv(struct bootstate *bootstate)
++{
++ struct bootstate_backend_nv *backend_nv;
++ struct bootstate_backend *backend;
++
++ if (bootstate->backend)
++ return -EBUSY;
++
++ backend_nv = xzalloc(sizeof(*backend_nv));
++ backend = &backend_nv->backend;
++
++ backend->load = bootstate_backend_nv_load;
++ backend->save = bootstate_backend_nv_save;
++ backend->name = "nv";
++ backend->path = "nv";
++
++ bootstate->backend = backend;
++
++ return bootstate_backend_nv_init(backend, bootstate);
++}
++
++struct bootstate_backend_state {
++ struct bootstate_backend backend;
++ struct state *state;
++};
++
++static int bootstate_backend_state_save(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ struct bootstate_backend_state *backend_state =
++ container_of(backend, struct bootstate_backend_state, backend);
++ int ret;
++
++ ret = bootstate_backend_save(backend, bootstate);
++ if (ret)
++ return ret;
++
++ return state_save(backend_state->state);
++}
++
++static int bootstate_backend_state_load(struct bootstate_backend *backend,
++ struct bootstate *bootstate)
++{
++ return bootstate_backend_load(backend, bootstate);
++}
++
++int bootstate_backend_state(struct bootstate *bootstate, const struct device_node *node)
++{
++ struct bootstate_backend_state *backend_state;
++ struct bootstate_backend *backend;
++ const struct device_node *state_node;
++ struct state *state;
++
++ if (bootstate->backend)
++ return -EBUSY;
++
++ state_node = of_parse_phandle(node, "backend", 0);
++ if (!state_node)
++ return -EINVAL;
++
++ state = state_by_node(state_node);
++ if (!state)
++ return -EPROBE_DEFER;
++
++ backend_state = xzalloc(sizeof(*backend_state));
++ backend_state->state = state;
++
++ backend = &backend_state->backend;
++ backend->load = bootstate_backend_state_load;
++ backend->save = bootstate_backend_state_save;
++ backend->name = "state";
++
++ bootstate->backend = backend;
++
++ return state_get_name(backend_state->state, &backend->path);
++}
++
++/*
++ * bootstate_new_from_node - create a new bootstate instance from a device_node
++ *
++ * @name The name of the new bootstate instance
++ * @node The device_node describing the new bootstate instance
++ */
++struct bootstate *bootstate_new_from_node(const char *name, const struct device_node *node)
++{
++ struct bootstate *bootstate;
++ int ret;
++
++ pr_debug("%s: node=%s, name=%s\n", __func__, node->full_name, name);
++
++ bootstate = bootstate_new(name);
++ if (!bootstate)
++ return ERR_PTR(-EINVAL);
++
++ ret = bootstate_from_node(bootstate, node, true);
++ if (ret) {
++ bootstate_release(bootstate);
++ return ERR_PTR(ret);
++ }
++
++ return bootstate;
++}
++
++/*
++ * bootstate_by_name - find a bootstate instance by name
++ *
++ * @name The name of the state instance
++ */
++struct bootstate *bootstate_by_name(const char *name)
++{
++ struct bootstate *bs;
++
++ list_for_each_entry(bs, &bootstate_list, list) {
++ if (!strcmp(name, bs->name))
++ return bs;
++ }
++
++ return NULL;
++}
++
++/*
++ * bootstate_load - load a bootstate from the backing store
++ *
++ * @bootstate The state instance to load
++ */
++static int bootstate_load(struct bootstate *bootstate)
++{
++ int ret;
++
++ if (!bootstate->backend)
++ return -ENOSYS;
++
++ ret = bootstate->backend->load(bootstate->backend, bootstate);
++ if (ret)
++ bootstate->dirty = 1;
++ else
++ bootstate->dirty = 0;
++
++ return ret;
++}
++
++/*
++ * bootstate_save - save a bootstate to the backing store
++ *
++ * @bootstate The bootstate instance to save
++ */
++static int bootstate_save(struct bootstate *bootstate)
++{
++ int ret;
++
++ if (!bootstate->dirty)
++ return 0;
++
++ if (!bootstate->backend)
++ return -ENOSYS;
++
++ ret = bootstate->backend->save(bootstate->backend, bootstate);
++ if (ret)
++ return ret;
++
++ bootstate->dirty = 0;
++
++ return 0;
++}
++
++void bootstate_info(void)
++{
++ struct bootstate *bootstate;
++
++ printf("registered bootstate instances:\n");
++
++ list_for_each_entry(bootstate, &bootstate_list, list) {
++ printf("%-20s ", bootstate->name);
++ printf("(backend: %s, path: %s)\n",
++ bootstate->backend->name, bootstate->backend->path);
++ }
++}
++
++#define __BF(arg) [__BOOTCHOOSER_FLAG_##arg##_SHIFT] = __stringify(arg)
++
++static const char * const bootstate_flags_str[] = {
++ __BF(ATTEMPTS_KEEP),
++ __BF(ATTEMPTS_DEC),
++ __BF(ATTEMPTS_RESET),
++ __BF(DEACTIVATE_ON_ZERO_ATTEMPTS),
++ __BF(VERBOSE),
++ __BF(DRYRUN),
++ __BF(RETRY_WITH_DEC),
++ __BF(WATCHDOG_ENABLE),
++ __BF(WATCHDOG_TIMEOUT_FROM_STATE),
++};
++
++#undef __BF
++
++#define pr(verbose, format, args...) \
++ ({ \
++ (verbose) ? pr_info((format), ##args) : 0; \
++ })
++
++void _pr_flags(struct bootstate *bootstate, unsigned flags)
++{
++ int i;
++
++ pr_info("%s: flags=0x%08x\n", bootstate->name, flags);
++
++ for (i = 0; i < ARRAY_SIZE(bootstate_flags_str); i++) {
++ if (flags & (1 << i))
++ pr_info("%s: -> %s\n", bootstate->name,
++ bootstate_flags_str[i]);
++ }
++}
++
++#define pr_flags(verbose, bootstate, flags) \
++ ({ \
++ (verbose) ? _pr_flags(bootstate, flags) : 0; \
++ })
++
++/*
++ * bootstate_get_target - create a new state instance from a device_node
++ *
++ * @bootstate the bootstate instance to work in
++ * @flags supported flags:
++ * BOOTCHOOSER_FLAG_VERBOSE
++ * BOOTCHOOSER_FLAG_ATTEMPTS_KEEP
++ * BOOTCHOOSER_FLAG_ATTEMPTS_DEC
++ * BOOTCHOOSER_FLAG_ATTEMPTS_RESET
++ * BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS
++ * @target_out a string to the choosen boot target is returned via
++ * this paramater
++ */
++int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out)
++{
++ struct bootstate_target *target;
++ int ret;
++ bool found = false;
++ bool v = flags & BOOTCHOOSER_FLAG_VERBOSE;
++
++ pr_flags(v, bootstate, flags);
++
++ ret = bootstate_load(bootstate);
++ if (ret)
++ return ret;
++
++ if (flags & BOOTCHOOSER_FLAG_ATTEMPTS_RESET) {
++ list_for_each_entry(target, &bootstate->targets, list) {
++ if (target->priority == 0)
++ continue;
++
++ target->remaining_attempts = target->default_attempts;
++ bootstate->dirty = true;
++
++ pr(v, "%s: target: name=%s setting rem to %d due to %s\n",
++ bootstate->name, target->name, target->default_attempts,
++ bootstate_flags_str[__BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT]);
++ }
++ pr(v, "%s: --------\n", bootstate->name);
++ }
++
++ list_for_each_entry(target, &bootstate->targets, list) {
++ pr_target(bootstate, target);
++
++ if (found)
++ continue;
++
++ if (target->priority == 0) {
++ pr(v, "%s: name=%s prio=%d - trying next\n",
++ bootstate->name, target->name, target->priority);
++ continue;
++ }
++
++ if (target->remaining_attempts == 0) {
++ pr(v, "%s: name=%s remaining attempts == 0 - trying next\n",
++ bootstate->name, target->name);
++ continue;
++ }
++
++ if (flags & BOOTCHOOSER_FLAG_ATTEMPTS_DEC) {
++ bootstate->dirty = true;
++ target->remaining_attempts--;
++
++ pr(v, "%s: name=%s decrementing remaining_attempts to %d due to %s\n",
++ bootstate->name, target->name,
++ target->remaining_attempts,
++ bootstate_flags_str[__BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT]);
++
++ if ((target->remaining_attempts == 0) &&
++ (flags & BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS)) {
++ target->priority = 0;
++
++ pr(v, "%s: name=%s deactivating target (setting priority = 0) due to %s\n",
++ bootstate->name, target->name,
++ bootstate_flags_str[__BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT]);
++ }
++ }
++
++ found = true;
++ *target_out = strdup(target->name);
++ pr_debug("%s: selected target '%s'\n", __func__, target->name);
++ if (!v)
++ goto out;
++
++ pr(v, "%s: --- other bootsources ---\n", bootstate->name);
++ }
++
++ out:
++ bootstate_save(bootstate);
++
++ if (!found)
++ return -ENOENT;
++
++ return 0;
++}
++
++int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout)
++{
++ struct bootstate *bootstate;
++ bool v = flags & BOOTCHOOSER_FLAG_VERBOSE;
++ char *target;
++ int ret;
++
++ if (!name)
++ name = "bootstate";
++
++ bootstate = bootstate_by_name(name);
++ if (!bootstate) {
++ pr_err("Bootstate '%s' not found.\n", name);
++ return -ENODEV;
++ }
++
++ if (flags & BOOTCHOOSER_FLAG_WATCHDOG_ENABLE) {
++ if (flags & BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE) {
++ ret = bootstate_variable_read_u32(bootstate, "watchdog_timeout",
++ &timeout);
++ if (ret)
++ return ret;
++ }
++
++ if (timeout != 0) {
++ pr(v, "%s: starting watchdog with timeout=%ds\n",
++ __func__, timeout);
++
++ ret = watchdog_set_timeout(timeout);
++ if (ret)
++ return ret;
++ }
++ }
++
++ while (true) {
++ char *cmd;
++
++ ret = bootstate_get_target(bootstate, flags, &target);
++ if (ret)
++ return ret;
++
++ cmd = asprintf("boot %s", target);
++ free(target);
++ pr_info("%srunning: %s...\n",
++ flags & BOOTCHOOSER_FLAG_DRYRUN ? "not " : "", cmd);
++ if (!(flags & BOOTCHOOSER_FLAG_DRYRUN))
++ ret = run_command(cmd);
++ free(cmd);
++
++ if (flags & BOOTCHOOSER_FLAG_RETRY_WITH_DEC) {
++ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_DEC;
++ flags &= ~(BOOTCHOOSER_FLAG_ATTEMPTS_RESET |
++ BOOTCHOOSER_FLAG_ATTEMPTS_KEEP);
++ continue;
++ }
++
++ return ret;
++ }
++
++ return -ENOENT;
++}
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 7a5b14697efd..2459051e1db1 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -19,4 +19,9 @@ config STATE_DRV
+ tristate "state driver"
+ depends on STATE
+
++config BOOTSTATE_DRV
++ tristate "bootstate driver"
++ depends on BOOTSTATE
++ depends on STATE
++
+ endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 487e4b8ba2e5..603e14ebb5de 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -5,3 +5,4 @@
+ obj-$(CONFIG_JTAG) += jtag.o
+ obj-$(CONFIG_SRAM) += sram.o
+ obj-$(CONFIG_STATE_DRV) += state.o
++obj-$(CONFIG_BOOTSTATE_DRV) += bootstate.o
+diff --git a/drivers/misc/bootstate.c b/drivers/misc/bootstate.c
+new file mode 100644
+index 000000000000..3ec9b8fda86b
+--- /dev/null
++++ b/drivers/misc/bootstate.c
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2013 Sascha Hauer <s.hauer@pengutronix.de>
++ * Copyright (C) 2015 Marc Kleine-Budde <mkl@pengutronix.de>
++ *
++ * 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.
++ *
++ * 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 <bootstate.h>
++#include <driver.h>
++#include <init.h>
++#include <malloc.h>
++#include <of.h>
++#include <printk.h>
++#include <string.h>
++
++#include <linux/err.h>
++
++static int bootstate_probe(struct device_d *dev)
++{
++ struct device_node *np = dev->device_node;
++ struct bootstate *bootstate;
++ const char *alias;
++ const char *backend_type = NULL;
++ int ret;
++
++ if (!np)
++ return -EINVAL;
++
++ alias = of_alias_get(np);
++ if (!alias)
++ alias = "bootstate";
++
++ bootstate = bootstate_new_from_node(alias, np);
++ if (IS_ERR(bootstate))
++ return PTR_ERR(bootstate);
++
++ of_property_read_string(np, "backend-type", &backend_type);
++ if (!strcmp(backend_type, "state")) {
++ ret = bootstate_backend_state(bootstate, np);
++ } else if (!strcmp(backend_type, "nv")) {
++ ret = bootstate_backend_nv(bootstate);
++ } else {
++ dev_warn(dev, "invalid backend type: %s\n", backend_type);
++ ret = -ENODEV;
++ goto out_release;
++ }
++
++ if (ret)
++ goto out_release;
++
++ return 0;
++
++ out_release:
++ bootstate_release(bootstate);
++ return ret;
++}
++
++static __maybe_unused struct of_device_id bootstate_ids[] = {
++ {
++ .compatible = "barebox,bootstate",
++ }, {
++ /* sentinel */
++ }
++};
++
++static struct driver_d bootstate_driver = {
++ .name = "bootstate",
++ .probe = bootstate_probe,
++ .of_compatible = DRV_OF_COMPAT(bootstate_ids),
++};
++device_platform_driver(bootstate_driver);
+diff --git a/include/bootstate.h b/include/bootstate.h
+new file mode 100644
+index 000000000000..22631c902f60
+--- /dev/null
++++ b/include/bootstate.h
+@@ -0,0 +1,39 @@
++#ifndef __BOOTSTATE_H
++#define __BOOTSTATE_H
++
++#include <of.h>
++
++struct bootstate *bootstate_new_from_node(const char *name, const struct device_node *node);
++struct bootstate *bootstate_find_by_name(const char *name);
++struct bootstate *bootstate_by_name(const char *name);
++void bootstate_release(struct bootstate *bootstate);
++void bootstate_info(void);
++int bootstate_backend_nv(struct bootstate *bootstate);
++int bootstate_backend_state(struct bootstate *bootstate, const struct device_node *node);
++
++enum {
++ __BOOTCHOOSER_FLAG_ATTEMPTS_KEEP_SHIFT,
++ __BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT,
++ __BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT,
++ __BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT,
++ __BOOTCHOOSER_FLAG_VERBOSE_SHIFT,
++ __BOOTCHOOSER_FLAG_DRYRUN_SHIFT,
++ __BOOTCHOOSER_FLAG_RETRY_WITH_DEC_SHIFT,
++ __BOOTCHOOSER_FLAG_WATCHDOG_ENABLE_SHIFT,
++ __BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE_SHIFT,
++};
++
++#define BOOTCHOOSER_FLAG_ATTEMPTS_KEEP (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_KEEP_SHIFT)
++#define BOOTCHOOSER_FLAG_ATTEMPTS_DEC (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT)
++#define BOOTCHOOSER_FLAG_ATTEMPTS_RESET (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT)
++#define BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS (1 << __BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT)
++#define BOOTCHOOSER_FLAG_VERBOSE (1 << __BOOTCHOOSER_FLAG_VERBOSE_SHIFT)
++#define BOOTCHOOSER_FLAG_DRYRUN (1 << __BOOTCHOOSER_FLAG_DRYRUN_SHIFT)
++#define BOOTCHOOSER_FLAG_RETRY_WITH_DEC (1 << __BOOTCHOOSER_FLAG_RETRY_WITH_DEC_SHIFT)
++#define BOOTCHOOSER_FLAG_WATCHDOG_ENABLE (1 << __BOOTCHOOSER_FLAG_WATCHDOG_ENABLE_SHIFT)
++#define BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE (1 << __BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE_SHIFT)
++
++int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out);
++int bootstate_bootchooser(char *name, unsigned flags, unsigned watchdog_timeout_s);
++
++#endif /* __BOOTSTATE_H */
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0002-bootstate-Add-kernel-option-containing-the-system-th.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0002-bootstate-Add-kernel-option-containing-the-system-th.patch
new file mode 100644
index 0000000..719cd50
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0002-bootstate-Add-kernel-option-containing-the-system-th.patch
@@ -0,0 +1,43 @@
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Mon, 20 Jul 2015 20:44:00 +0200
+Subject: [PATCH] bootstate: Add kernel option containing the system that is
+ started
+
+This is useful to allow the userspace to determine which system
+is actually started without dissecting the root= option.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ common/bootstate.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/common/bootstate.c b/common/bootstate.c
+index 3dc18813064d..b0cb0183068a 100644
+--- a/common/bootstate.c
++++ b/common/bootstate.c
+@@ -753,12 +753,16 @@ int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout)
+ }
+
+ while (true) {
+- char *cmd;
++ char *cmd, *system;
+
+ ret = bootstate_get_target(bootstate, flags, &target);
+ if (ret)
+ return ret;
+
++ system = asprintf("bootstate.active=%s", target);
++ globalvar_add_simple("linux.bootargs.bootchooser", system);
++ free(system);
++
+ cmd = asprintf("boot %s", target);
+ free(target);
+ pr_info("%srunning: %s...\n",
+@@ -766,6 +770,7 @@ int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout)
+ if (!(flags & BOOTCHOOSER_FLAG_DRYRUN))
+ ret = run_command(cmd);
+ free(cmd);
++ globalvar_set_match("linux.bootargs.bootchooser", NULL);
+
+ if (flags & BOOTCHOOSER_FLAG_RETRY_WITH_DEC) {
+ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_DEC;
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0003-bootstate-separate-names-from-boot-targets.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0003-bootstate-separate-names-from-boot-targets.patch
new file mode 100644
index 0000000..77f4949
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0003-bootstate-separate-names-from-boot-targets.patch
@@ -0,0 +1,63 @@
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Thu, 23 Jul 2015 16:42:18 +0200
+Subject: [PATCH] bootstate: separate names from boot targets
+
+The name of a boot target and the device or script to boot may be two
+different things. Allow a 'boot' property in the boot targets.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ common/bootstate.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/common/bootstate.c b/common/bootstate.c
+index b0cb0183068a..fde278262fa3 100644
+--- a/common/bootstate.c
++++ b/common/bootstate.c
+@@ -75,6 +75,7 @@ struct bootstate_target {
+ /* spec */
+ const char *name;
+ unsigned int default_attempts;
++ const char *boot;
+ };
+
+ static void pr_target(struct bootstate *bootstate, struct bootstate_target *target)
+@@ -205,7 +206,7 @@ static struct bootstate_target *bootstate_target_find(const struct bootstate *bo
+ return ERR_PTR(-ENOENT);
+ }
+
+-static int bootstate_target_from_node(struct bootstate *bootstate, const struct device_node *node, bool create)
++static int bootstate_target_from_node(struct bootstate *bootstate, struct device_node *node, bool create)
+ {
+ struct bootstate_target *target;
+ char *name, *indexs;
+@@ -217,10 +218,18 @@ static int bootstate_target_from_node(struct bootstate *bootstate, const struct
+ *indexs++ = 0;
+
+ if (create) {
++ const char *boot;
++
+ /* create*/
+ target = xzalloc(sizeof(*target));
+
+ target->name = xstrdup(name);
++
++ if (!of_property_read_string(node, "boot", &boot))
++ target->boot = xstrdup(boot);
++ else
++ target->boot = xstrdup(name);
++
+ list_add_tail(&target->list, &bootstate->targets);
+ list_add_tail(&target->list_unsorted,
+ &bootstate->targets_unsorted);
+@@ -701,8 +710,9 @@ int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **tar
+ }
+
+ found = true;
+- *target_out = strdup(target->name);
+- pr_debug("%s: selected target '%s'\n", __func__, target->name);
++ *target_out = strdup(target->boot);
++ pr_debug("%s: selected target '%s', boot '%s'\n",
++ __func__, target->name, target->boot);
+ if (!v)
+ goto out;
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0004-bootstate-set-kernel-option-to-name-of-boot-target.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0004-bootstate-set-kernel-option-to-name-of-boot-target.patch
new file mode 100644
index 0000000..1db763c
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0004-bootstate-set-kernel-option-to-name-of-boot-target.patch
@@ -0,0 +1,119 @@
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Mon, 27 Jul 2015 13:39:45 +0200
+Subject: [PATCH] bootstate: set kernel option to name of boot target
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ common/bootstate.c | 60 ++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 36 insertions(+), 24 deletions(-)
+
+diff --git a/common/bootstate.c b/common/bootstate.c
+index fde278262fa3..2dcc47cfa257 100644
+--- a/common/bootstate.c
++++ b/common/bootstate.c
+@@ -631,20 +631,8 @@ void _pr_flags(struct bootstate *bootstate, unsigned flags)
+ (verbose) ? _pr_flags(bootstate, flags) : 0; \
+ })
+
+-/*
+- * bootstate_get_target - create a new state instance from a device_node
+- *
+- * @bootstate the bootstate instance to work in
+- * @flags supported flags:
+- * BOOTCHOOSER_FLAG_VERBOSE
+- * BOOTCHOOSER_FLAG_ATTEMPTS_KEEP
+- * BOOTCHOOSER_FLAG_ATTEMPTS_DEC
+- * BOOTCHOOSER_FLAG_ATTEMPTS_RESET
+- * BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS
+- * @target_out a string to the choosen boot target is returned via
+- * this paramater
+- */
+-int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out)
++static struct bootstate_target *bootstate_target_get(struct bootstate *bootstate,
++ unsigned flags)
+ {
+ struct bootstate_target *target;
+ int ret;
+@@ -655,7 +643,7 @@ int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **tar
+
+ ret = bootstate_load(bootstate);
+ if (ret)
+- return ret;
++ return ERR_PTR(ret);
+
+ if (flags & BOOTCHOOSER_FLAG_ATTEMPTS_RESET) {
+ list_for_each_entry(target, &bootstate->targets, list) {
+@@ -710,7 +698,6 @@ int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **tar
+ }
+
+ found = true;
+- *target_out = strdup(target->boot);
+ pr_debug("%s: selected target '%s', boot '%s'\n",
+ __func__, target->name, target->boot);
+ if (!v)
+@@ -723,7 +710,33 @@ int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **tar
+ bootstate_save(bootstate);
+
+ if (!found)
+- return -ENOENT;
++ return ERR_PTR(-ENOENT);
++
++ return target;
++}
++
++/*
++ * bootstate_get_target - create a new state instance from a device_node
++ *
++ * @bootstate the bootstate instance to work in
++ * @flags supported flags:
++ * BOOTCHOOSER_FLAG_VERBOSE
++ * BOOTCHOOSER_FLAG_ATTEMPTS_KEEP
++ * BOOTCHOOSER_FLAG_ATTEMPTS_DEC
++ * BOOTCHOOSER_FLAG_ATTEMPTS_RESET
++ * BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS
++ * @target_out a string to the choosen boot target is returned via
++ * this paramater
++ */
++int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out)
++{
++ struct bootstate_target *target;
++
++ target = bootstate_target_get(bootstate, flags);
++ if (IS_ERR(target))
++ return PTR_ERR(target);
++
++ *target_out = strdup(target->boot);
+
+ return 0;
+ }
+@@ -732,7 +745,7 @@ int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout)
+ {
+ struct bootstate *bootstate;
+ bool v = flags & BOOTCHOOSER_FLAG_VERBOSE;
+- char *target;
++ struct bootstate_target *target;
+ int ret;
+
+ if (!name)
+@@ -765,16 +778,15 @@ int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout)
+ while (true) {
+ char *cmd, *system;
+
+- ret = bootstate_get_target(bootstate, flags, &target);
+- if (ret)
+- return ret;
++ target = bootstate_target_get(bootstate, flags);
++ if (IS_ERR(target))
++ return PTR_ERR(target);
+
+- system = asprintf("bootstate.active=%s", target);
++ system = asprintf("bootstate.active=%s", target->name);
+ globalvar_add_simple("linux.bootargs.bootchooser", system);
+ free(system);
+
+- cmd = asprintf("boot %s", target);
+- free(target);
++ cmd = asprintf("boot %s", target->boot);
+ pr_info("%srunning: %s...\n",
+ flags & BOOTCHOOSER_FLAG_DRYRUN ? "not " : "", cmd);
+ if (!(flags & BOOTCHOOSER_FLAG_DRYRUN))
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0101-beaglebone-add-state-entrie-for-mmc0-and-mmc1.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0101-beaglebone-add-state-entrie-for-mmc0-and-mmc1.patch
new file mode 100644
index 0000000..9761b58
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0101-beaglebone-add-state-entrie-for-mmc0-and-mmc1.patch
@@ -0,0 +1,35 @@
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Date: Fri, 10 Jun 2016 14:02:30 +0200
+Subject: [PATCH] beaglebone: add state entrie for mmc0 and mmc1
+
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+---
+ arch/arm/dts/am335x-bone-common.dtsi | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/arch/arm/dts/am335x-bone-common.dtsi b/arch/arm/dts/am335x-bone-common.dtsi
+index ef97d906616c..d14c6ded6a55 100644
+--- a/arch/arm/dts/am335x-bone-common.dtsi
++++ b/arch/arm/dts/am335x-bone-common.dtsi
+@@ -11,6 +11,21 @@
+ linux,stdout-path = &uart0;
+ };
+
++ bootstate: bootstate {
++ compatible = "barebox,bootstate";
++ backend-type = "nv";
++
++ system0 {
++ default_attempts = <3>;
++ boot = "mmc0";
++ };
++
++ system1 {
++ default_attempts = <3>;
++ boot = "mmc1";
++ };
++ };
++
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&dcdc2_reg>;
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0201-rpi2-add-basic-boot-spec-devicetree-support.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0201-rpi2-add-basic-boot-spec-devicetree-support.patch
new file mode 100644
index 0000000..40d67be
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0201-rpi2-add-basic-boot-spec-devicetree-support.patch
@@ -0,0 +1,462 @@
+From: Alexander Aring <aar@pengutronix.de>
+Date: Thu, 9 Jun 2016 11:26:03 +0200
+Subject: [PATCH] rpi2: add basic boot-spec devicetree support
+
+Signed-off-by: Alexander Aring <aar@pengutronix.de>
+---
+ arch/arm/dts/Makefile | 1 +
+ arch/arm/dts/bcm2835-rpi.dtsi | 60 +++++++++++
+ arch/arm/dts/bcm2836-rpi-2-b.dts | 35 +++++++
+ arch/arm/dts/bcm2836.dtsi | 78 ++++++++++++++
+ arch/arm/dts/bcm283x.dtsi | 212 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-bcm283x/core.c | 4 +-
+ 6 files changed, 389 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/dts/bcm2835-rpi.dtsi
+ create mode 100644 arch/arm/dts/bcm2836-rpi-2-b.dts
+ create mode 100644 arch/arm/dts/bcm2836.dtsi
+ create mode 100644 arch/arm/dts/bcm283x.dtsi
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index b83c1109ef39..960d8aac3933 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -9,6 +9,7 @@ obj- += dummy.o
+
+ pbl-dtb-$(CONFIG_MACH_AFI_GF) += am335x-afi-gf.dtb.o
+ pbl-dtb-$(CONFIG_MACH_BEAGLEBONE) += am335x-bone.dtb.o am335x-boneblack.dtb.o am335x-bone-common.dtb.o
++pbl-dtb-$(CONFIG_MACH_RPI2) += bcm2836-rpi-2-b.dtb.o
+ pbl-dtb-$(CONFIG_MACH_CM_FX6) += imx6dl-cm-fx6.dtb.o imx6q-cm-fx6.dtb.o imx6q-utilite.dtb.o
+ pbl-dtb-$(CONFIG_MACH_DFI_FS700_M60) += imx6q-dfi-fs700-m60-6q.dtb.o imx6dl-dfi-fs700-m60-6s.dtb.o
+ pbl-dtb-$(CONFIG_MACH_DUCKBILL) += imx28-duckbill.dtb.o
+diff --git a/arch/arm/dts/bcm2835-rpi.dtsi b/arch/arm/dts/bcm2835-rpi.dtsi
+new file mode 100644
+index 000000000000..3afb9fefe2d1
+--- /dev/null
++++ b/arch/arm/dts/bcm2835-rpi.dtsi
+@@ -0,0 +1,60 @@
++/ {
++ memory {
++ reg = <0 0x10000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ act {
++ label = "ACT";
++ default-state = "keep";
++ linux,default-trigger = "heartbeat";
++ };
++ };
++
++ soc {
++ firmware: firmware {
++ compatible = "raspberrypi,bcm2835-firmware";
++ mboxes = <&mailbox>;
++ };
++ };
++};
++
++&gpio {
++ pinctrl-names = "default";
++
++ gpioout: gpioout {
++ brcm,pins = <6>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ alt0: alt0 {
++ brcm,pins = <0 1 2 3 4 5 7 8 9 10 11 14 15 40 45>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ alt3: alt3 {
++ brcm,pins = <48 49 50 51 52 53>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++};
++
++&i2c0 {
++ status = "okay";
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ status = "okay";
++ clock-frequency = <100000>;
++};
++
++&i2c2 {
++ status = "okay";
++};
++
++&sdhci {
++ status = "okay";
++ bus-width = <4>;
++};
+diff --git a/arch/arm/dts/bcm2836-rpi-2-b.dts b/arch/arm/dts/bcm2836-rpi-2-b.dts
+new file mode 100644
+index 000000000000..ff946661bd13
+--- /dev/null
++++ b/arch/arm/dts/bcm2836-rpi-2-b.dts
+@@ -0,0 +1,35 @@
++/dts-v1/;
++#include "bcm2836.dtsi"
++#include "bcm2835-rpi.dtsi"
++
++/ {
++ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
++ model = "Raspberry Pi 2 Model B";
++
++ memory {
++ reg = <0 0x40000000>;
++ };
++
++ leds {
++ act {
++ gpios = <&gpio 47 0>;
++ };
++
++ pwr {
++ label = "PWR";
++ gpios = <&gpio 35 0>;
++ default-state = "keep";
++ linux,default-trigger = "default-on";
++ };
++ };
++};
++
++&gpio {
++ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
++
++ /* I2S interface */
++ i2s_alt0: i2s_alt0 {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++};
+diff --git a/arch/arm/dts/bcm2836.dtsi b/arch/arm/dts/bcm2836.dtsi
+new file mode 100644
+index 000000000000..9d0651d8f373
+--- /dev/null
++++ b/arch/arm/dts/bcm2836.dtsi
+@@ -0,0 +1,78 @@
++#include "bcm283x.dtsi"
++
++/ {
++ compatible = "brcm,bcm2836";
++
++ soc {
++ ranges = <0x7e000000 0x3f000000 0x1000000>,
++ <0x40000000 0x40000000 0x00001000>;
++ dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
++
++ local_intc: local_intc {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ interrupt-parent = <&local_intc>;
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a7-pmu";
++ interrupt-parent = <&local_intc>;
++ interrupts = <9>;
++ };
++ };
++
++ timer {
++ compatible = "arm,armv7-timer";
++ interrupt-parent = <&local_intc>;
++ interrupts = <0>, // PHYS_SECURE_PPI
++ <1>, // PHYS_NONSECURE_PPI
++ <3>, // VIRT_PPI
++ <2>; // HYP_PPI
++ always-on;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ v7_cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf00>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf01>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf02>;
++ clock-frequency = <800000000>;
++ };
++
++ v7_cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a7";
++ reg = <0xf03>;
++ clock-frequency = <800000000>;
++ };
++ };
++};
++
++/* Make the BCM2835-style global interrupt controller be a child of the
++ * CPU-local interrupt controller.
++ */
++&intc {
++ compatible = "brcm,bcm2836-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-parent = <&local_intc>;
++ interrupts = <8>;
++};
+diff --git a/arch/arm/dts/bcm283x.dtsi b/arch/arm/dts/bcm283x.dtsi
+new file mode 100644
+index 000000000000..971e741e5467
+--- /dev/null
++++ b/arch/arm/dts/bcm283x.dtsi
+@@ -0,0 +1,212 @@
++#include <dt-bindings/pinctrl/bcm2835.h>
++#include <dt-bindings/clock/bcm2835.h>
++#include "skeleton.dtsi"
++
++/* This include file covers the common peripherals and configuration between
++ * bcm2835 and bcm2836 implementations, leaving the CPU configuration to
++ * bcm2835.dtsi and bcm2836.dtsi.
++ */
++
++/ {
++ compatible = "brcm,bcm2835";
++ model = "BCM2835";
++ interrupt-parent = <&intc>;
++
++ chosen {
++ bootargs = "earlyprintk console=ttyAMA0";
++ };
++
++ soc {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ timer@7e003000 {
++ compatible = "brcm,bcm2835-system-timer";
++ reg = <0x7e003000 0x1000>;
++ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
++ /* This could be a reference to BCM2835_CLOCK_TIMER,
++ * but we don't have the driver using the common clock
++ * support yet.
++ */
++ clock-frequency = <1000000>;
++ };
++
++ dma: dma@7e007000 {
++ compatible = "brcm,bcm2835-dma";
++ reg = <0x7e007000 0xf00>;
++ interrupts = <1 16>,
++ <1 17>,
++ <1 18>,
++ <1 19>,
++ <1 20>,
++ <1 21>,
++ <1 22>,
++ <1 23>,
++ <1 24>,
++ <1 25>,
++ <1 26>,
++ <1 27>,
++ <1 28>;
++
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x7f35>;
++ };
++
++ intc: interrupt-controller@7e00b200 {
++ compatible = "brcm,bcm2835-armctrl-ic";
++ reg = <0x7e00b200 0x200>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ watchdog@7e100000 {
++ compatible = "brcm,bcm2835-pm-wdt";
++ reg = <0x7e100000 0x28>;
++ };
++
++ clocks: cprman@7e101000 {
++ compatible = "brcm,bcm2835-cprman";
++ #clock-cells = <1>;
++ reg = <0x7e101000 0x2000>;
++
++ /* CPRMAN derives everything from the platform's
++ * oscillator.
++ */
++ clocks = <&clk_osc>;
++ };
++
++ rng@7e104000 {
++ compatible = "brcm,bcm2835-rng";
++ reg = <0x7e104000 0x10>;
++ };
++
++ mailbox: mailbox@7e00b800 {
++ compatible = "brcm,bcm2835-mbox";
++ reg = <0x7e00b880 0x40>;
++ interrupts = <0 1>;
++ #mbox-cells = <0>;
++ };
++
++ gpio: gpio@7e200000 {
++ compatible = "brcm,bcm2835-gpio";
++ reg = <0x7e200000 0xb4>;
++ /*
++ * The GPIO IP block is designed for 3 banks of GPIOs.
++ * Each bank has a GPIO interrupt for itself.
++ * There is an overall "any bank" interrupt.
++ * In order, these are GIC interrupts 17, 18, 19, 20.
++ * Since the BCM2835 only has 2 banks, the 2nd bank
++ * interrupt output appears to be mirrored onto the
++ * 3rd bank's interrupt signal.
++ * So, a bank0 interrupt shows up on 17, 20, and
++ * a bank1 interrupt shows up on 18, 19, 20!
++ */
++ interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
++
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ uart0: uart@7e201000 {
++ compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ reg = <0x7e201000 0x1000>;
++ interrupts = <2 25>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ };
++
++ i2s: i2s@7e203000 {
++ compatible = "brcm,bcm2835-i2s";
++ reg = <0x7e203000 0x20>,
++ <0x7e101098 0x02>;
++
++ dmas = <&dma 2>,
++ <&dma 3>;
++ dma-names = "tx", "rx";
++ status = "disabled";
++ };
++
++ spi: spi@7e204000 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204000 0x1000>;
++ interrupts = <2 22>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c0: i2c@7e205000 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e205000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ aux: aux@0x7e215000 {
++ compatible = "brcm,bcm2835-aux";
++ #clock-cells = <1>;
++ reg = <0x7e215000 0x8>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ };
++
++ sdhci: sdhci@7e300000 {
++ compatible = "brcm,bcm2835-sdhci";
++ reg = <0x7e300000 0x100>;
++ interrupts = <2 30>;
++ clocks = <&clocks BCM2835_CLOCK_EMMC>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@7e804000 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e804000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c2: i2c@7e805000 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e805000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ usb@7e980000 {
++ compatible = "brcm,bcm2835-usb";
++ reg = <0x7e980000 0x10000>;
++ interrupts = <1 9>;
++ };
++ };
++
++ clocks {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ /* The oscillator is the root of the clock tree. */
++ clk_osc: clock@3 {
++ compatible = "fixed-clock";
++ reg = <3>;
++ #clock-cells = <0>;
++ clock-output-names = "osc";
++ clock-frequency = <19200000>;
++ };
++
++ };
++};
+diff --git a/arch/arm/mach-bcm283x/core.c b/arch/arm/mach-bcm283x/core.c
+index 64f37813883a..f11221dd6685 100644
+--- a/arch/arm/mach-bcm283x/core.c
++++ b/arch/arm/mach-bcm283x/core.c
+@@ -42,15 +42,17 @@ static int bcm2835_clk_init(void)
+
+ clk = clk_fixed("uart0-pl0110", 3 * 1000 * 1000);
+ clk_register_clkdev(clk, NULL, "uart0-pl0110");
++ clk_register_clkdev(clk, NULL, "3f201000.uart");
+
+ clk = clk_fixed("bcm2835-cs", 1 * 1000 * 1000);
+ clk_register_clkdev(clk, NULL, "bcm2835-cs");
++ clk_register_clkdev(clk, NULL, "3f003000.timer");
+
+ add_generic_device("bcm2835-cs", DEVICE_ID_SINGLE, NULL, BCM2835_ST_BASE, 0x1C, IORESOURCE_MEM, NULL);
+
+ return 0;
+ }
+-postcore_initcall(bcm2835_clk_init);
++pure_initcall(bcm2835_clk_init);
+
+ void bcm2835_register_uart(void)
+ {
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0301-Release-2016.05.0-customers-pengutronix-multi_v7-201.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0301-Release-2016.05.0-customers-pengutronix-multi_v7-201.patch
new file mode 100644
index 0000000..76e12c8
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/0301-Release-2016.05.0-customers-pengutronix-multi_v7-201.patch
@@ -0,0 +1,22 @@
+From: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Date: Fri, 10 Jun 2016 14:10:58 +0200
+Subject: [PATCH] Release 2016.05.0/customers/pengutronix/multi_v7/20160610-1
+
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index 93f1d17d99d2..b844aa674da5 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2016
+ PATCHLEVEL = 05
+ SUBLEVEL = 0
+-EXTRAVERSION =
++EXTRAVERSION =-20160610-1
+ NAME = None
+
+ # *DOCUMENTATION*
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/series b/configs/platform-v7a/patches/barebox-2016.05.0/series
new file mode 100644
index 0000000..a93c9d2
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2016.05.0/series
@@ -0,0 +1,22 @@
+# umpf-base: v2016.05.0
+# umpf-name: 2016.05.0/customers/pengutronix/multi_v7
+# umpf-version: 2016.05.0/customers/pengutronix/multi_v7/20160610-1
+# umpf-topic: v2016.05.0/topic/bootstate
+# umpf-hashinfo: bfaa55682a5f53a0f679ab08e6b55350594ed047
+# umpf-topic-range: f5142b8564005d95324e4c326dbc390ce85e8bef..bfaa55682a5f53a0f679ab08e6b55350594ed047
+0001-bootstate-add-framework-for-redundant-boot-scenarios.patch
+0002-bootstate-Add-kernel-option-containing-the-system-th.patch
+0003-bootstate-separate-names-from-boot-targets.patch
+0004-bootstate-set-kernel-option-to-name-of-boot-target.patch
+# umpf-topic: v2016.05.0/customers/pengutronix/beaglebone
+# umpf-hashinfo: 9cbaeb8cfaa8b5e7837725df242aacccbbc5fa53
+# umpf-topic-range: bfaa55682a5f53a0f679ab08e6b55350594ed047..c95ad802cdf09922b56027338b85cd58de732c2a
+0101-beaglebone-add-state-entrie-for-mmc0-and-mmc1.patch
+# umpf-topic: v2016.05.0/customers/pengutronix/rpi2
+# umpf-hashinfo: 2df94ba7d6c5680032d7da8c1554cf01c7ca845b
+# umpf-topic-range: c95ad802cdf09922b56027338b85cd58de732c2a..64afca484be01d3a0329b289fe4667608495e14b
+0201-rpi2-add-basic-boot-spec-devicetree-support.patch
+# umpf-release: 2016.05.0/customers/pengutronix/multi_v7/20160610-1
+# umpf-topic-range: 64afca484be01d3a0329b289fe4667608495e14b..92019e24a71b3a5484927b84863d0f2bf34aae51
+0301-Release-2016.05.0-customers-pengutronix-multi_v7-201.patch
+# umpf-end