mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-09-20 22:52:00 +00:00
fdtdec tests and improvements for carve-outs
pinctrl race-condition fix various other fixes in sandbox, sound, mkimage, etc. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAlyxBfcACgkQfxc6PpAI reYtsgf8DSi0h6bNmoPGA8q/aRTQii2x6TheT+AonvND4Kt5ycyw5Otjn3n7O13G ubDvBn3Ix5znRaj6nSip7zO1M59dNB19Qk5i+ad21w3rx2V8HTWcLYMwUmC2DPZU qMaOpIeEWYKuCDFRhpw/b6yF1rtq4lMxWTrSlB+ewntmrKV+Ymk0UWYSCfNMmZ8F cLSd/wFWoTxysZLT4t/5jbNIPU8XaO0hYH0C9Y/tsK80bCpdjkTMNQuO7/qlgUb9 E7BCf1HXuMqWTZuqub9hu1y24PYufNSHziK1R+lNqm+yW3MxJGihP5OsCfVoHDgu FU+QIKeBo64R3eH1VSrAh8pLp143bg== =4/BU -----END PGP SIGNATURE----- Merge tag 'pull-12apr19' of git://git.denx.de/u-boot-dm fdtdec tests and improvements for carve-outs pinctrl race-condition fix various other fixes in sandbox, sound, mkimage, etc.
This commit is contained in:
commit
cf5eebeb18
32 changed files with 1305 additions and 420 deletions
|
@ -0,0 +1,136 @@
|
||||||
|
*** Reserved memory regions ***
|
||||||
|
|
||||||
|
Reserved memory is specified as a node under the /reserved-memory node.
|
||||||
|
The operating system shall exclude reserved memory from normal usage
|
||||||
|
one can create child nodes describing particular reserved (excluded from
|
||||||
|
normal use) memory regions. Such memory regions are usually designed for
|
||||||
|
the special usage by various device drivers.
|
||||||
|
|
||||||
|
Parameters for each memory region can be encoded into the device tree
|
||||||
|
with the following nodes:
|
||||||
|
|
||||||
|
/reserved-memory node
|
||||||
|
---------------------
|
||||||
|
#address-cells, #size-cells (required) - standard definition
|
||||||
|
- Should use the same values as the root node
|
||||||
|
ranges (required) - standard definition
|
||||||
|
- Should be empty
|
||||||
|
|
||||||
|
/reserved-memory/ child nodes
|
||||||
|
-----------------------------
|
||||||
|
Each child of the reserved-memory node specifies one or more regions of
|
||||||
|
reserved memory. Each child node may either use a 'reg' property to
|
||||||
|
specify a specific range of reserved memory, or a 'size' property with
|
||||||
|
optional constraints to request a dynamically allocated block of memory.
|
||||||
|
|
||||||
|
Following the generic-names recommended practice, node names should
|
||||||
|
reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
|
||||||
|
address (@<address>) should be appended to the name if the node is a
|
||||||
|
static allocation.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
Requires either a) or b) below.
|
||||||
|
a) static allocation
|
||||||
|
reg (required) - standard definition
|
||||||
|
b) dynamic allocation
|
||||||
|
size (required) - length based on parent's #size-cells
|
||||||
|
- Size in bytes of memory to reserve.
|
||||||
|
alignment (optional) - length based on parent's #size-cells
|
||||||
|
- Address boundary for alignment of allocation.
|
||||||
|
alloc-ranges (optional) - prop-encoded-array (address, length pairs).
|
||||||
|
- Specifies regions of memory that are
|
||||||
|
acceptable to allocate from.
|
||||||
|
|
||||||
|
If both reg and size are present, then the reg property takes precedence
|
||||||
|
and size is ignored.
|
||||||
|
|
||||||
|
Additional properties:
|
||||||
|
compatible (optional) - standard definition
|
||||||
|
- may contain the following strings:
|
||||||
|
- shared-dma-pool: This indicates a region of memory meant to be
|
||||||
|
used as a shared pool of DMA buffers for a set of devices. It can
|
||||||
|
be used by an operating system to instantiate the necessary pool
|
||||||
|
management subsystem if necessary.
|
||||||
|
- vendor specific string in the form <vendor>,[<device>-]<usage>
|
||||||
|
no-map (optional) - empty property
|
||||||
|
- Indicates the operating system must not create a virtual mapping
|
||||||
|
of the region as part of its standard mapping of system memory,
|
||||||
|
nor permit speculative access to it under any circumstances other
|
||||||
|
than under the control of the device driver using the region.
|
||||||
|
reusable (optional) - empty property
|
||||||
|
- The operating system can use the memory in this region with the
|
||||||
|
limitation that the device driver(s) owning the region need to be
|
||||||
|
able to reclaim it back. Typically that means that the operating
|
||||||
|
system can use that region to store volatile or cached data that
|
||||||
|
can be otherwise regenerated or migrated elsewhere.
|
||||||
|
|
||||||
|
Linux implementation note:
|
||||||
|
- If a "linux,cma-default" property is present, then Linux will use the
|
||||||
|
region for the default pool of the contiguous memory allocator.
|
||||||
|
|
||||||
|
- If a "linux,dma-default" property is present, then Linux will use the
|
||||||
|
region for the default pool of the consistent DMA allocator.
|
||||||
|
|
||||||
|
Device node references to reserved memory
|
||||||
|
-----------------------------------------
|
||||||
|
Regions in the /reserved-memory node may be referenced by other device
|
||||||
|
nodes by adding a memory-region property to the device node.
|
||||||
|
|
||||||
|
memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
This example defines 3 contiguous regions are defined for Linux kernel:
|
||||||
|
one default of all device drivers (named linux,cma@72000000 and 64MiB in size),
|
||||||
|
one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and
|
||||||
|
one for multimedia processing (named multimedia-memory@77000000, 64MiB).
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
memory {
|
||||||
|
reg = <0x40000000 0x40000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
reserved-memory {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
/* global autoconfigured region for contiguous allocations */
|
||||||
|
linux,cma {
|
||||||
|
compatible = "shared-dma-pool";
|
||||||
|
reusable;
|
||||||
|
size = <0x4000000>;
|
||||||
|
alignment = <0x2000>;
|
||||||
|
linux,cma-default;
|
||||||
|
};
|
||||||
|
|
||||||
|
display_reserved: framebuffer@78000000 {
|
||||||
|
reg = <0x78000000 0x800000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
multimedia_reserved: multimedia@77000000 {
|
||||||
|
compatible = "acme,multimedia-memory";
|
||||||
|
reg = <0x77000000 0x4000000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
fb0: video@12300000 {
|
||||||
|
memory-region = <&display_reserved>;
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
scaler: scaler@12500000 {
|
||||||
|
memory-region = <&multimedia_reserved>;
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
codec: codec@12600000 {
|
||||||
|
memory-region = <&multimedia_reserved>;
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
};
|
|
@ -493,6 +493,7 @@
|
||||||
compatible = "denx,u-boot-probe-test";
|
compatible = "denx,u-boot-probe-test";
|
||||||
first-syscon = <&syscon0>;
|
first-syscon = <&syscon0>;
|
||||||
second-sys-ctrl = <&another_system_controller>;
|
second-sys-ctrl = <&another_system_controller>;
|
||||||
|
third-syscon = <&syscon2>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -597,7 +598,7 @@
|
||||||
0x38 8>;
|
0x38 8>;
|
||||||
};
|
};
|
||||||
|
|
||||||
syscon@2 {
|
syscon2: syscon@2 {
|
||||||
compatible = "simple-mfd", "syscon";
|
compatible = "simple-mfd", "syscon";
|
||||||
reg = <0x40 5
|
reg = <0x40 5
|
||||||
0x48 6
|
0x48 6
|
||||||
|
|
|
@ -104,7 +104,7 @@ static inline int sandbox_sdl_sound_start(uint frequency)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sandbox_sdl_sound_play(const void *data, uint count)
|
static inline int sandbox_sdl_sound_play(const void *data, uint count)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ static inline int sandbox_sdl_sound_stop(void)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sandbox_sdl_sound_init(int rate, int channels)
|
static inline int sandbox_sdl_sound_init(int rate, int channels)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,21 @@ typedef unsigned short umode_t;
|
||||||
/*
|
/*
|
||||||
* Number of bits in a C 'long' on this architecture.
|
* Number of bits in a C 'long' on this architecture.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PHYS64
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
#define BITS_PER_LONG 64
|
#define BITS_PER_LONG 64
|
||||||
#else /* CONFIG_PHYS64 */
|
#else /* CONFIG_PHYS_64BIT */
|
||||||
#define BITS_PER_LONG 32
|
#define BITS_PER_LONG 32
|
||||||
#endif /* CONFIG_PHYS64 */
|
#endif /* CONFIG_PHYS_64BIT */
|
||||||
|
|
||||||
#ifdef CONFIG_PHYS64
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
typedef unsigned long long dma_addr_t;
|
typedef unsigned long long dma_addr_t;
|
||||||
typedef u64 phys_addr_t;
|
typedef u64 phys_addr_t;
|
||||||
typedef u64 phys_size_t;
|
typedef u64 phys_size_t;
|
||||||
#else /* CONFIG_PHYS64 */
|
#else /* CONFIG_PHYS_64BIT */
|
||||||
typedef unsigned long dma_addr_t;
|
typedef unsigned long dma_addr_t;
|
||||||
typedef u32 phys_addr_t;
|
typedef u32 phys_addr_t;
|
||||||
typedef u32 phys_size_t;
|
typedef u32 phys_size_t;
|
||||||
#endif /* CONFIG_PHYS64 */
|
#endif /* CONFIG_PHYS_64BIT */
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ int pci_map_physmem(phys_addr_t paddr, unsigned long *lenp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("%s: failed: addr=%x\n", __func__, paddr);
|
debug("%s: failed: addr=%pap\n", __func__, &paddr);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -456,12 +456,6 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
|
||||||
if (!banks)
|
if (!banks)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < banks; i++)
|
|
||||||
if (start[i] == 0 && size[i] == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
banks = i;
|
|
||||||
|
|
||||||
len = fdt_pack_reg(blob, tmp, start, size, banks);
|
len = fdt_pack_reg(blob, tmp, start, size, banks);
|
||||||
|
|
||||||
err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
|
err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
|
||||||
|
|
|
@ -194,6 +194,7 @@ CONFIG_CMD_DHRYSTONE=y
|
||||||
CONFIG_TPM=y
|
CONFIG_TPM=y
|
||||||
CONFIG_LZ4=y
|
CONFIG_LZ4=y
|
||||||
CONFIG_ERRNO_STR=y
|
CONFIG_ERRNO_STR=y
|
||||||
|
CONFIG_TEST_FDTDEC=y
|
||||||
CONFIG_UNIT_TEST=y
|
CONFIG_UNIT_TEST=y
|
||||||
CONFIG_UT_TIME=y
|
CONFIG_UT_TIME=y
|
||||||
CONFIG_UT_DM=y
|
CONFIG_UT_DM=y
|
||||||
|
|
|
@ -215,6 +215,7 @@ CONFIG_CMD_DHRYSTONE=y
|
||||||
CONFIG_TPM=y
|
CONFIG_TPM=y
|
||||||
CONFIG_LZ4=y
|
CONFIG_LZ4=y
|
||||||
CONFIG_ERRNO_STR=y
|
CONFIG_ERRNO_STR=y
|
||||||
|
CONFIG_TEST_FDTDEC=y
|
||||||
CONFIG_UNIT_TEST=y
|
CONFIG_UNIT_TEST=y
|
||||||
CONFIG_UT_TIME=y
|
CONFIG_UT_TIME=y
|
||||||
CONFIG_UT_DM=y
|
CONFIG_UT_DM=y
|
||||||
|
|
|
@ -1,239 +1,177 @@
|
||||||
Running U-Boot from coreboot on Chromebooks
|
Chromium OS Support in U-Boot
|
||||||
===========================================
|
=============================
|
||||||
|
|
||||||
U-Boot can be used as a secondary boot loader in a few situations such as from
|
Introduction
|
||||||
UEFI and coreboot (see README.x86). Recent Chromebooks use coreboot even on
|
------------
|
||||||
ARM platforms to start up the machine.
|
|
||||||
|
|
||||||
This document aims to provide a guide to booting U-Boot on a Chromebook. It
|
This describes how to use U-Boot with Chromium OS. Several options are
|
||||||
is only a starting point, and there are many guides on the interwebs. But
|
available:
|
||||||
placing this information in the U-Boot tree should make it easier to find for
|
|
||||||
those who use U-Boot habitually.
|
|
||||||
|
|
||||||
Most of these platforms are supported by U-Boot natively, but it is risky to
|
- Running U-Boot from the 'altfw' feature, which is available on selected
|
||||||
replace the ROM unless you have a servo board and cable to restore it with.
|
Chromebooks from 2019 onwards (initially Grunt). Press '1' from the
|
||||||
|
developer-mode screen to get into U-Boot. See here for details:
|
||||||
|
https://sites.google.com/a/chromium.org/dev/chromium-os/poking-around-your-chrome-os-device?pli=1
|
||||||
|
|
||||||
|
- Running U-Boot from the disk partition. This involves signing U-Boot and
|
||||||
|
placing it on the disk, for booting as a 'kernel'. See
|
||||||
|
README.chromium-chainload for information on this. This is the only
|
||||||
|
option on non-U-Boot Chromebooks from 2013 to 2018 and is somewhat
|
||||||
|
more involved.
|
||||||
|
|
||||||
|
- Running U-Boot with Chromium OS verified boot. This allows U-Boot to be
|
||||||
|
used instead of either or both of depthcharge (a bootloader which forked
|
||||||
|
from U-Boot in 2013) and coreboot. See below for more information on
|
||||||
|
this.
|
||||||
|
|
||||||
|
|
||||||
For all of these the standard U-Boot build instructions apply. For example on
|
U-Boot with Chromium OS verified boot
|
||||||
ARM:
|
-------------------------------------
|
||||||
|
|
||||||
sudo apt install gcc-arm-linux-gnueabi
|
To obtain:
|
||||||
mkdir b
|
|
||||||
make O=b/nyan_big CROSS_COMPILE=arm-linux-gnueabi- nyan-big_defconfig all
|
|
||||||
|
|
||||||
You can obtain the vbutil_kernel utility here:
|
git clone https://github.com/sglass68/u-boot.git
|
||||||
|
cd u-boot
|
||||||
|
git checkout cros-master
|
||||||
|
|
||||||
https://drive.google.com/open?id=0B7WYZbZ9zd-3dHlVVXo4VXE2T0U
|
To build for sandbox:
|
||||||
|
|
||||||
|
UB=/tmp/b/chromeos_sandbox # U-Boot build directory
|
||||||
|
CROS=/home/sglass/cosarm # Chromium OS directory
|
||||||
|
make O=$UB/chromeos_sandbox_defconfig
|
||||||
|
make O=$UB -j20 -s VBOOT_SOURCE=$CROS/src/platform/vboot_reference \
|
||||||
|
MAKEFLAGS_VBOOT=DEBUG=1 QUIET=1
|
||||||
|
|
||||||
|
Replace sandbox with another supported target.
|
||||||
|
|
||||||
|
This produces $UB/image.bin which contains the firmware binaries in a SPI
|
||||||
|
flash image.
|
||||||
|
|
||||||
|
To run on sandbox:
|
||||||
|
|
||||||
|
$UB/tpl/u-boot-tpl -d $UB/u-boot.dtb.out \
|
||||||
|
-L6 -c "host bind 0 $CROS/src/build/images/cheza/latest/chromiumos_image.bin; vboot go auto" \
|
||||||
|
-l -w -s state.dtb -r
|
||||||
|
|
||||||
|
To run on other boards:
|
||||||
|
Install image.bin in the SPI flash of your device
|
||||||
|
Boot your system
|
||||||
|
|
||||||
|
|
||||||
Snow (Samsung ARM Chromebook)
|
Sandbox
|
||||||
-----------------------------
|
-------
|
||||||
|
|
||||||
See here:
|
Most Chromium OS development with U-Boot is undertaken using sandbox. There is
|
||||||
|
a sandbox target available (chromeos_sandbox) which allows running U-Boot on
|
||||||
|
a Linux machine completion with emulations of the display, TPM, disk, etc.
|
||||||
|
|
||||||
https://www.chromium.org/chromium-os/firmware-porting-guide/using-nv-u-boot-on-the-samsung-arm-chromebook
|
Running sandbox starts TPL, which contains the first phase of vboot, providing
|
||||||
|
a device tree and binding a Chromium OS disk image for use to find kernels
|
||||||
|
(any Chromium OS image will do). It also saves driver state between U-Boot
|
||||||
|
phases into state.dtb and will automatically ensure that memory is shared
|
||||||
|
between all phases. TPL will jump to SPL and then on to U-Boot proper.
|
||||||
|
|
||||||
|
It is possible to run with debugging on, e.g.
|
||||||
|
|
||||||
|
gdb --args $UB/tpl/u-boot-tpl -d ....
|
||||||
|
|
||||||
|
Breakpoints can be set in any U-Boot phase. Overall this is a good debugging
|
||||||
|
environment for new verified-boot features.
|
||||||
|
|
||||||
|
|
||||||
Nyan-big
|
Samus
|
||||||
|
-----
|
||||||
|
|
||||||
|
Basic support is available for samus, using the chromeos_samus target. If you
|
||||||
|
have an em100, use:
|
||||||
|
|
||||||
|
sudo em100 -s -c W25Q128FW -d $UB/image.bin -t -r
|
||||||
|
|
||||||
|
to write the image and then boot samus (Power-Refresh).
|
||||||
|
|
||||||
|
|
||||||
|
Boot flow
|
||||||
|
---------
|
||||||
|
|
||||||
|
Verified boot starts in TPL, which selects the A or B SPL, which in turn selects
|
||||||
|
the A or B U-Boot. Then this jumps to the selected kernel. If anything goes
|
||||||
|
wrong, the device reboots and the recovery SPL and U-Boot are used instead.
|
||||||
|
|
||||||
|
More details are available here:
|
||||||
|
|
||||||
|
https://www.chromium.org/chromium-os/chromiumos-design-docs/firmware-boot-and-recovery
|
||||||
|
|
||||||
|
|
||||||
|
New uclasses
|
||||||
|
------------
|
||||||
|
|
||||||
|
Several uclasses are provided in cros/:
|
||||||
|
|
||||||
|
UCLASS_CROS_AUX_FW Chrome OS auxiliary firmware
|
||||||
|
UCLASS_CROS_FWSTORE Chrome OS firmware storage
|
||||||
|
UCLASS_CROS_NVDATA Chrome OS non-volatile data device
|
||||||
|
UCLASS_CROS_VBOOT_EC Chrome OS vboot EC operations
|
||||||
|
UCLASS_CROS_VBOOT_FLAG Chrome OS verified boot flag
|
||||||
|
|
||||||
|
The existing UCLASS_CROS_EC is also used.
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Compiled based on information here:
|
A new 'vboot' command is provided to run particular vboot stages. The most
|
||||||
https://lists.denx.de/pipermail/u-boot/2015-March/209530.html
|
useful command is 'vboot go auto', which continues where the last stage left
|
||||||
https://git.collabora.com/cgit/user/tomeu/u-boot.git/commit/?h=nyan-big
|
off.
|
||||||
https://lists.denx.de/pipermail/u-boot/2017-May/289491.html
|
|
||||||
https://github.com/chromeos-nvidia-androidtv/gnu-linux-on-acer-chromebook-13#copy-data-to-the-sd-card
|
|
||||||
|
|
||||||
1. Build U-Boot
|
Note that TPL and SPL do not supports commands as yet, so the vboot code is
|
||||||
|
called directly from the SPL boot devices (BOOT_DEVICE_CROS_VBOOT). See
|
||||||
|
cros_load_image_tpl() and cros_load_image_spl() which both call
|
||||||
|
vboot_run_auto().
|
||||||
|
|
||||||
mkdir b
|
|
||||||
make -j8 O=b/nyan-big CROSS_COMPILE=arm-linux-gnueabi- nyan-big_defconfig all
|
|
||||||
|
|
||||||
|
Config options
|
||||||
|
--------------
|
||||||
|
|
||||||
2. Select a .its file
|
The main option is CONFIG_CHROMEOS, which enables a wide array of other options
|
||||||
|
so that the required features are present.
|
||||||
|
|
||||||
Select something from doc/chromium which matches your board, or create your
|
|
||||||
own.
|
|
||||||
|
|
||||||
Note that the device tree node is required, even though it is not actually
|
Device-tree config
|
||||||
used by U-Boot. This is because the Chromebook expects to pass it to the
|
------------------
|
||||||
kernel, and crashes if it is not present.
|
|
||||||
|
|
||||||
|
Various options are available which control the operation of verified boot.
|
||||||
|
See cros/dts/bindings/config.txt for details. Most config is handled at run-
|
||||||
|
time, although build-time config (with Kconfig) could also be added fairly
|
||||||
|
easily.
|
||||||
|
|
||||||
3. Build and sign an image
|
|
||||||
|
|
||||||
./b/nyan-big/tools/mkimage -f doc/chromium/nyan-big.its u-boot-chromium.fit
|
Porting to other hardware
|
||||||
echo test >dummy.txt
|
-------------------------
|
||||||
vbutil_kernel --arch arm --keyblock doc/chromium/devkeys/kernel.keyblock \
|
|
||||||
--signprivate doc/chromium/devkeys/kernel_data_key.vbprivk \
|
|
||||||
--version 1 --config dummy.txt --vmlinuz u-boot-chromium.fit \
|
|
||||||
--bootloader dummy.txt --pack u-boot.kpart
|
|
||||||
|
|
||||||
|
A basic port to samus (Chromebook Pixel 2015) is in a basic working state,
|
||||||
|
using the chromeos_samus target. Patches will likely be forthcoming in early
|
||||||
|
2019. Ports to an ARM board and coreboot (for x86 Chromebooks) are in the
|
||||||
|
dreaming state.
|
||||||
|
|
||||||
4. Prepare an SD card
|
|
||||||
|
|
||||||
DISK=/dev/sdc # Replace with your actual SD card device
|
Tests
|
||||||
sudo cgpt create $DISK
|
-----
|
||||||
sudo cgpt add -b 34 -s 32768 -P 1 -S 1 -t kernel $DISK
|
|
||||||
sudo cgpt add -b 32802 -s 2000000 -t rootfs $DISK
|
|
||||||
sudo gdisk $DISK # Enter command 'w' to write a protective MBR to the disk
|
|
||||||
|
|
||||||
|
Chromium OS firmware has a very limited set of tests. The tests that originally
|
||||||
|
existed in U-Boot were not brought over to coreboot or depthcharge.
|
||||||
|
|
||||||
5. Write U-Boot to the SD card
|
The U-Boot tests ('make check') do operate, but at present there are no
|
||||||
|
Chromium OS tests available. These will hopefully come together over time. Of
|
||||||
|
course the above sandbox feature provides a sort of functional test and can
|
||||||
|
detecte problems that affect the flow or particular vboot features.
|
||||||
|
|
||||||
sudo dd if=u-boot.kpart of=/dev/sdc1; sync
|
|
||||||
|
|
||||||
|
TO DO
|
||||||
|
-----
|
||||||
|
|
||||||
6. Start it up
|
- Support for booting from coreboot (patches expected March 2019)
|
||||||
|
- Support for booting from an ARM board, e.g. bob
|
||||||
|
|
||||||
Reboot the device in dev mode. Make sure that you have USB booting enabled. To
|
|
||||||
do this, login as root (via Ctrl-Alt-forward_arrow) and type
|
|
||||||
'enable_dev_usb_boot'. You only need to do this once.
|
|
||||||
|
|
||||||
Reboot the device with the SD card inserted. Press Clrl-U at the developer
|
Simon Glass
|
||||||
mode screen. It should show something like the following on the display:
|
sjg@chromium.org
|
||||||
|
7 October 2018
|
||||||
U-Boot 2017.07-00637-g242eb42-dirty (May 22 2017 - 06:14:21 -0600)
|
|
||||||
|
|
||||||
Model: Acer Chromebook 13 CB5-311
|
|
||||||
Board: Google/NVIDIA Nyan-big, ID: 1
|
|
||||||
|
|
||||||
Net: No ethernet found.
|
|
||||||
Hit any key to stop autoboot: 0
|
|
||||||
Tegra124 (Nyan-big) #
|
|
||||||
|
|
||||||
|
|
||||||
7. Known problems
|
|
||||||
|
|
||||||
On the serial console the word MMC is chopped at the start of the line:
|
|
||||||
|
|
||||||
C: sdhci@700b0000: 2, sdhci@700b0400: 1, sdhci@700b0600: 0
|
|
||||||
|
|
||||||
This is likely due to some problem with change-over of the serial driver
|
|
||||||
during relocation (or perhaps updating the clock setup in board_init()).
|
|
||||||
|
|
||||||
|
|
||||||
9. Notes
|
|
||||||
|
|
||||||
To check that you copied the u-boot.its file correctly, use these commands.
|
|
||||||
You should see that the data at 0x100 in u-boot-chromium.fit is the first few
|
|
||||||
bytes of U-Boot:
|
|
||||||
|
|
||||||
hd u-boot-chromium.fit |head -20
|
|
||||||
...
|
|
||||||
00000100 b8 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 |................|
|
|
||||||
|
|
||||||
hd b/nyan-big/u-boot.bin |head
|
|
||||||
00000000 b8 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 |................|
|
|
||||||
|
|
||||||
|
|
||||||
The 'data' property of the FIT is set up to start at offset 0x100 bytes into
|
|
||||||
the file. The change to CONFIG_SYS_TEXT_BASE is also an offset of 0x100 bytes
|
|
||||||
from the load address. If this changes, you either need to modify U-Boot to be
|
|
||||||
fully relocatable, or expect it to hang.
|
|
||||||
|
|
||||||
|
|
||||||
chromebook_jerry
|
|
||||||
----------------
|
|
||||||
|
|
||||||
The instruction are similar to those for Nyan with changes as noted below:
|
|
||||||
|
|
||||||
1. Patch U-Boot
|
|
||||||
|
|
||||||
Open include/configs/rk3288_common.h
|
|
||||||
|
|
||||||
Change:
|
|
||||||
|
|
||||||
#define CONFIG_SYS_TEXT_BASE 0x00100000
|
|
||||||
|
|
||||||
to:
|
|
||||||
|
|
||||||
#define CONFIG_SYS_TEXT_BASE 0x02000100
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2. Build U-Boot
|
|
||||||
|
|
||||||
mkdir b
|
|
||||||
make -j8 O=b/chromebook_jerry CROSS_COMPILE=arm-linux-gnueabi- \
|
|
||||||
chromebook_jerry_defconfig all
|
|
||||||
|
|
||||||
|
|
||||||
3. See above
|
|
||||||
|
|
||||||
4. Build and sign an image
|
|
||||||
|
|
||||||
./b/chromebook_jerry/tools/mkimage -f doc/chromium/chromebook_jerry.its \
|
|
||||||
u-boot-chromium.fit
|
|
||||||
echo test >dummy.txt
|
|
||||||
vbutil_kernel --arch arm --keyblock doc/chromium/devkeys/kernel.keyblock \
|
|
||||||
--signprivate doc/chromium/devkeys/kernel_data_key.vbprivk \
|
|
||||||
--version 1 --config dummy.txt --vmlinuz u-boot-chromium.fit \
|
|
||||||
--bootloader dummy.txt --pack u-boot.kpart
|
|
||||||
|
|
||||||
|
|
||||||
5. See above
|
|
||||||
|
|
||||||
6. See above
|
|
||||||
|
|
||||||
7. Start it up
|
|
||||||
|
|
||||||
Reboot the device in dev mode. Make sure that you have USB booting enabled. To
|
|
||||||
do this, login as root (via Ctrl-Alt-forward_arrow) and type
|
|
||||||
'enable_dev_usb_boot'. You only need to do this once.
|
|
||||||
|
|
||||||
Reboot the device with the SD card inserted. Press Clrl-U at the developer
|
|
||||||
mode screen. It should show something like the following on the display:
|
|
||||||
|
|
||||||
U-Boot 2017.05-00649-g72acdbf-dirty (May 29 2017 - 14:57:05 -0600)
|
|
||||||
|
|
||||||
Model: Google Jerry
|
|
||||||
Net: Net Initialization Skipped
|
|
||||||
No ethernet found.
|
|
||||||
Hit any key to stop autoboot: 0
|
|
||||||
|
|
||||||
|
|
||||||
8. Known problems
|
|
||||||
|
|
||||||
None as yet.
|
|
||||||
|
|
||||||
|
|
||||||
9. Notes
|
|
||||||
|
|
||||||
None as yet.
|
|
||||||
|
|
||||||
|
|
||||||
Other notes
|
|
||||||
===========
|
|
||||||
|
|
||||||
flashrom
|
|
||||||
--------
|
|
||||||
|
|
||||||
Used to make a backup of your firmware, or to replace it.
|
|
||||||
|
|
||||||
See: https://www.chromium.org/chromium-os/packages/cros-flashrom
|
|
||||||
|
|
||||||
|
|
||||||
coreboot
|
|
||||||
--------
|
|
||||||
|
|
||||||
Coreboot itself is not designed to actually boot an OS. Instead, a program
|
|
||||||
called Depthcharge is used. This originally came out of U-Boot and was then
|
|
||||||
heavily hacked and modified such that is is almost unrecognisable. It does
|
|
||||||
include a very small part of the U-Boot command-line interface but is not
|
|
||||||
usable as a general-purpose boot loader.
|
|
||||||
|
|
||||||
In addition, it has a very unusual design in that it does not do device init
|
|
||||||
itself, but instead relies on coreboot. This is similar to (in U-Boot) having
|
|
||||||
a SPI driver with an empty probe() method, relying on whatever was set up
|
|
||||||
beforehand. It can be quite hard to figure out between these two code bases
|
|
||||||
what settings are actually used. When chain-loading into U-Boot we must be
|
|
||||||
careful to reinit anything that U-Boot expects. If not, some peripherals (or
|
|
||||||
the whole machine) may not work. This makes the process of chainloading more
|
|
||||||
complicated than it could be on some platforms.
|
|
||||||
|
|
||||||
Finally, it supports only a subset of the U-Boot's FIT format. In particular
|
|
||||||
it uses a fixed address to load the FIT and does not support load/exec
|
|
||||||
addresses. This means that U-Boot must be able to boot from whatever
|
|
||||||
address Depthcharge happens to use (it is the CONFIG_KERNEL_START setting
|
|
||||||
in Depthcharge). In practice this means that the data in the kernel@1 FIT node
|
|
||||||
(see above) must start at the same address as U-Boot's CONFIG_SYS_TEXT_BASE.
|
|
||||||
|
|
239
doc/README.chromium-chainload
Normal file
239
doc/README.chromium-chainload
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
Running U-Boot from coreboot on Chromebooks
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
U-Boot can be used as a secondary boot loader in a few situations such as from
|
||||||
|
UEFI and coreboot (see README.x86). Recent Chromebooks use coreboot even on
|
||||||
|
ARM platforms to start up the machine.
|
||||||
|
|
||||||
|
This document aims to provide a guide to booting U-Boot on a Chromebook. It
|
||||||
|
is only a starting point, and there are many guides on the interwebs. But
|
||||||
|
placing this information in the U-Boot tree should make it easier to find for
|
||||||
|
those who use U-Boot habitually.
|
||||||
|
|
||||||
|
Most of these platforms are supported by U-Boot natively, but it is risky to
|
||||||
|
replace the ROM unless you have a servo board and cable to restore it with.
|
||||||
|
|
||||||
|
|
||||||
|
For all of these the standard U-Boot build instructions apply. For example on
|
||||||
|
ARM:
|
||||||
|
|
||||||
|
sudo apt install gcc-arm-linux-gnueabi
|
||||||
|
mkdir b
|
||||||
|
make O=b/nyan_big CROSS_COMPILE=arm-linux-gnueabi- nyan-big_defconfig all
|
||||||
|
|
||||||
|
You can obtain the vbutil_kernel utility here:
|
||||||
|
|
||||||
|
https://drive.google.com/open?id=0B7WYZbZ9zd-3dHlVVXo4VXE2T0U
|
||||||
|
|
||||||
|
|
||||||
|
Snow (Samsung ARM Chromebook)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
See here:
|
||||||
|
|
||||||
|
https://www.chromium.org/chromium-os/firmware-porting-guide/using-nv-u-boot-on-the-samsung-arm-chromebook
|
||||||
|
|
||||||
|
|
||||||
|
Nyan-big
|
||||||
|
--------
|
||||||
|
|
||||||
|
Compiled based on information here:
|
||||||
|
https://lists.denx.de/pipermail/u-boot/2015-March/209530.html
|
||||||
|
https://git.collabora.com/cgit/user/tomeu/u-boot.git/commit/?h=nyan-big
|
||||||
|
https://lists.denx.de/pipermail/u-boot/2017-May/289491.html
|
||||||
|
https://github.com/chromeos-nvidia-androidtv/gnu-linux-on-acer-chromebook-13#copy-data-to-the-sd-card
|
||||||
|
|
||||||
|
1. Build U-Boot
|
||||||
|
|
||||||
|
mkdir b
|
||||||
|
make -j8 O=b/nyan-big CROSS_COMPILE=arm-linux-gnueabi- nyan-big_defconfig all
|
||||||
|
|
||||||
|
|
||||||
|
2. Select a .its file
|
||||||
|
|
||||||
|
Select something from doc/chromium which matches your board, or create your
|
||||||
|
own.
|
||||||
|
|
||||||
|
Note that the device tree node is required, even though it is not actually
|
||||||
|
used by U-Boot. This is because the Chromebook expects to pass it to the
|
||||||
|
kernel, and crashes if it is not present.
|
||||||
|
|
||||||
|
|
||||||
|
3. Build and sign an image
|
||||||
|
|
||||||
|
./b/nyan-big/tools/mkimage -f doc/chromium/nyan-big.its u-boot-chromium.fit
|
||||||
|
echo test >dummy.txt
|
||||||
|
vbutil_kernel --arch arm --keyblock doc/chromium/devkeys/kernel.keyblock \
|
||||||
|
--signprivate doc/chromium/devkeys/kernel_data_key.vbprivk \
|
||||||
|
--version 1 --config dummy.txt --vmlinuz u-boot-chromium.fit \
|
||||||
|
--bootloader dummy.txt --pack u-boot.kpart
|
||||||
|
|
||||||
|
|
||||||
|
4. Prepare an SD card
|
||||||
|
|
||||||
|
DISK=/dev/sdc # Replace with your actual SD card device
|
||||||
|
sudo cgpt create $DISK
|
||||||
|
sudo cgpt add -b 34 -s 32768 -P 1 -S 1 -t kernel $DISK
|
||||||
|
sudo cgpt add -b 32802 -s 2000000 -t rootfs $DISK
|
||||||
|
sudo gdisk $DISK # Enter command 'w' to write a protective MBR to the disk
|
||||||
|
|
||||||
|
|
||||||
|
5. Write U-Boot to the SD card
|
||||||
|
|
||||||
|
sudo dd if=u-boot.kpart of=/dev/sdc1; sync
|
||||||
|
|
||||||
|
|
||||||
|
6. Start it up
|
||||||
|
|
||||||
|
Reboot the device in dev mode. Make sure that you have USB booting enabled. To
|
||||||
|
do this, login as root (via Ctrl-Alt-forward_arrow) and type
|
||||||
|
'enable_dev_usb_boot'. You only need to do this once.
|
||||||
|
|
||||||
|
Reboot the device with the SD card inserted. Press Clrl-U at the developer
|
||||||
|
mode screen. It should show something like the following on the display:
|
||||||
|
|
||||||
|
U-Boot 2017.07-00637-g242eb42-dirty (May 22 2017 - 06:14:21 -0600)
|
||||||
|
|
||||||
|
Model: Acer Chromebook 13 CB5-311
|
||||||
|
Board: Google/NVIDIA Nyan-big, ID: 1
|
||||||
|
|
||||||
|
Net: No ethernet found.
|
||||||
|
Hit any key to stop autoboot: 0
|
||||||
|
Tegra124 (Nyan-big) #
|
||||||
|
|
||||||
|
|
||||||
|
7. Known problems
|
||||||
|
|
||||||
|
On the serial console the word MMC is chopped at the start of the line:
|
||||||
|
|
||||||
|
C: sdhci@700b0000: 2, sdhci@700b0400: 1, sdhci@700b0600: 0
|
||||||
|
|
||||||
|
This is likely due to some problem with change-over of the serial driver
|
||||||
|
during relocation (or perhaps updating the clock setup in board_init()).
|
||||||
|
|
||||||
|
|
||||||
|
9. Notes
|
||||||
|
|
||||||
|
To check that you copied the u-boot.its file correctly, use these commands.
|
||||||
|
You should see that the data at 0x100 in u-boot-chromium.fit is the first few
|
||||||
|
bytes of U-Boot:
|
||||||
|
|
||||||
|
hd u-boot-chromium.fit |head -20
|
||||||
|
...
|
||||||
|
00000100 b8 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 |................|
|
||||||
|
|
||||||
|
hd b/nyan-big/u-boot.bin |head
|
||||||
|
00000000 b8 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 |................|
|
||||||
|
|
||||||
|
|
||||||
|
The 'data' property of the FIT is set up to start at offset 0x100 bytes into
|
||||||
|
the file. The change to CONFIG_SYS_TEXT_BASE is also an offset of 0x100 bytes
|
||||||
|
from the load address. If this changes, you either need to modify U-Boot to be
|
||||||
|
fully relocatable, or expect it to hang.
|
||||||
|
|
||||||
|
|
||||||
|
chromebook_jerry
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The instruction are similar to those for Nyan with changes as noted below:
|
||||||
|
|
||||||
|
1. Patch U-Boot
|
||||||
|
|
||||||
|
Open include/configs/rk3288_common.h
|
||||||
|
|
||||||
|
Change:
|
||||||
|
|
||||||
|
#define CONFIG_SYS_TEXT_BASE 0x00100000
|
||||||
|
|
||||||
|
to:
|
||||||
|
|
||||||
|
#define CONFIG_SYS_TEXT_BASE 0x02000100
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2. Build U-Boot
|
||||||
|
|
||||||
|
mkdir b
|
||||||
|
make -j8 O=b/chromebook_jerry CROSS_COMPILE=arm-linux-gnueabi- \
|
||||||
|
chromebook_jerry_defconfig all
|
||||||
|
|
||||||
|
|
||||||
|
3. See above
|
||||||
|
|
||||||
|
4. Build and sign an image
|
||||||
|
|
||||||
|
./b/chromebook_jerry/tools/mkimage -f doc/chromium/chromebook_jerry.its \
|
||||||
|
u-boot-chromium.fit
|
||||||
|
echo test >dummy.txt
|
||||||
|
vbutil_kernel --arch arm --keyblock doc/chromium/devkeys/kernel.keyblock \
|
||||||
|
--signprivate doc/chromium/devkeys/kernel_data_key.vbprivk \
|
||||||
|
--version 1 --config dummy.txt --vmlinuz u-boot-chromium.fit \
|
||||||
|
--bootloader dummy.txt --pack u-boot.kpart
|
||||||
|
|
||||||
|
|
||||||
|
5. See above
|
||||||
|
|
||||||
|
6. See above
|
||||||
|
|
||||||
|
7. Start it up
|
||||||
|
|
||||||
|
Reboot the device in dev mode. Make sure that you have USB booting enabled. To
|
||||||
|
do this, login as root (via Ctrl-Alt-forward_arrow) and type
|
||||||
|
'enable_dev_usb_boot'. You only need to do this once.
|
||||||
|
|
||||||
|
Reboot the device with the SD card inserted. Press Clrl-U at the developer
|
||||||
|
mode screen. It should show something like the following on the display:
|
||||||
|
|
||||||
|
U-Boot 2017.05-00649-g72acdbf-dirty (May 29 2017 - 14:57:05 -0600)
|
||||||
|
|
||||||
|
Model: Google Jerry
|
||||||
|
Net: Net Initialization Skipped
|
||||||
|
No ethernet found.
|
||||||
|
Hit any key to stop autoboot: 0
|
||||||
|
|
||||||
|
|
||||||
|
8. Known problems
|
||||||
|
|
||||||
|
None as yet.
|
||||||
|
|
||||||
|
|
||||||
|
9. Notes
|
||||||
|
|
||||||
|
None as yet.
|
||||||
|
|
||||||
|
|
||||||
|
Other notes
|
||||||
|
===========
|
||||||
|
|
||||||
|
flashrom
|
||||||
|
--------
|
||||||
|
|
||||||
|
Used to make a backup of your firmware, or to replace it.
|
||||||
|
|
||||||
|
See: https://www.chromium.org/chromium-os/packages/cros-flashrom
|
||||||
|
|
||||||
|
|
||||||
|
coreboot
|
||||||
|
--------
|
||||||
|
|
||||||
|
Coreboot itself is not designed to actually boot an OS. Instead, a program
|
||||||
|
called Depthcharge is used. This originally came out of U-Boot and was then
|
||||||
|
heavily hacked and modified such that is is almost unrecognisable. It does
|
||||||
|
include a very small part of the U-Boot command-line interface but is not
|
||||||
|
usable as a general-purpose boot loader.
|
||||||
|
|
||||||
|
In addition, it has a very unusual design in that it does not do device init
|
||||||
|
itself, but instead relies on coreboot. This is similar to (in U-Boot) having
|
||||||
|
a SPI driver with an empty probe() method, relying on whatever was set up
|
||||||
|
beforehand. It can be quite hard to figure out between these two code bases
|
||||||
|
what settings are actually used. When chain-loading into U-Boot we must be
|
||||||
|
careful to reinit anything that U-Boot expects. If not, some peripherals (or
|
||||||
|
the whole machine) may not work. This makes the process of chainloading more
|
||||||
|
complicated than it could be on some platforms.
|
||||||
|
|
||||||
|
Finally, it supports only a subset of the U-Boot's FIT format. In particular
|
||||||
|
it uses a fixed address to load the FIT and does not support load/exec
|
||||||
|
addresses. This means that U-Boot must be able to boot from whatever
|
||||||
|
address Depthcharge happens to use (it is the CONFIG_KERNEL_START setting
|
||||||
|
in Depthcharge). In practice this means that the data in the kernel@1 FIT node
|
||||||
|
(see above) must start at the same address as U-Boot's CONFIG_SYS_TEXT_BASE.
|
|
@ -254,7 +254,8 @@ static int socfpga_a10_clk_bind(struct udevice *dev)
|
||||||
fdt_node_check_compatible(fdt, offset, "fixed-clock"))
|
fdt_node_check_compatible(fdt, offset, "fixed-clock"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pre_reloc_only && !dm_fdt_pre_reloc(fdt, offset))
|
if (pre_reloc_only &&
|
||||||
|
!dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = device_bind_driver_to_node(dev, "clk-a10", name,
|
ret = device_bind_driver_to_node(dev, "clk-a10", name,
|
||||||
|
|
|
@ -61,7 +61,7 @@ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
|
||||||
offset > 0;
|
offset > 0;
|
||||||
offset = fdt_next_subnode(fdt, offset)) {
|
offset = fdt_next_subnode(fdt, offset)) {
|
||||||
if (pre_reloc_only &&
|
if (pre_reloc_only &&
|
||||||
!dm_fdt_pre_reloc(fdt, offset))
|
!dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
|
||||||
continue;
|
continue;
|
||||||
/*
|
/*
|
||||||
* If this node has "compatible" property, this is not
|
* If this node has "compatible" property, this is not
|
||||||
|
|
|
@ -254,14 +254,13 @@ int ofnode_read_size(ofnode node, const char *propname)
|
||||||
fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
|
fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
|
||||||
{
|
{
|
||||||
int na, ns;
|
int na, ns;
|
||||||
fdt_size_t size;
|
|
||||||
|
|
||||||
if (ofnode_is_np(node)) {
|
if (ofnode_is_np(node)) {
|
||||||
const __be32 *prop_val;
|
const __be32 *prop_val;
|
||||||
uint flags;
|
uint flags;
|
||||||
|
|
||||||
prop_val = of_get_address(ofnode_to_np(node), index,
|
prop_val = of_get_address(ofnode_to_np(node), index,
|
||||||
(u64 *)&size, &flags);
|
NULL, &flags);
|
||||||
if (!prop_val)
|
if (!prop_val)
|
||||||
return FDT_ADDR_T_NONE;
|
return FDT_ADDR_T_NONE;
|
||||||
|
|
||||||
|
@ -278,7 +277,7 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
|
||||||
ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
|
ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
|
||||||
return fdtdec_get_addr_size_fixed(gd->fdt_blob,
|
return fdtdec_get_addr_size_fixed(gd->fdt_blob,
|
||||||
ofnode_to_offset(node), "reg",
|
ofnode_to_offset(node), "reg",
|
||||||
index, na, ns, &size, true);
|
index, na, ns, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FDT_ADDR_T_NONE;
|
return FDT_ADDR_T_NONE;
|
||||||
|
@ -700,18 +699,18 @@ int ofnode_read_simple_size_cells(ofnode node)
|
||||||
|
|
||||||
bool ofnode_pre_reloc(ofnode node)
|
bool ofnode_pre_reloc(ofnode node)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
|
||||||
|
/* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
|
||||||
|
* had property dm-pre-reloc or u-boot,dm-spl/tpl.
|
||||||
|
* They are removed in final dtb (fdtgrep 2nd pass)
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
|
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
|
||||||
return true;
|
return true;
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
|
if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef CONFIG_TPL_BUILD
|
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-tpl"))
|
|
||||||
return true;
|
|
||||||
#elif defined(CONFIG_SPL_BUILD)
|
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-spl"))
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
/*
|
/*
|
||||||
* In regular builds individual spl and tpl handling both
|
* In regular builds individual spl and tpl handling both
|
||||||
* count as handled pre-relocation for later second init.
|
* count as handled pre-relocation for later second init.
|
||||||
|
@ -719,9 +718,9 @@ bool ofnode_pre_reloc(ofnode node)
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
|
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
|
||||||
ofnode_read_bool(node, "u-boot,dm-tpl"))
|
ofnode_read_bool(node, "u-boot,dm-tpl"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ofnode_read_resource(ofnode node, uint index, struct resource *res)
|
int ofnode_read_resource(ofnode node, uint index, struct resource *res)
|
||||||
|
|
|
@ -57,18 +57,64 @@ static int syscon_pre_probe(struct udevice *dev)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
|
||||||
|
{
|
||||||
|
struct udevice *dev, *parent;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
|
||||||
|
if (!ofnode_device_is_compatible(node, "syscon")) {
|
||||||
|
dev_dbg(dev, "invalid compatible for syscon device\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bound to driver with same ofnode or to root if not found */
|
||||||
|
if (device_find_global_by_ofnode(node, &parent))
|
||||||
|
parent = dm_root();
|
||||||
|
|
||||||
|
/* force bound to syscon class */
|
||||||
|
ret = device_bind_driver_to_node(parent, "syscon",
|
||||||
|
ofnode_get_name(node),
|
||||||
|
node, &dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_dbg(dev, "unable to bound syscon device\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = device_probe(dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_dbg(dev, "unable to probe syscon device\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*devp = dev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
|
struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
struct udevice *syscon;
|
struct udevice *syscon;
|
||||||
struct regmap *r;
|
struct regmap *r;
|
||||||
|
u32 phandle;
|
||||||
|
ofnode node;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
|
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
|
||||||
name, &syscon);
|
name, &syscon);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_dbg(dev, "unable to find syscon device\n");
|
/* found node with "syscon" compatible, not bounded to SYSCON */
|
||||||
return ERR_PTR(err);
|
err = ofnode_read_u32(dev_ofnode(dev), name, &phandle);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
node = ofnode_get_by_phandle(phandle);
|
||||||
|
if (!ofnode_valid(node)) {
|
||||||
|
dev_dbg(dev, "unable to find syscon device\n");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
err = syscon_probe_by_ofnode(node, &syscon);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = syscon_get_regmap(syscon);
|
r = syscon_get_regmap(syscon);
|
||||||
|
@ -152,29 +198,18 @@ U_BOOT_DRIVER(generic_syscon) = {
|
||||||
*/
|
*/
|
||||||
struct regmap *syscon_node_to_regmap(ofnode node)
|
struct regmap *syscon_node_to_regmap(ofnode node)
|
||||||
{
|
{
|
||||||
struct udevice *dev, *parent;
|
struct udevice *dev;
|
||||||
int ret;
|
struct regmap *r;
|
||||||
|
|
||||||
if (!uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
|
if (uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
|
||||||
return syscon_get_regmap(dev);
|
if (syscon_probe_by_ofnode(node, &dev))
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
if (!ofnode_device_is_compatible(node, "syscon"))
|
r = syscon_get_regmap(dev);
|
||||||
return ERR_PTR(-EINVAL);
|
if (!r) {
|
||||||
|
dev_dbg(dev, "unable to find regmap\n");
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
/* bound to driver with same ofnode or to root if not found */
|
return r;
|
||||||
if (device_find_global_by_ofnode(node, &parent))
|
|
||||||
parent = dm_root();
|
|
||||||
|
|
||||||
/* force bound to syscon class */
|
|
||||||
ret = device_bind_driver_to_node(parent, "syscon",
|
|
||||||
ofnode_get_name(node),
|
|
||||||
node, &dev);
|
|
||||||
if (ret)
|
|
||||||
return ERR_PTR(ret);
|
|
||||||
|
|
||||||
ret = device_probe(dev);
|
|
||||||
if (ret)
|
|
||||||
return ERR_PTR(ret);
|
|
||||||
|
|
||||||
return syscon_get_regmap(dev);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,42 +31,18 @@ int list_count_items(struct list_head *head)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dm_fdt_pre_reloc(const void *blob, int offset)
|
|
||||||
{
|
|
||||||
if (fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
#ifdef CONFIG_TPL_BUILD
|
|
||||||
if (fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL))
|
|
||||||
return true;
|
|
||||||
#elif defined(CONFIG_SPL_BUILD)
|
|
||||||
if (fdt_getprop(blob, offset, "u-boot,dm-spl", NULL))
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* In regular builds individual spl and tpl handling both
|
|
||||||
* count as handled pre-relocation for later second init.
|
|
||||||
*/
|
|
||||||
if (fdt_getprop(blob, offset, "u-boot,dm-spl", NULL) ||
|
|
||||||
fdt_getprop(blob, offset, "u-boot,dm-tpl", NULL))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dm_ofnode_pre_reloc(ofnode node)
|
bool dm_ofnode_pre_reloc(ofnode node)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
|
||||||
|
/* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
|
||||||
|
* had property dm-pre-reloc or u-boot,dm-spl/tpl.
|
||||||
|
* They are removed in final dtb (fdtgrep 2nd pass)
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
|
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef CONFIG_TPL_BUILD
|
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-tpl"))
|
|
||||||
return true;
|
|
||||||
#elif defined(CONFIG_SPL_BUILD)
|
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-spl"))
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
/*
|
/*
|
||||||
* In regular builds individual spl and tpl handling both
|
* In regular builds individual spl and tpl handling both
|
||||||
* count as handled pre-relocation for later second init.
|
* count as handled pre-relocation for later second init.
|
||||||
|
@ -74,7 +50,7 @@ bool dm_ofnode_pre_reloc(ofnode node)
|
||||||
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
|
if (ofnode_read_bool(node, "u-boot,dm-spl") ||
|
||||||
ofnode_read_bool(node, "u-boot,dm-tpl"))
|
ofnode_read_bool(node, "u-boot,dm-tpl"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,28 +27,6 @@ int pinctrl_decode_pin_config(const void *blob, int node)
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: this function is temporary for v2019.01.
|
|
||||||
* It should be renamed to pinctrl_decode_pin_config(),
|
|
||||||
* the original pinctrl_decode_pin_config() function should
|
|
||||||
* be removed and all callers of the original function should
|
|
||||||
* be migrated to use the new one.
|
|
||||||
*/
|
|
||||||
int pinctrl_decode_pin_config_dm(struct udevice *dev)
|
|
||||||
{
|
|
||||||
int pinconfig = 0;
|
|
||||||
|
|
||||||
if (dev->uclass->uc_drv->id != UCLASS_PINCONFIG)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (dev_read_bool(dev, "bias-pull-up"))
|
|
||||||
pinconfig |= 1 << PIN_CONFIG_BIAS_PULL_UP;
|
|
||||||
else if (dev_read_bool(dev, "bias-pull-down"))
|
|
||||||
pinconfig |= 1 << PIN_CONFIG_BIAS_PULL_DOWN;
|
|
||||||
|
|
||||||
return pinconfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
|
#if CONFIG_IS_ENABLED(PINCTRL_FULL)
|
||||||
/**
|
/**
|
||||||
* pinctrl_config_one() - apply pinctrl settings for a single node
|
* pinctrl_config_one() - apply pinctrl settings for a single node
|
||||||
|
@ -149,6 +127,9 @@ static int pinconfig_post_bind(struct udevice *dev)
|
||||||
ofnode_get_property(node, "compatible", &ret);
|
ofnode_get_property(node, "compatible", &ret);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
continue;
|
continue;
|
||||||
|
/* If this node has "gpio-controller" property, skip */
|
||||||
|
if (ofnode_read_bool(node, "gpio-controller"))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (ret != -FDT_ERR_NOTFOUND)
|
if (ret != -FDT_ERR_NOTFOUND)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -201,11 +182,14 @@ static int pinctrl_select_state_simple(struct udevice *dev)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For simplicity, assume the first device of PINCTRL uclass
|
* For most system, there is only one pincontroller device. But in
|
||||||
* is the correct one. This is most likely OK as there is
|
* case of multiple pincontroller devices, probe the one with sequence
|
||||||
* usually only one pinctrl device on the system.
|
* number 0 (defined by alias) to avoid race condition.
|
||||||
*/
|
*/
|
||||||
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
|
ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev);
|
||||||
|
if (ret)
|
||||||
|
/* if not found, get the first one */
|
||||||
|
ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -36,20 +36,9 @@ static struct sysreset_ops syscon_reboot_ops = {
|
||||||
int syscon_reboot_probe(struct udevice *dev)
|
int syscon_reboot_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct syscon_reboot_priv *priv = dev_get_priv(dev);
|
struct syscon_reboot_priv *priv = dev_get_priv(dev);
|
||||||
int err;
|
|
||||||
u32 phandle;
|
|
||||||
ofnode node;
|
|
||||||
|
|
||||||
err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle);
|
priv->regmap = syscon_regmap_lookup_by_phandle(dev, "regmap");
|
||||||
if (err)
|
if (IS_ERR(priv->regmap)) {
|
||||||
return err;
|
|
||||||
|
|
||||||
node = ofnode_get_by_phandle(phandle);
|
|
||||||
if (!ofnode_valid(node))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
priv->regmap = syscon_node_to_regmap(node);
|
|
||||||
if (!priv->regmap) {
|
|
||||||
pr_err("unable to find regmap\n");
|
pr_err("unable to find regmap\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,10 +291,10 @@ config SPL_MULTI_DTB_FIT_USER_DEF_ADDR
|
||||||
config OF_SPL_REMOVE_PROPS
|
config OF_SPL_REMOVE_PROPS
|
||||||
string "List of device tree properties to drop for SPL"
|
string "List of device tree properties to drop for SPL"
|
||||||
depends on SPL_OF_CONTROL
|
depends on SPL_OF_CONTROL
|
||||||
default "interrupt-parent" if SPL_PINCTRL && SPL_CLK
|
default "interrupt-parent interrupts" if SPL_PINCTRL && SPL_CLK
|
||||||
default "clocks clock-names interrupt-parent" if SPL_PINCTRL
|
default "clocks clock-names interrupt-parent interrupts" if SPL_PINCTRL
|
||||||
default "pinctrl-0 pinctrl-names interrupt-parent" if SPL_CLK
|
default "pinctrl-0 pinctrl-names interrupt-parent interrupts" if SPL_CLK
|
||||||
default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
|
default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent interrupts"
|
||||||
help
|
help
|
||||||
Since SPL normally runs in a reduced memory space, the device tree
|
Since SPL normally runs in a reduced memory space, the device tree
|
||||||
is cut down to only what is needed to load and start U-Boot. Only
|
is cut down to only what is needed to load and start U-Boot. Only
|
||||||
|
|
|
@ -354,18 +354,6 @@ int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph);
|
||||||
*/
|
*/
|
||||||
int pinctrl_decode_pin_config(const void *blob, int node);
|
int pinctrl_decode_pin_config(const void *blob, int node);
|
||||||
|
|
||||||
/**
|
|
||||||
* pinctrl_decode_pin_config_dm() - decode pin configuration flags
|
|
||||||
*
|
|
||||||
* This decodes some of the PIN_CONFIG values into flags, with each value
|
|
||||||
* being (1 << pin_cfg). This does not support things with values like the
|
|
||||||
* slew rate.
|
|
||||||
*
|
|
||||||
* @pinconfig: Pinconfig udevice
|
|
||||||
* @return decoded flag value, or -ve on error
|
|
||||||
*/
|
|
||||||
int pinctrl_decode_pin_config_dm(struct udevice *dev);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pinctrl_get_gpio_mux() - get the mux value for a particular GPIO
|
* pinctrl_get_gpio_mux() - get the mux value for a particular GPIO
|
||||||
*
|
*
|
||||||
|
|
|
@ -39,32 +39,6 @@ static inline void dm_dump_devres(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a dt node should be or was bound before relocation.
|
|
||||||
*
|
|
||||||
* Devicetree nodes can be marked as needed to be bound
|
|
||||||
* in the loader stages via special devicetree properties.
|
|
||||||
*
|
|
||||||
* Before relocation this function can be used to check if nodes
|
|
||||||
* are required in either SPL or TPL stages.
|
|
||||||
*
|
|
||||||
* After relocation and jumping into the real U-Boot binary
|
|
||||||
* it is possible to determine if a node was bound in one of
|
|
||||||
* SPL/TPL stages.
|
|
||||||
*
|
|
||||||
* There are 3 settings currently in use
|
|
||||||
* -
|
|
||||||
* - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL
|
|
||||||
* Existing platforms only use it to indicate nodes needed in
|
|
||||||
* SPL. Should probably be replaced by u-boot,dm-spl for
|
|
||||||
* existing platforms.
|
|
||||||
* @blob: devicetree
|
|
||||||
* @offset: node offset
|
|
||||||
*
|
|
||||||
* Returns true if node is needed in SPL/TL, false otherwise.
|
|
||||||
*/
|
|
||||||
bool dm_fdt_pre_reloc(const void *blob, int offset);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an of node should be or was bound before relocation.
|
* Check if an of node should be or was bound before relocation.
|
||||||
*
|
*
|
||||||
|
|
169
include/fdtdec.h
169
include/fdtdec.h
|
@ -23,15 +23,44 @@
|
||||||
*/
|
*/
|
||||||
typedef phys_addr_t fdt_addr_t;
|
typedef phys_addr_t fdt_addr_t;
|
||||||
typedef phys_size_t fdt_size_t;
|
typedef phys_size_t fdt_size_t;
|
||||||
|
|
||||||
|
static inline fdt32_t fdt_addr_unpack(fdt_addr_t addr, fdt32_t *upper)
|
||||||
|
{
|
||||||
|
if (upper)
|
||||||
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
|
*upper = addr >> 32;
|
||||||
|
#else
|
||||||
|
*upper = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline fdt32_t fdt_size_unpack(fdt_size_t size, fdt32_t *upper)
|
||||||
|
{
|
||||||
|
if (upper)
|
||||||
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
|
*upper = size >> 32;
|
||||||
|
#else
|
||||||
|
*upper = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PHYS_64BIT
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
#define FDT_ADDR_T_NONE (-1U)
|
#define FDT_ADDR_T_NONE (-1U)
|
||||||
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
|
#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
|
||||||
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
|
#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
|
||||||
|
#define cpu_to_fdt_addr(reg) cpu_to_be64(reg)
|
||||||
|
#define cpu_to_fdt_size(reg) cpu_to_be64(reg)
|
||||||
typedef fdt64_t fdt_val_t;
|
typedef fdt64_t fdt_val_t;
|
||||||
#else
|
#else
|
||||||
#define FDT_ADDR_T_NONE (-1U)
|
#define FDT_ADDR_T_NONE (-1U)
|
||||||
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
|
#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
|
||||||
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
|
#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
|
||||||
|
#define cpu_to_fdt_addr(reg) cpu_to_be32(reg)
|
||||||
|
#define cpu_to_fdt_size(reg) cpu_to_be32(reg)
|
||||||
typedef fdt32_t fdt_val_t;
|
typedef fdt32_t fdt_val_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -991,6 +1020,146 @@ int fdtdec_setup_memory_banksize_fdt(const void *blob);
|
||||||
*/
|
*/
|
||||||
int fdtdec_setup_memory_banksize(void);
|
int fdtdec_setup_memory_banksize(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdtdec_set_phandle() - sets the phandle of a given node
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param node offset in the FDT blob of the node whose phandle is to
|
||||||
|
* be set
|
||||||
|
* @param phandle phandle to set for the given node
|
||||||
|
* @return 0 on success or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdtdec_set_phandle(void *blob, int node, uint32_t phandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdtdec_add_reserved_memory() - add or find a reserved-memory node
|
||||||
|
*
|
||||||
|
* If a reserved-memory node already exists for the given carveout, a phandle
|
||||||
|
* for that node will be returned. Otherwise a new node will be created and a
|
||||||
|
* phandle corresponding to it will be returned.
|
||||||
|
*
|
||||||
|
* See Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
|
||||||
|
* for details on how to use reserved memory regions.
|
||||||
|
*
|
||||||
|
* As an example, consider the following code snippet:
|
||||||
|
*
|
||||||
|
* struct fdt_memory fb = {
|
||||||
|
* .start = 0x92cb3000,
|
||||||
|
* .end = 0x934b2fff,
|
||||||
|
* };
|
||||||
|
* uint32_t phandle;
|
||||||
|
*
|
||||||
|
* fdtdec_add_reserved_memory(fdt, "framebuffer", &fb, &phandle);
|
||||||
|
*
|
||||||
|
* This results in the following subnode being added to the top-level
|
||||||
|
* /reserved-memory node:
|
||||||
|
*
|
||||||
|
* reserved-memory {
|
||||||
|
* #address-cells = <0x00000002>;
|
||||||
|
* #size-cells = <0x00000002>;
|
||||||
|
* ranges;
|
||||||
|
*
|
||||||
|
* framebuffer@92cb3000 {
|
||||||
|
* reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>;
|
||||||
|
* phandle = <0x0000004d>;
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* If the top-level /reserved-memory node does not exist, it will be created.
|
||||||
|
* The phandle returned from the function call can be used to reference this
|
||||||
|
* reserved memory region from other nodes.
|
||||||
|
*
|
||||||
|
* See fdtdec_set_carveout() for a more elaborate example.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param basename base name of the node to create
|
||||||
|
* @param carveout information about the carveout region
|
||||||
|
* @param phandlep return location for the phandle of the carveout region
|
||||||
|
* @return 0 on success or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdtdec_add_reserved_memory(void *blob, const char *basename,
|
||||||
|
const struct fdt_memory *carveout,
|
||||||
|
uint32_t *phandlep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdtdec_get_carveout() - reads a carveout from an FDT
|
||||||
|
*
|
||||||
|
* Reads information about a carveout region from an FDT. The carveout is a
|
||||||
|
* referenced by its phandle that is read from a given property in a given
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param node name of a node
|
||||||
|
* @param name name of the property in the given node that contains
|
||||||
|
* the phandle for the carveout
|
||||||
|
* @param index index of the phandle for which to read the carveout
|
||||||
|
* @param carveout return location for the carveout information
|
||||||
|
* @return 0 on success or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdtdec_get_carveout(const void *blob, const char *node, const char *name,
|
||||||
|
unsigned int index, struct fdt_memory *carveout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdtdec_set_carveout() - sets a carveout region for a given node
|
||||||
|
*
|
||||||
|
* Sets a carveout region for a given node. If a reserved-memory node already
|
||||||
|
* exists for the carveout, the phandle for that node will be reused. If no
|
||||||
|
* such node exists, a new one will be created and a phandle to it stored in
|
||||||
|
* a specified property of the given node.
|
||||||
|
*
|
||||||
|
* As an example, consider the following code snippet:
|
||||||
|
*
|
||||||
|
* const char *node = "/host1x@50000000/dc@54240000";
|
||||||
|
* struct fdt_memory fb = {
|
||||||
|
* .start = 0x92cb3000,
|
||||||
|
* .end = 0x934b2fff,
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* fdtdec_set_carveout(fdt, node, "memory-region", 0, "framebuffer", &fb);
|
||||||
|
*
|
||||||
|
* dc@54200000 is a display controller and was set up by the bootloader to
|
||||||
|
* scan out the framebuffer specified by "fb". This would cause the following
|
||||||
|
* reserved memory region to be added:
|
||||||
|
*
|
||||||
|
* reserved-memory {
|
||||||
|
* #address-cells = <0x00000002>;
|
||||||
|
* #size-cells = <0x00000002>;
|
||||||
|
* ranges;
|
||||||
|
*
|
||||||
|
* framebuffer@92cb3000 {
|
||||||
|
* reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>;
|
||||||
|
* phandle = <0x0000004d>;
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* A "memory-region" property will also be added to the node referenced by the
|
||||||
|
* offset parameter.
|
||||||
|
*
|
||||||
|
* host1x@50000000 {
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* dc@54240000 {
|
||||||
|
* ...
|
||||||
|
* memory-region = <0x0000004d>;
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @param blob FDT blob
|
||||||
|
* @param node name of the node to add the carveout to
|
||||||
|
* @param prop_name name of the property in which to store the phandle of
|
||||||
|
* the carveout
|
||||||
|
* @param index index of the phandle to store
|
||||||
|
* @param name base name of the reserved-memory node to create
|
||||||
|
* @param carveout information about the carveout to add
|
||||||
|
* @return 0 on success or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name,
|
||||||
|
unsigned int index, const char *name,
|
||||||
|
const struct fdt_memory *carveout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the device tree ready for use
|
* Set up the device tree ready for use
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -436,4 +436,8 @@ source lib/efi/Kconfig
|
||||||
source lib/efi_loader/Kconfig
|
source lib/efi_loader/Kconfig
|
||||||
source lib/optee/Kconfig
|
source lib/optee/Kconfig
|
||||||
|
|
||||||
|
config TEST_FDTDEC
|
||||||
|
bool "enable fdtdec test"
|
||||||
|
depends on OF_LIBFDT
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
225
lib/fdtdec.c
225
lib/fdtdec.c
|
@ -1261,6 +1261,231 @@ __weak void *board_fdt_blob_setup(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int fdtdec_set_phandle(void *blob, int node, uint32_t phandle)
|
||||||
|
{
|
||||||
|
fdt32_t value = cpu_to_fdt32(phandle);
|
||||||
|
|
||||||
|
return fdt_setprop(blob, node, "phandle", &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdtdec_init_reserved_memory(void *blob)
|
||||||
|
{
|
||||||
|
int na, ns, node, err;
|
||||||
|
fdt32_t value;
|
||||||
|
|
||||||
|
/* inherit #address-cells and #size-cells from the root node */
|
||||||
|
na = fdt_address_cells(blob, 0);
|
||||||
|
ns = fdt_size_cells(blob, 0);
|
||||||
|
|
||||||
|
node = fdt_add_subnode(blob, 0, "reserved-memory");
|
||||||
|
if (node < 0)
|
||||||
|
return node;
|
||||||
|
|
||||||
|
err = fdt_setprop(blob, node, "ranges", NULL, 0);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
value = cpu_to_fdt32(ns);
|
||||||
|
|
||||||
|
err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
value = cpu_to_fdt32(na);
|
||||||
|
|
||||||
|
err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdtdec_add_reserved_memory(void *blob, const char *basename,
|
||||||
|
const struct fdt_memory *carveout,
|
||||||
|
uint32_t *phandlep)
|
||||||
|
{
|
||||||
|
fdt32_t cells[4] = {}, *ptr = cells;
|
||||||
|
uint32_t upper, lower, phandle;
|
||||||
|
int parent, node, na, ns, err;
|
||||||
|
char name[64];
|
||||||
|
|
||||||
|
/* create an empty /reserved-memory node if one doesn't exist */
|
||||||
|
parent = fdt_path_offset(blob, "/reserved-memory");
|
||||||
|
if (parent < 0) {
|
||||||
|
parent = fdtdec_init_reserved_memory(blob);
|
||||||
|
if (parent < 0)
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only 1 or 2 #address-cells and #size-cells are supported */
|
||||||
|
na = fdt_address_cells(blob, parent);
|
||||||
|
if (na < 1 || na > 2)
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
ns = fdt_size_cells(blob, parent);
|
||||||
|
if (ns < 1 || ns > 2)
|
||||||
|
return -FDT_ERR_BADNCELLS;
|
||||||
|
|
||||||
|
/* find a matching node and return the phandle to that */
|
||||||
|
fdt_for_each_subnode(node, blob, parent) {
|
||||||
|
const char *name = fdt_get_name(blob, node, NULL);
|
||||||
|
phys_addr_t addr, size;
|
||||||
|
|
||||||
|
addr = fdtdec_get_addr_size(blob, node, "reg", &size);
|
||||||
|
if (addr == FDT_ADDR_T_NONE) {
|
||||||
|
debug("failed to read address/size for %s\n", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr == carveout->start && (addr + size) == carveout->end) {
|
||||||
|
*phandlep = fdt_get_phandle(blob, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpack the start address and generate the name of the new node
|
||||||
|
* base on the basename and the unit-address.
|
||||||
|
*/
|
||||||
|
lower = fdt_addr_unpack(carveout->start, &upper);
|
||||||
|
|
||||||
|
if (na > 1 && upper > 0)
|
||||||
|
snprintf(name, sizeof(name), "%s@%x,%x", basename, upper,
|
||||||
|
lower);
|
||||||
|
else {
|
||||||
|
if (upper > 0) {
|
||||||
|
debug("address %08x:%08x exceeds addressable space\n",
|
||||||
|
upper, lower);
|
||||||
|
return -FDT_ERR_BADVALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "%s@%x", basename, lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_add_subnode(blob, parent, name);
|
||||||
|
if (node < 0)
|
||||||
|
return node;
|
||||||
|
|
||||||
|
err = fdt_generate_phandle(blob, &phandle);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = fdtdec_set_phandle(blob, node, phandle);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* store one or two address cells */
|
||||||
|
if (na > 1)
|
||||||
|
*ptr++ = cpu_to_fdt32(upper);
|
||||||
|
|
||||||
|
*ptr++ = cpu_to_fdt32(lower);
|
||||||
|
|
||||||
|
/* store one or two size cells */
|
||||||
|
lower = fdt_size_unpack(carveout->end - carveout->start + 1, &upper);
|
||||||
|
|
||||||
|
if (ns > 1)
|
||||||
|
*ptr++ = cpu_to_fdt32(upper);
|
||||||
|
|
||||||
|
*ptr++ = cpu_to_fdt32(lower);
|
||||||
|
|
||||||
|
err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* return the phandle for the new node for the caller to use */
|
||||||
|
if (phandlep)
|
||||||
|
*phandlep = phandle;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdtdec_get_carveout(const void *blob, const char *node, const char *name,
|
||||||
|
unsigned int index, struct fdt_memory *carveout)
|
||||||
|
{
|
||||||
|
const fdt32_t *prop;
|
||||||
|
uint32_t phandle;
|
||||||
|
int offset, len;
|
||||||
|
fdt_size_t size;
|
||||||
|
|
||||||
|
offset = fdt_path_offset(blob, node);
|
||||||
|
if (offset < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
prop = fdt_getprop(blob, offset, name, &len);
|
||||||
|
if (!prop) {
|
||||||
|
debug("failed to get %s for %s\n", name, node);
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((len % sizeof(phandle)) != 0) {
|
||||||
|
debug("invalid phandle property\n");
|
||||||
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < (sizeof(phandle) * (index + 1))) {
|
||||||
|
debug("invalid phandle index\n");
|
||||||
|
return -FDT_ERR_BADPHANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
phandle = fdt32_to_cpu(prop[index]);
|
||||||
|
|
||||||
|
offset = fdt_node_offset_by_phandle(blob, phandle);
|
||||||
|
if (offset < 0) {
|
||||||
|
debug("failed to find node for phandle %u\n", phandle);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset,
|
||||||
|
"reg", 0, &size,
|
||||||
|
true);
|
||||||
|
if (carveout->start == FDT_ADDR_T_NONE) {
|
||||||
|
debug("failed to read address/size from \"reg\" property\n");
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
carveout->end = carveout->start + size - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name,
|
||||||
|
unsigned int index, const char *name,
|
||||||
|
const struct fdt_memory *carveout)
|
||||||
|
{
|
||||||
|
uint32_t phandle;
|
||||||
|
int err, offset;
|
||||||
|
fdt32_t value;
|
||||||
|
|
||||||
|
/* XXX implement support for multiple phandles */
|
||||||
|
if (index > 0) {
|
||||||
|
debug("invalid index %u\n", index);
|
||||||
|
return -FDT_ERR_BADOFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle);
|
||||||
|
if (err < 0) {
|
||||||
|
debug("failed to add reserved memory: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = fdt_path_offset(blob, node);
|
||||||
|
if (offset < 0) {
|
||||||
|
debug("failed to find offset for node %s: %d\n", node, offset);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = cpu_to_fdt32(phandle);
|
||||||
|
|
||||||
|
err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value));
|
||||||
|
if (err < 0) {
|
||||||
|
debug("failed to set %s property for node %s: %d\n", prop_name,
|
||||||
|
node, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdtdec_setup(void)
|
int fdtdec_setup(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||||
|
|
|
@ -15,48 +15,28 @@
|
||||||
/* The size of our test fdt blob */
|
/* The size of our test fdt blob */
|
||||||
#define FDT_SIZE (16 * 1024)
|
#define FDT_SIZE (16 * 1024)
|
||||||
|
|
||||||
/**
|
#define CHECK(op) ({ \
|
||||||
* Check if an operation failed, and if so, print an error
|
int err = op; \
|
||||||
*
|
if (err < 0) { \
|
||||||
* @param oper_name Name of operation
|
printf("%s: %s: %s\n", __func__, #op, \
|
||||||
* @param err Error code to check
|
fdt_strerror(err)); \
|
||||||
*
|
return err; \
|
||||||
* @return 0 if ok, -1 if there was an error
|
} \
|
||||||
*/
|
\
|
||||||
static int fdt_checkerr(const char *oper_name, int err)
|
err; \
|
||||||
{
|
})
|
||||||
if (err) {
|
|
||||||
printf("%s: %s: %s\n", __func__, oper_name, fdt_strerror(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
#define CHECKVAL(op, expected) ({ \
|
||||||
}
|
int err = op; \
|
||||||
|
if (err != expected) { \
|
||||||
|
printf("%s: %s: expected %d, but returned %d\n",\
|
||||||
|
__func__, #op, expected, err); \
|
||||||
|
return err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
err; \
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the result of an operation and if incorrect, print an error
|
|
||||||
*
|
|
||||||
* @param oper_name Name of operation
|
|
||||||
* @param expected Expected value
|
|
||||||
* @param value Actual value
|
|
||||||
*
|
|
||||||
* @return 0 if ok, -1 if there was an error
|
|
||||||
*/
|
|
||||||
static int checkval(const char *oper_name, int expected, int value)
|
|
||||||
{
|
|
||||||
if (expected != value) {
|
|
||||||
printf("%s: %s: expected %d, but returned %d\n", __func__,
|
|
||||||
oper_name, expected, value);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK(op) if (fdt_checkerr(#op, op)) return -1
|
|
||||||
#define CHECKVAL(op, expected) \
|
|
||||||
if (checkval(#op, expected, op)) \
|
|
||||||
return -1
|
|
||||||
#define CHECKOK(op) CHECKVAL(op, 0)
|
#define CHECKOK(op) CHECKVAL(op, 0)
|
||||||
|
|
||||||
/* maximum number of nodes / aliases to generate */
|
/* maximum number of nodes / aliases to generate */
|
||||||
|
@ -79,7 +59,9 @@ static int make_fdt(void *fdt, int size, const char *aliases,
|
||||||
{
|
{
|
||||||
char name[20], value[20];
|
char name[20], value[20];
|
||||||
const char *s;
|
const char *s;
|
||||||
|
#if defined(DEBUG) && defined(CONFIG_SANDBOX)
|
||||||
int fd;
|
int fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
CHECK(fdt_create(fdt, size));
|
CHECK(fdt_create(fdt, size));
|
||||||
CHECK(fdt_finish_reservemap(fdt));
|
CHECK(fdt_finish_reservemap(fdt));
|
||||||
|
@ -136,7 +118,7 @@ static int run_test(const char *aliases, const char *nodes, const char *expect)
|
||||||
CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0);
|
CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0);
|
||||||
CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c",
|
CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c",
|
||||||
COMPAT_UNKNOWN,
|
COMPAT_UNKNOWN,
|
||||||
list, ARRAY_SIZE(list)), strlen(expect));
|
list, ARRAY_SIZE(list)), (int)strlen(expect));
|
||||||
|
|
||||||
/* Check we got the right ones */
|
/* Check we got the right ones */
|
||||||
for (i = 0, s = expect; *s; s++, i++) {
|
for (i = 0, s = expect; *s; s++, i++) {
|
||||||
|
@ -159,6 +141,156 @@ static int run_test(const char *aliases, const char *nodes, const char *expect)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int make_fdt_carveout_device(void *fdt, uint32_t na, uint32_t ns)
|
||||||
|
{
|
||||||
|
const char *basename = "/display";
|
||||||
|
struct fdt_memory carveout = {
|
||||||
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
|
.start = 0x180000000,
|
||||||
|
.end = 0x18fffffff,
|
||||||
|
#else
|
||||||
|
.start = 0x80000000,
|
||||||
|
.end = 0x8fffffff,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
fdt32_t cells[4], *ptr = cells;
|
||||||
|
uint32_t upper, lower;
|
||||||
|
char name[32];
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
/* store one or two address cells */
|
||||||
|
lower = fdt_addr_unpack(carveout.start, &upper);
|
||||||
|
|
||||||
|
if (na > 1 && upper > 0)
|
||||||
|
snprintf(name, sizeof(name), "%s@%x,%x", basename, upper,
|
||||||
|
lower);
|
||||||
|
else
|
||||||
|
snprintf(name, sizeof(name), "%s@%x", basename, lower);
|
||||||
|
|
||||||
|
if (na > 1)
|
||||||
|
*ptr++ = cpu_to_fdt32(upper);
|
||||||
|
|
||||||
|
*ptr++ = cpu_to_fdt32(lower);
|
||||||
|
|
||||||
|
/* store one or two size cells */
|
||||||
|
lower = fdt_size_unpack(carveout.end - carveout.start + 1, &upper);
|
||||||
|
|
||||||
|
if (ns > 1)
|
||||||
|
*ptr++ = cpu_to_fdt32(upper);
|
||||||
|
|
||||||
|
*ptr++ = cpu_to_fdt32(lower);
|
||||||
|
|
||||||
|
offset = CHECK(fdt_add_subnode(fdt, 0, name + 1));
|
||||||
|
CHECK(fdt_setprop(fdt, offset, "reg", cells, (na + ns) * sizeof(*cells)));
|
||||||
|
|
||||||
|
return fdtdec_set_carveout(fdt, name, "memory-region", 0,
|
||||||
|
"framebuffer", &carveout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_fdt_carveout(void *fdt, uint32_t address_cells,
|
||||||
|
uint32_t size_cells)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_PHYS_64BIT
|
||||||
|
const char *name = "/display@1,80000000";
|
||||||
|
const struct fdt_memory expected = {
|
||||||
|
.start = 0x180000000,
|
||||||
|
.end = 0x18fffffff,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const char *name = "/display@80000000";
|
||||||
|
const struct fdt_memory expected = {
|
||||||
|
.start = 0x80000000,
|
||||||
|
.end = 0x8fffffff,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
struct fdt_memory carveout;
|
||||||
|
|
||||||
|
printf("carveout: %pap-%pap na=%u ns=%u: ", &expected.start,
|
||||||
|
&expected.end, address_cells, size_cells);
|
||||||
|
|
||||||
|
CHECK(fdtdec_get_carveout(fdt, name, "memory-region", 0, &carveout));
|
||||||
|
|
||||||
|
if ((carveout.start != expected.start) ||
|
||||||
|
(carveout.end != expected.end)) {
|
||||||
|
printf("carveout: %pap-%pap, expected %pap-%pap\n",
|
||||||
|
&carveout.start, &carveout.end,
|
||||||
|
&expected.start, &expected.end);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("pass\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_fdt_carveout(void *fdt, int size, uint32_t address_cells,
|
||||||
|
uint32_t size_cells)
|
||||||
|
{
|
||||||
|
fdt32_t na = cpu_to_fdt32(address_cells);
|
||||||
|
fdt32_t ns = cpu_to_fdt32(size_cells);
|
||||||
|
#if defined(DEBUG) && defined(CONFIG_SANDBOX)
|
||||||
|
char filename[512];
|
||||||
|
int fd;
|
||||||
|
#endif
|
||||||
|
int err;
|
||||||
|
|
||||||
|
CHECK(fdt_create(fdt, size));
|
||||||
|
CHECK(fdt_finish_reservemap(fdt));
|
||||||
|
CHECK(fdt_begin_node(fdt, ""));
|
||||||
|
CHECK(fdt_property(fdt, "#address-cells", &na, sizeof(na)));
|
||||||
|
CHECK(fdt_property(fdt, "#size-cells", &ns, sizeof(ns)));
|
||||||
|
CHECK(fdt_end_node(fdt));
|
||||||
|
CHECK(fdt_finish(fdt));
|
||||||
|
CHECK(fdt_pack(fdt));
|
||||||
|
|
||||||
|
CHECK(fdt_open_into(fdt, fdt, FDT_SIZE));
|
||||||
|
|
||||||
|
err = make_fdt_carveout_device(fdt, address_cells, size_cells);
|
||||||
|
|
||||||
|
#if defined(DEBUG) && defined(CONFIG_SANDBOX)
|
||||||
|
snprintf(filename, sizeof(filename), "/tmp/fdtdec-carveout-%u-%u.dtb",
|
||||||
|
address_cells, size_cells);
|
||||||
|
|
||||||
|
fd = os_open(filename, OS_O_CREAT | OS_O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
printf("could not open .dtb file to write\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_write(fd, fdt, size);
|
||||||
|
os_close(fd);
|
||||||
|
|
||||||
|
out:
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_carveout(void)
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
|
||||||
|
fdt = malloc(FDT_SIZE);
|
||||||
|
if (!fdt) {
|
||||||
|
printf("%s: out of memory\n", __func__);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_PHYS_64BIT
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), 0);
|
||||||
|
CHECKOK(check_fdt_carveout(fdt, 1, 1));
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), 0);
|
||||||
|
CHECKOK(check_fdt_carveout(fdt, 1, 2));
|
||||||
|
#else
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), -FDT_ERR_BADVALUE);
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), -FDT_ERR_BADVALUE);
|
||||||
|
#endif
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 1), 0);
|
||||||
|
CHECKOK(check_fdt_carveout(fdt, 2, 1));
|
||||||
|
CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 2), 0);
|
||||||
|
CHECKOK(check_fdt_carveout(fdt, 2, 2));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc,
|
static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||||
char * const argv[])
|
char * const argv[])
|
||||||
{
|
{
|
||||||
|
@ -200,6 +332,8 @@ static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||||
CHECKOK(run_test("2a 1a 0a", "a", " a"));
|
CHECKOK(run_test("2a 1a 0a", "a", " a"));
|
||||||
CHECKOK(run_test("0a 1a 2a", "a", "a"));
|
CHECKOK(run_test("0a 1a 2a", "a", "a"));
|
||||||
|
|
||||||
|
CHECKOK(check_carveout());
|
||||||
|
|
||||||
printf("Test passed\n");
|
printf("Test passed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,37 @@ uint32_t fdt_get_max_phandle(const void *fdt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
|
||||||
|
{
|
||||||
|
uint32_t max = 0;
|
||||||
|
int offset = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL);
|
||||||
|
if (offset < 0) {
|
||||||
|
if (offset == -FDT_ERR_NOTFOUND)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fdt_get_phandle(fdt, offset);
|
||||||
|
|
||||||
|
if (value > max)
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == FDT_MAX_PHANDLE)
|
||||||
|
return -FDT_ERR_NOPHANDLES;
|
||||||
|
|
||||||
|
if (phandle)
|
||||||
|
*phandle = max + 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||||
{
|
{
|
||||||
FDT_CHECK_HEADER(fdt);
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
|
@ -457,7 +457,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||||
return device_path_string(buf, end, ptr, field_width,
|
return device_path_string(buf, end, ptr, field_width,
|
||||||
precision, flags);
|
precision, flags);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CMD_NET
|
|
||||||
case 'a':
|
case 'a':
|
||||||
flags |= SPECIAL | ZEROPAD;
|
flags |= SPECIAL | ZEROPAD;
|
||||||
|
|
||||||
|
@ -469,6 +468,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_CMD_NET
|
||||||
case 'm':
|
case 'm':
|
||||||
flags |= SPECIAL;
|
flags |= SPECIAL;
|
||||||
/* Fallthrough */
|
/* Fallthrough */
|
||||||
|
|
|
@ -525,4 +525,5 @@ quiet_cmd_fdtgrep = FDTGREP $@
|
||||||
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
|
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
|
||||||
-n /chosen -n /config -O dtb | \
|
-n /chosen -n /config -O dtb | \
|
||||||
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
|
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
|
||||||
|
-P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl \
|
||||||
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
|
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
|
||||||
|
|
|
@ -115,6 +115,37 @@ uint32_t fdt_get_max_phandle(const void *fdt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
|
||||||
|
{
|
||||||
|
uint32_t max = 0;
|
||||||
|
int offset = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
offset = fdt_next_node(fdt, offset, NULL);
|
||||||
|
if (offset < 0) {
|
||||||
|
if (offset == -FDT_ERR_NOTFOUND)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fdt_get_phandle(fdt, offset);
|
||||||
|
|
||||||
|
if (value > max)
|
||||||
|
max = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == FDT_MAX_PHANDLE)
|
||||||
|
return -FDT_ERR_NOPHANDLES;
|
||||||
|
|
||||||
|
if (phandle)
|
||||||
|
*phandle = max + 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||||
{
|
{
|
||||||
FDT_CHECK_HEADER(fdt);
|
FDT_CHECK_HEADER(fdt);
|
||||||
|
|
|
@ -139,6 +139,10 @@
|
||||||
|
|
||||||
#define FDT_ERR_MAX 17
|
#define FDT_ERR_MAX 17
|
||||||
|
|
||||||
|
/* constants */
|
||||||
|
#define FDT_MAX_PHANDLE 0xfffffffe
|
||||||
|
/* Valid values for phandles range from 1 to 2^32-2. */
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* Low-level functions (you probably don't need these) */
|
/* Low-level functions (you probably don't need these) */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
@ -313,6 +317,21 @@ const char *fdt_string(const void *fdt, int stroffset);
|
||||||
*/
|
*/
|
||||||
uint32_t fdt_get_max_phandle(const void *fdt);
|
uint32_t fdt_get_max_phandle(const void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_generate_phandle - return a new, unused phandle for a device tree blob
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @phandle: return location for the new phandle
|
||||||
|
*
|
||||||
|
* Walks the device tree blob and looks for the highest phandle value. On
|
||||||
|
* success, the new, unused phandle value (one higher than the previously
|
||||||
|
* highest phandle value in the device tree blob) will be returned in the
|
||||||
|
* @phandle parameter.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success or a negative error-code on failure
|
||||||
|
*/
|
||||||
|
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
|
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
|
||||||
* @fdt: pointer to the device tree blob
|
* @fdt: pointer to the device tree blob
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
@ -67,6 +67,13 @@ static int dm_test_syscon_by_phandle(struct unit_test_state *uts)
|
||||||
ut_assert(!IS_ERR(map));
|
ut_assert(!IS_ERR(map));
|
||||||
ut_asserteq(4, map->range_count);
|
ut_asserteq(4, map->range_count);
|
||||||
|
|
||||||
|
ut_assertok_ptr(syscon_regmap_lookup_by_phandle(dev,
|
||||||
|
"third-syscon"));
|
||||||
|
map = syscon_regmap_lookup_by_phandle(dev, "third-syscon");
|
||||||
|
ut_assert(map);
|
||||||
|
ut_assert(!IS_ERR(map));
|
||||||
|
ut_asserteq(4, map->range_count);
|
||||||
|
|
||||||
ut_assert(IS_ERR(syscon_regmap_lookup_by_phandle(dev, "not-present")));
|
ut_assert(IS_ERR(syscon_regmap_lookup_by_phandle(dev, "not-present")));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -403,14 +403,21 @@ int main(int argc, char **argv)
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (params.fflag) {
|
||||||
* scan through mkimage registry for all supported image types
|
/*
|
||||||
* and verify the input image file header for match
|
* Verifies the header format based on the expected header for image
|
||||||
* Print the image information for matched image type
|
* type in tparams
|
||||||
* Returns the error code if not matched
|
*/
|
||||||
*/
|
retval = imagetool_verify_print_header_by_type(ptr, &sbuf,
|
||||||
retval = imagetool_verify_print_header_by_type(ptr, &sbuf,
|
tparams, ¶ms);
|
||||||
tparams, ¶ms);
|
} else {
|
||||||
|
/**
|
||||||
|
* When listing the image, we are not given the image type. Simply check all
|
||||||
|
* image types to find one that matches our header
|
||||||
|
*/
|
||||||
|
retval = imagetool_verify_print_header(ptr, &sbuf,
|
||||||
|
tparams, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
(void) munmap((void *)ptr, sbuf.st_size);
|
(void) munmap((void *)ptr, sbuf.st_size);
|
||||||
(void) close (ifd);
|
(void) close (ifd);
|
||||||
|
|
Loading…
Reference in a new issue