Prepare v2021.07-rc2

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEEGjx/cOCPqxcHgJu/FHw5/5Y0tywFAmCZn8UACgkQFHw5/5Y0
 tyw+GAwAsupHDouwir3d710jhMnFfJk6PBRkbwdeypBNA3zkQlQE2dbLZ9p4NBCv
 CYCS1LsmWxWIehrJu3qXiddl+k6pbQ5eI3g6sl/cus27q39hIo3B6/4prXs4alH3
 a6lf1x9HjzOM+TblIReI9Zqd6S7FzS1L/f3xeYMGn1+vNg1rQMtrzbOlnsCB5ESq
 XFcfzvTur+hBsCe+9D1g9RxxEpnn0QKN4/9qtzes2loX9QL2WcloOWIaz9ZBtc0P
 7me8Tj0AMaRiWbpyHzumYK/qENJu/Pb1DZeFLH5ETCNHKsg1znc/82MScuUYqxJe
 3CTRu2ws83Chc1hBlFbHVoC4M8PuMKewwfQlqtIKvNxOKYVqUwpIDvAB4aQRW7Dd
 s8dVIWqzWCQA34SoaX/pw0JCYznhs+ByM4+x1cxfXqAW0kV92E5Ytdf19DdbQSkx
 Vq93jFe13uv0MFNWTzguiXzV83i9L43P8hmvAQvzucTbb4C2KEzYvi/WIq/bjHPw
 zEdEAZ7v
 =aTso
 -----END PGP SIGNATURE-----

Merge tag 'v2021.07-rc2' into 2021.07+fslc

Prepare v2021.07-rc2

* tag 'v2021.07-rc2':
  Prepare v2021.07-rc2
  MAINTAINERS: Add an entry for VirtIO
  doc: develop: Convert README.virtio to reST
  x86: Correct regwidth prompt in cbsysinfo
  cmd/exception: support ebreak exception on RISC-V
  atcspi200: Add timeout mechanism in spi_xfer()
  riscv: cpu: fu740: clear feature disable CSR
  riscv: cpu: Add callback to init each core
  fdt_support.c: Allow late kernel cmdline modification
  cmd: gpt: Add option to write GPT partitions to environment variable
  sandbox: add test of CONFIG_ENV_IMPORT_FDT
  env: allow environment to be amended from control dtb
  test: Add gpio-sysinfo test
  sysinfo: Add gpio-sysinfo driver
  sysinfo: Require that sysinfo_detect be called before other methods
  sysinfo: Use global sysinfo IDs for existing sysinfo drivers
  dm: gpio: Fix gpio_get_list_count failing with livetree

Change-Id: I391f68fc2c7413372aa66f38805b8dca3cdb80c2
This commit is contained in:
Otavio Salvador 2021-05-11 18:10:42 -03:00
commit f0f7f23c85
41 changed files with 644 additions and 68 deletions

View File

@ -1171,6 +1171,18 @@ F: common/lcd*.c
F: include/lcd*.h
F: include/video*.h
VirtIO
M: Bin Meng <bmeng.cn@gmail.com>
S: Maintained
F: drivers/virtio/
F: cmd/virtio.c
F: include/config/virtio/
F: include/config/virtio.h
F: include/config/cmd/virtio.h
F: include/virtio*.h
F: test/dm/virtio.c
F: doc/develop/driver-model/virtio.rst
X86
M: Simon Glass <sjg@chromium.org>
M: Bin Meng <bmeng.cn@gmail.com>

View File

@ -3,7 +3,7 @@
VERSION = 2021
PATCHLEVEL = 07
SUBLEVEL =
EXTRAVERSION = -rc1
EXTRAVERSION = -rc2
NAME =
# *DOCUMENTATION*

View File

@ -140,3 +140,14 @@ int arch_early_init_r(void)
{
return riscv_cpu_probe();
}
/**
* harts_early_init() - A callback function called by start.S to configure
* feature settings of each hart.
*
* In a multi-core system, memory access shall be careful here, it shall
* take care of race conditions.
*/
__weak void harts_early_init(void)
{
}

View File

@ -6,6 +6,9 @@
#include <dm.h>
#include <log.h>
#include <asm/csr.h>
#define CSR_U74_FEATURE_DISABLE 0x7c1
int spl_soc_init(void)
{
@ -21,3 +24,15 @@ int spl_soc_init(void)
return 0;
}
void harts_early_init(void)
{
/*
* Feature Disable CSR
*
* Clear feature disable CSR to '0' to turn on all features for
* each core. This operation must be in M-mode.
*/
if (CONFIG_IS_ENABLED(RISCV_MMODE))
csr_write(CSR_U74_FEATURE_DISABLE, 0);
}

View File

@ -117,6 +117,10 @@ call_board_init_f_0:
mv sp, a0
#endif
/* Configure proprietary settings and customized CSRs of harts */
call_harts_early_init:
jal harts_early_init
#ifndef CONFIG_XIP
/*
* Pick hart to initialize global data and run U-Boot. The other harts

View File

@ -53,6 +53,13 @@
osd0 = "/osd";
};
config {
environment {
from_fdt = "yes";
fdt_env_path = "";
};
};
audio: audio-codec {
compatible = "sandbox,audio-codec";
#sound-dai-cells = <1>;
@ -1526,6 +1533,13 @@
compatible = "sandbox,sysinfo-sandbox";
};
sysinfo-gpio {
compatible = "gpio-sysinfo";
gpios = <&gpio_a 15>, <&gpio_a 16>, <&gpio_a 17>;
revisions = <19>, <5>;
names = "rev_a", "foo";
};
some_regmapped-bus {
#address-cells = <0x1>;
#size-cells = <0x1>;

View File

@ -350,17 +350,46 @@ static int get_gpt_info(struct blk_desc *dev_desc)
}
/* a wrapper to test get_gpt_info */
static int do_get_gpt_info(struct blk_desc *dev_desc)
static int do_get_gpt_info(struct blk_desc *dev_desc, char * const namestr)
{
int ret;
int numparts;
ret = get_gpt_info(dev_desc);
if (ret > 0) {
print_gpt_info();
numparts = get_gpt_info(dev_desc);
if (numparts > 0) {
if (namestr) {
char disk_guid[UUID_STR_LEN + 1];
char *partitions_list;
int partlistlen;
int ret = -1;
ret = get_disk_guid(dev_desc, disk_guid);
if (ret < 0)
return ret;
partlistlen = calc_parts_list_len(numparts);
partitions_list = malloc(partlistlen);
if (!partitions_list) {
del_gpt_info();
return -ENOMEM;
}
memset(partitions_list, '\0', partlistlen);
ret = create_gpt_partitions_list(numparts, disk_guid,
partitions_list);
if (ret < 0)
printf("Error: Could not create partition list string!\n");
else
env_set(namestr, partitions_list);
free(partitions_list);
} else {
print_gpt_info();
}
del_gpt_info();
return 0;
}
return ret;
return numparts;
}
#endif
@ -982,7 +1011,7 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
ret = do_disk_guid(blk_dev_desc, argv[4]);
#ifdef CONFIG_CMD_GPT_RENAME
} else if (strcmp(argv[1], "read") == 0) {
ret = do_get_gpt_info(blk_dev_desc);
ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL);
} else if ((strcmp(argv[1], "swap") == 0) ||
(strcmp(argv[1], "rename") == 0)) {
ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
@ -1028,8 +1057,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
" gpt guid mmc 0 varname\n"
#ifdef CONFIG_CMD_GPT_RENAME
"gpt partition renaming commands:\n"
" gpt read <interface> <dev>\n"
" gpt read <interface> <dev> [<varname>]\n"
" - read GPT into a data structure for manipulation\n"
" - read GPT partitions into environment variable\n"
" gpt swap <interface> <dev> <name1> <name2>\n"
" - change all partitions named name1 to name2\n"
" and vice-versa\n"

View File

@ -8,6 +8,13 @@
#include <common.h>
#include <command.h>
static int do_ebreak(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
asm volatile ("ebreak\n");
return CMD_RET_FAILURE;
}
static int do_unaligned(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@ -28,6 +35,8 @@ static int do_undefined(struct cmd_tbl *cmdtp, int flag, int argc,
}
static struct cmd_tbl cmd_sub[] = {
U_BOOT_CMD_MKENT(ebreak, CONFIG_SYS_MAXARGS, 1, do_ebreak,
"", ""),
U_BOOT_CMD_MKENT(unaligned, CONFIG_SYS_MAXARGS, 1, do_unaligned,
"", ""),
U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined,
@ -37,6 +46,7 @@ static struct cmd_tbl cmd_sub[] = {
static char exception_help_text[] =
"<ex>\n"
" The following exceptions are available:\n"
" ebreak - breakpoint\n"
" undefined - illegal instruction\n"
" unaligned - load address misaligned\n"
;

View File

@ -205,7 +205,7 @@ static void show_table(struct sysinfo_t *info, bool verbose)
print_hex(">type", ser->type);
print_addr(">base", ser->baseaddr);
print_dec(">baud", ser->baud);
print_hex(">baud", ser->regwidth);
print_hex(">regwidth", ser->regwidth);
print_dec(">input_hz", ser->input_hertz);
print_addr(">PCI addr", ser->uart_pci_addr);
}

View File

@ -459,6 +459,8 @@ static int initr_env(void)
else
env_set_default(NULL, 0);
env_import_fdt();
if (IS_ENABLED(CONFIG_OF_CONTROL))
env_set_hex("fdtcontroladdr",
(unsigned long)map_to_sysmem(gd->fdt_blob));

View File

@ -269,6 +269,15 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
return 0;
}
/**
* board_fdt_chosen_bootargs - boards may override this function to use
* alternative kernel command line arguments
*/
__weak char *board_fdt_chosen_bootargs(void)
{
return env_get("bootargs");
}
int fdt_chosen(void *fdt)
{
int nodeoffset;
@ -286,7 +295,8 @@ int fdt_chosen(void *fdt)
if (nodeoffset < 0)
return nodeoffset;
str = env_get("bootargs");
str = board_fdt_chosen_bootargs();
if (str) {
err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
strlen(str) + 1);

View File

@ -110,6 +110,10 @@ static int spl_fit_get_image_name(const struct spl_fit_info *ctx,
* no string in the property for this index. Check if the
* sysinfo-level code can supply one.
*/
rc = sysinfo_detect(sysinfo);
if (rc)
return rc;
rc = sysinfo_get_fit_loadable(sysinfo, index - i - 1, type,
&str);
if (rc && rc != -ENOENT)

View File

@ -91,6 +91,7 @@ CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_EXT4=y
CONFIG_ENV_EXT4_INTERFACE="host"
CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
CONFIG_ENV_IMPORT_FDT=y
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
@ -204,6 +205,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y

View File

@ -106,6 +106,7 @@ CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_EXT4=y
CONFIG_ENV_EXT4_INTERFACE="host"
CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
CONFIG_ENV_IMPORT_FDT=y
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
@ -245,6 +246,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y

View File

@ -178,6 +178,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y

View File

@ -197,6 +197,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_TIMER=y

View File

@ -199,6 +199,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_TIMER=y

View File

@ -237,6 +237,23 @@ doc/arch/index.rst:
=> gpt swap host 0 name othername
[ . . . ]
Modifying GPT partition layout from U-Boot:
===========================================
The entire GPT partition layout can be exported to an environment
variable and then modified enmasse. Users can change the partition
numbers, offsets, names and sizes. The resulting variable can used to
reformat the device. Here is an example of reading the GPT partitions
into a variable and then modifying them:
U-BOOT> gpt read mmc 0 current_partitions
U-BOOT> env edit current_partitions
edit: uuid_disk=[...];name=part1,start=0x4000,size=0x4000,uuid=[...];
name=part2,start=0xc000,size=0xc000,uuid=[...];[ . . . ]
U-BOOT> gpt write mmc 0 $current_partitions
U-BOOT> gpt verify mmc 0 $current_partitions
Partition type GUID:
====================

View File

@ -27,3 +27,4 @@ subsystems
soc-framework
spi-howto
usb-info
virtio

View File

@ -1,11 +1,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
.. SPDX-License-Identifier: GPL-2.0+
.. sectionauthor:: Bin Meng <bmeng.cn@gmail.com>
VirtIO Support
==============
This document describes the information about U-Boot support for VirtIO [1]
This document describes the information about U-Boot support for VirtIO_
devices, including supported boards, build instructions, driver details etc.
What's VirtIO?
@ -15,7 +14,7 @@ just the guest's device driver "knows" it is running in a virtual environment,
and cooperates with the hypervisor. This enables guests to get high performance
network and disk operations, and gives most of the performance benefits of
paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the
virtual environment are normally QEMU [2] targets like ARM, RISC-V and x86.
virtual environment are normally QEMU_ targets like ARM, RISC-V and x86.
Status
------
@ -49,6 +48,8 @@ Building U-Boot for pre-configured QEMU targets is no different from others.
For example, we can do the following with the CROSS_COMPILE environment
variable being properly set to a working toolchain for ARM:
.. code-block:: bash
$ make qemu_arm_defconfig
$ make
@ -56,11 +57,13 @@ You can even create a QEMU ARM target with VirtIO devices showing up on both
MMIO and PCI buses. In this case, you can enable the PCI transport driver
from 'make menuconfig':
Device Drivers --->
...
VirtIO Drivers --->
...
[*] PCI driver for virtio devices
.. code-block:: none
Device Drivers --->
...
VirtIO Drivers --->
...
[*] PCI driver for virtio devices
Other drivers are at the same location and can be tuned to suit the needs.
@ -74,6 +77,8 @@ Testing
The following QEMU command line is used to get U-Boot up and running with
VirtIO net and block devices on ARM.
.. code-block:: bash
$ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-device,netdev=net0 \
@ -82,6 +87,8 @@ VirtIO net and block devices on ARM.
On x86, command is slightly different to create PCI VirtIO devices.
.. code-block:: bash
$ qemu-system-i386 -nographic -bios u-boot.rom \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0 \
@ -93,6 +100,8 @@ parameters. It is also possible to specify both MMIO and PCI VirtIO devices.
For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO
and 2 on PCI bus.
.. code-block:: bash
$ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0 \
@ -104,6 +113,8 @@ and 2 on PCI bus.
By default QEMU creates VirtIO legacy devices by default. To create non-legacy
(aka modern) devices, pass additional device property/value pairs like below:
.. code-block:: bash
$ qemu-system-i386 -nographic -bios u-boot.rom \
-netdev tap,ifname=tap0,id=net0 \
-device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \
@ -112,6 +123,8 @@ By default QEMU creates VirtIO legacy devices by default. To create non-legacy
A 'virtio' command is provided in U-Boot shell.
.. code-block:: none
=> virtio
virtio - virtio block devices sub-system
@ -127,10 +140,14 @@ A 'virtio' command is provided in U-Boot shell.
To probe all the VirtIO devices, type:
.. code-block:: none
=> virtio scan
Then we can show the connected block device details by:
.. code-block:: none
=> virtio info
Device 0: QEMU VirtIO Block Device
Type: Hard Disk
@ -138,6 +155,8 @@ Then we can show the connected block device details by:
And list the directories and files on the disk by:
.. code-block:: none
=> ls virtio 0 /
<DIR> 4096 .
<DIR> 4096 ..
@ -167,6 +186,8 @@ Driver Internals
----------------
There are 3 level of drivers in the VirtIO driver family.
.. code-block:: none
+---------------------------------------+
| virtio device drivers |
| +-------------+ +------------+ |
@ -199,20 +220,26 @@ The transport drivers provide a set of ops (struct dm_virtio_ops) for the real
virtio device driver to call. These ops APIs's parameter is designed to remind
the caller to pass the correct 'struct udevice' id of the virtio device, eg:
int virtio_get_status(struct udevice *vdev, u8 *status)
.. code-block:: C
int virtio_get_status(struct udevice *vdev, u8 *status)
So the parameter 'vdev' indicates the device should be the real virtio device.
But we also have an API like:
struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
unsigned int vring_align,
struct udevice *udev)
.. code-block:: C
struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
unsigned int vring_align,
struct udevice *udev)
Here the parameter 'udev' indicates the device should be the transport device.
Similar naming is applied in other functions that are even not APIs, eg:
static int virtio_uclass_post_probe(struct udevice *udev)
static int virtio_uclass_child_pre_probe(struct udevice *vdev)
.. code-block:: C
static int virtio_uclass_post_probe(struct udevice *udev)
static int virtio_uclass_child_pre_probe(struct udevice *vdev)
So it's easy to tell which device these functions are operating on.
@ -223,20 +250,29 @@ ID 2) are supported. If you want to develop new driver for new devices,
please follow the guideline below.
1. add new device ID in virtio.h
#define VIRTIO_ID_XXX X
.. code-block:: C
#define VIRTIO_ID_XXX X
2. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1
3. add new driver name string in virtio.h
#define VIRTIO_XXX_DRV_NAME "virtio-xxx"
.. code-block:: C
#define VIRTIO_XXX_DRV_NAME "virtio-xxx"
4. create a new driver with name set to the name string above
U_BOOT_DRIVER(virtio_xxx) = {
.name = VIRTIO_XXX_DRV_NAME,
...
.remove = virtio_reset,
.flags = DM_FLAG_ACTIVE_DMA,
}
.. code-block:: C
U_BOOT_DRIVER(virtio_xxx) = {
.name = VIRTIO_XXX_DRV_NAME,
...
.remove = virtio_reset,
.flags = DM_FLAG_ACTIVE_DMA,
}
Note the driver needs to provide the remove method and normally this can be
hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA
@ -247,7 +283,5 @@ for the remove method to be called before jumping to OS.
6. do funny stuff with the driver
References
----------
[1] http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
[2] https://www.qemu.org
.. _VirtIO: http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
.. _QEMU: https://www.qemu.org

View File

@ -0,0 +1,37 @@
GPIO-based Sysinfo device
This binding describes several GPIOs which specify a board revision. Each GPIO
forms a digit in a ternary revision number. This revision is then mapped to a
name using the revisions and names properties.
Each GPIO may be floating, pulled-up, or pulled-down, mapping to digits 2, 1,
and 0, respectively. The first GPIO forms the least-significant digit of the
revision. For example, consider the property
gpios = <&gpio 0>, <&gpio 1>, <&gpio 2>;
If GPIO 0 is pulled-up, GPIO 1 is pulled-down, and GPIO 2 is floating, then the
revision would be
0t201 = 2*9 + 0*3 + 1*3 = 19
If instead GPIO 0 is floating, GPIO 1 is pulled-up, and GPIO 2 is pulled-down,
then the revision would be
0t012 = 0*9 + 1*3 + 2*1 = 5
Required properties:
- compatible: should be "gpio-sysinfo".
- gpios: should be a list of gpios forming the revision number,
least-significant-digit first
- revisions: a list of known revisions; any revisions not present will have the
name "unknown"
- names: the name of each revision in revisions
Example:
sysinfo {
compatible = "gpio-sysinfo";
gpios = <&gpio_a 15>, <&gpio_a 16>, <&gpio_a 17>;
revisions = <19>, <5>;
names = "rev_a", "foo";
};

View File

@ -31,6 +31,9 @@ type
**RISC-V:**
ebreak
breakpoint exception
unaligned
load address misaligned

View File

@ -1215,9 +1215,9 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name)
{
int ret;
ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0, -1,
NULL);
if (ret) {
ret = dev_count_phandle_with_args(dev, list_name, "#gpio-cells",
-ENOENT);
if (ret < 0) {
debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
__func__, dev->name, list_name, ret);
}

View File

@ -201,7 +201,7 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
size_t cmd_len = ns->cmd_len;
unsigned long data_len = bitlen / 8;
int rf_cnt;
int ret = 0;
int ret = 0, timeout = 0;
max_tran_len = ns->max_transfer_length;
switch (flags) {
@ -243,11 +243,12 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
ns->tran_len = tran_len;
num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE);
num_bytes = (tran_len) % CHUNK_SIZE;
timeout = SPI_TIMEOUT;
if(num_bytes == 0)
num_bytes = CHUNK_SIZE;
__atcspi200_spi_start(ns);
while (num_blks) {
while (num_blks && (timeout--)) {
event = in_le32(&ns->regs->status);
if ((event & TXEPTY) && (data_out)) {
__nspi_espi_tx(ns, dout);
@ -269,6 +270,11 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
din = (unsigned char *)din + rx_bytes;
}
}
if (!timeout) {
debug("spi_xfer: %s() timeout\n", __func__);
break;
}
}
data_len -= tran_len;

View File

@ -30,4 +30,12 @@ config SYSINFO_SMBIOS
one which provides a way to specify this SMBIOS information in the
devicetree, without needing any board-specific functionality.
config SYSINFO_GPIO
bool "Enable gpio sysinfo driver"
help
Support querying gpios to determine board revision. This uses gpios to
form a ternary number (when they are pulled-up, -down, or floating).
This ternary number is then mapped to a board revision name using
device tree properties.
endif

View File

@ -4,5 +4,6 @@
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
obj-y += sysinfo-uclass.o
obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o
obj-$(CONFIG_SYSINFO_GPIO) += gpio.o
obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o
obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o

View File

@ -5,10 +5,12 @@
*
*/
#include <sysinfo.h>
enum {
BOARD_MULTICHANNEL,
BOARD_VARIANT,
BOARD_HWVERSION,
BOARD_HWVERSION = SYSINFO_ID_BOARD_MODEL,
BOARD_MULTICHANNEL = SYSINFO_ID_USER,
BOARD_VARIANT
};
enum {

141
drivers/sysinfo/gpio.c Normal file
View File

@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
*/
#include <common.h>
#include <dm.h>
#include <log.h>
#include <sysinfo.h>
#include <asm/gpio.h>
#include <dm/device_compat.h>
/**
* struct sysinfo_gpio_priv - GPIO sysinfo private data
* @gpios: List of GPIOs used to detect the revision
* @gpio_num: The number of GPIOs in @gpios
* @revision: The revision as detected from the GPIOs.
*/
struct sysinfo_gpio_priv {
struct gpio_desc *gpios;
int gpio_num, revision;
};
static int sysinfo_gpio_detect(struct udevice *dev)
{
int ret;
struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
ret = dm_gpio_get_values_as_int_base3(priv->gpios, priv->gpio_num);
if (ret < 0)
return ret;
priv->revision = ret;
return 0;
}
static int sysinfo_gpio_get_int(struct udevice *dev, int id, int *val)
{
struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
switch (id) {
case SYSINFO_ID_BOARD_MODEL:
*val = priv->revision;
return 0;
default:
return -EINVAL;
};
}
static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char *val)
{
struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
switch (id) {
case SYSINFO_ID_BOARD_MODEL: {
const char *name = NULL;
int i, ret;
u32 revision;
for (i = 0; i < priv->gpio_num; i++) {
ret = dev_read_u32_index(dev, "revisions", i,
&revision);
if (ret) {
if (ret != -EOVERFLOW)
return ret;
break;
}
if (revision == priv->revision) {
ret = dev_read_string_index(dev, "names", i,
&name);
if (ret < 0)
return ret;
break;
}
}
if (!name)
name = "unknown";
strncpy(val, name, size);
val[size - 1] = '\0';
return 0;
} default:
return -EINVAL;
};
}
static const struct sysinfo_ops sysinfo_gpio_ops = {
.detect = sysinfo_gpio_detect,
.get_int = sysinfo_gpio_get_int,
.get_str = sysinfo_gpio_get_str,
};
static int sysinfo_gpio_probe(struct udevice *dev)
{
int ret;
struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
priv->gpio_num = gpio_get_list_count(dev, "gpios");
if (priv->gpio_num < 0) {
dev_err(dev, "could not get gpios length (err = %d)\n",
priv->gpio_num);
return priv->gpio_num;
}
priv->gpios = calloc(priv->gpio_num, sizeof(*priv->gpios));
if (!priv->gpios) {
dev_err(dev, "could not allocate memory for %d gpios\n",
priv->gpio_num);
return -ENOMEM;
}
ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
priv->gpio_num, GPIOD_IS_IN);
if (ret != priv->gpio_num) {
dev_err(dev, "could not get gpios (err = %d)\n",
priv->gpio_num);
return ret;
}
if (!dev_read_bool(dev, "revisions") || !dev_read_bool(dev, "names")) {
dev_err(dev, "revisions or names properties missing\n");
return -ENOENT;
}
return 0;
}
static const struct udevice_id sysinfo_gpio_ids[] = {
{ .compatible = "gpio-sysinfo" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(sysinfo_gpio) = {
.name = "sysinfo_gpio",
.id = UCLASS_SYSINFO,
.of_match = sysinfo_gpio_ids,
.ops = &sysinfo_gpio_ops,
.priv_auto = sizeof(struct sysinfo_gpio_priv),
.probe = sysinfo_gpio_probe,
};

View File

@ -5,7 +5,7 @@
*/
enum {
BOOL_CALLED_DETECT,
BOOL_CALLED_DETECT = SYSINFO_ID_USER,
INT_TEST1,
INT_TEST2,
STR_VACATIONSPOT,

View File

@ -8,6 +8,10 @@
#include <dm.h>
#include <sysinfo.h>
struct sysinfo_priv {
bool detected;
};
int sysinfo_get(struct udevice **devp)
{
return uclass_first_device_err(UCLASS_SYSINFO, devp);
@ -15,19 +19,29 @@ int sysinfo_get(struct udevice **devp)
int sysinfo_detect(struct udevice *dev)
{
int ret;
struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!ops->detect)
return -ENOSYS;
return ops->detect(dev);
ret = ops->detect(dev);
if (!ret)
priv->detected = true;
return ret;
}
int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
const char **strp)
{
struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!priv->detected)
return -EPERM;
if (!ops->get_fit_loadable)
return -ENOSYS;
@ -36,8 +50,12 @@ int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
int sysinfo_get_bool(struct udevice *dev, int id, bool *val)
{
struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!priv->detected)
return -EPERM;
if (!ops->get_bool)
return -ENOSYS;
@ -46,8 +64,12 @@ int sysinfo_get_bool(struct udevice *dev, int id, bool *val)
int sysinfo_get_int(struct udevice *dev, int id, int *val)
{
struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!priv->detected)
return -EPERM;
if (!ops->get_int)
return -ENOSYS;
@ -56,8 +78,12 @@ int sysinfo_get_int(struct udevice *dev, int id, int *val)
int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val)
{
struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!priv->detected)
return -EPERM;
if (!ops->get_str)
return -ENOSYS;
@ -68,4 +94,5 @@ UCLASS_DRIVER(sysinfo) = {
.id = UCLASS_SYSINFO,
.name = "sysinfo",
.post_bind = dm_scan_fdt_dev,
.per_device_auto = sizeof(bool),
};

18
env/Kconfig vendored
View File

@ -670,6 +670,24 @@ config DELAY_ENVIRONMENT
later by U-Boot code. With CONFIG_OF_CONTROL this is instead
controlled by the value of /config/load-environment.
config ENV_IMPORT_FDT
bool "Amend environment by FDT properties"
depends on OF_CONTROL
help
If selected, after the environment has been loaded from its
persistent location, the "env_fdt_path" variable is looked
up and used as a path to a node in the control DTB. The
property/value pairs in that node is then used to update the
run-time environment. This can be useful to use the same
U-Boot binary with different board variants.
config ENV_FDT_PATH
string "Default value for env_fdt_path variable"
depends on ENV_IMPORT_FDT
default "/config/environment"
help
The initial value of the env_fdt_path variable.
config ENV_APPEND
bool "Always append the environment with new data"
default n

30
env/common.c vendored
View File

@ -20,6 +20,7 @@
#include <errno.h>
#include <malloc.h>
#include <u-boot/crc.h>
#include <dm/ofnode.h>
DECLARE_GLOBAL_DATA_PTR;
@ -334,3 +335,32 @@ int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf,
return found;
}
#endif
#ifdef CONFIG_ENV_IMPORT_FDT
void env_import_fdt(void)
{
const char *path;
struct ofprop prop;
ofnode node;
int res;
path = env_get("env_fdt_path");
if (!path || !path[0])
return;
node = ofnode_path(path);
if (!ofnode_valid(node)) {
printf("Warning: device tree node '%s' not found\n", path);
return;
}
for (res = ofnode_get_first_property(node, &prop);
!res;
res = ofnode_get_next_property(&prop)) {
const char *name, *val;
val = ofnode_get_property_by_prop(&prop, &name, NULL);
env_set(name, val);
}
}
#endif

View File

@ -375,4 +375,19 @@ int env_get_char(int index);
* This is used for those unfortunate archs with crappy toolchains
*/
void env_reloc(void);
/**
* env_import_fdt() - Import environment values from device tree blob
*
* This uses the value of the environment variable "env_fdt_path" as a
* path to an fdt node, whose property/value pairs are added to the
* environment.
*/
#ifdef CONFIG_ENV_IMPORT_FDT
void env_import_fdt(void);
#else
static inline void env_import_fdt(void) {}
#endif
#endif

View File

@ -103,6 +103,9 @@ const uchar default_environment[] = {
#ifdef CONFIG_SYS_SOC
"soc=" CONFIG_SYS_SOC "\0"
#endif
#ifdef CONFIG_ENV_IMPORT_FDT
"env_fdt_path=" CONFIG_ENV_FDT_PATH "\0"
#endif
#endif
#if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
"bootlimit=" __stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0"

View File

@ -185,6 +185,16 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
*/
int ft_board_setup(void *blob, struct bd_info *bd);
/**
* board_fdt_chosen_bootargs() - Arbitrarily amend fdt kernel command line
*
* This is used for late modification of kernel command line arguments just
* before they are added into the /chosen node in flat device tree.
*
* @return: pointer to kernel command line arguments in memory
*/
char *board_fdt_chosen_bootargs(void);
/*
* The keystone2 SOC requires all 32 bit aliased addresses to be converted
* to their 36 physical format. This has to happen after all fdt nodes

View File

@ -60,7 +60,8 @@ struct sysinfo_ops {
* This operation might take a long time (e.g. read from EEPROM,
* check the presence of a device on a bus etc.), hence this is not
* done in the probe() method, but later during operation in this
* dedicated method.
* dedicated method. This method will be called before any other
* methods.
*
* Return: 0 if OK, -ve on error.
*/
@ -104,7 +105,7 @@ struct sysinfo_ops {
* get_fit_loadable - Get the name of an image to load from FIT
* This function can be used to provide the image names based on runtime
* detection. A classic use-case would when DTBOs are used to describe
* additionnal daughter cards.
* additional daughter cards.
*
* @dev: The sysinfo instance to gather the data.
* @index: Index of the image. Starts at 0 and gets incremented
@ -127,6 +128,9 @@ struct sysinfo_ops {
*
* @dev: The device containing the information
*
* This function must be called before any other accessor function for this
* device.
*
* Return: 0 if OK, -ve on error.
*/
int sysinfo_detect(struct udevice *dev);
@ -138,7 +142,8 @@ int sysinfo_detect(struct udevice *dev);
* @id: A unique identifier for the bool value to be read.
* @val: Pointer to a buffer that receives the value read.
*
* Return: 0 if OK, -ve on error.
* Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
* error.
*/
int sysinfo_get_bool(struct udevice *dev, int id, bool *val);
@ -149,7 +154,8 @@ int sysinfo_get_bool(struct udevice *dev, int id, bool *val);
* @id: A unique identifier for the int value to be read.
* @val: Pointer to a buffer that receives the value read.
*
* Return: 0 if OK, -ve on error.
* Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
* error.
*/
int sysinfo_get_int(struct udevice *dev, int id, int *val);
@ -161,7 +167,8 @@ int sysinfo_get_int(struct udevice *dev, int id, int *val);
* @size: The size of the buffer to receive the string data.
* @val: Pointer to a buffer that receives the value read.
*
* Return: 0 if OK, -ve on error.
* Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
* error.
*/
int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val);
@ -173,7 +180,8 @@ int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val);
* function that returns the unique device. This is especially useful for use
* in sysinfo files.
*
* Return: 0 if OK, -ve on error.
* Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
* error.
*/
int sysinfo_get(struct udevice **devp);
@ -181,7 +189,7 @@ int sysinfo_get(struct udevice **devp);
* sysinfo_get_fit_loadable - Get the name of an image to load from FIT
* This function can be used to provide the image names based on runtime
* detection. A classic use-case would when DTBOs are used to describe
* additionnal daughter cards.
* additional daughter cards.
*
* @dev: The sysinfo instance to gather the data.
* @index: Index of the image. Starts at 0 and gets incremented
@ -190,8 +198,8 @@ int sysinfo_get(struct udevice **devp);
* @strp: A pointer to string. Untouched if the function fails
*
*
* Return: 0 if OK, -ENOENT if no loadable is available else -ve on
* error.
* Return: 0 if OK, -EPERM if called before sysinfo_detect(), -ENOENT if no
* loadable is available else -ve on error.
*/
int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
const char **strp);

View File

@ -96,6 +96,7 @@ obj-$(CONFIG_SPMI) += spmi.o
obj-y += syscon.o
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
obj-$(CONFIG_SYSINFO) += sysinfo.o
obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_USB) += usb.o

69
test/dm/sysinfo-gpio.c Normal file
View File

@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
*/
#include <common.h>
#include <dm.h>
#include <log.h>
#include <sysinfo.h>
#include <asm/gpio.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
static int dm_test_sysinfo_gpio(struct unit_test_state *uts)
{
char buf[64];
int val;
struct udevice *sysinfo, *gpio;
ut_assertok(uclass_get_device_by_name(UCLASS_SYSINFO, "sysinfo-gpio",
&sysinfo));
ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
/*
* Set up pins: pull-up (1), pull-down (0) and floating (2). This should
* result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19
*/
sandbox_gpio_set_flags(gpio, 15, GPIOD_EXT_PULL_UP);
sandbox_gpio_set_flags(gpio, 16, GPIOD_EXT_PULL_DOWN);
sandbox_gpio_set_flags(gpio, 17, 0);
ut_assertok(sysinfo_detect(sysinfo));
ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
ut_asserteq(19, val);
ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
buf));
ut_asserteq_str("rev_a", buf);
/*
* Set up pins: floating (2), pull-up (1) and pull-down (0). This should
* result in digits 0 1 2, i.e. 1 * 3 + 2 = 5
*/
sandbox_gpio_set_flags(gpio, 15, 0);
sandbox_gpio_set_flags(gpio, 16, GPIOD_EXT_PULL_UP);
sandbox_gpio_set_flags(gpio, 17, GPIOD_EXT_PULL_DOWN);
ut_assertok(sysinfo_detect(sysinfo));
ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
ut_asserteq(5, val);
ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
buf));
ut_asserteq_str("foo", buf);
/*
* Set up pins: floating (2), pull-up (1) and pull-down (0). This should
* result in digits 1 2 0, i.e. 1 * 9 + 2 * 3 = 15
*/
sandbox_gpio_set_flags(gpio, 15, GPIOD_EXT_PULL_DOWN);
sandbox_gpio_set_flags(gpio, 16, 0);
sandbox_gpio_set_flags(gpio, 17, GPIOD_EXT_PULL_UP);
ut_assertok(sysinfo_detect(sysinfo));
ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
ut_asserteq(15, val);
ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
buf));
ut_asserteq_str("unknown", buf);
return 0;
}
DM_TEST(dm_test_sysinfo_gpio, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

View File

@ -17,40 +17,45 @@
static int dm_test_sysinfo(struct unit_test_state *uts)
{
struct udevice *sysinfo;
bool called_detect;
bool called_detect = false;
char str[64];
int i;
ut_assertok(sysinfo_get(&sysinfo));
ut_assert(sysinfo);
sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, &called_detect);
ut_asserteq(-EPERM, sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT,
&called_detect));
ut_assert(!called_detect);
sysinfo_detect(sysinfo);
sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, &called_detect);
ut_assertok(sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT,
&called_detect));
ut_assert(called_detect);
sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
str));
ut_assertok(strcmp(str, "R'lyeh"));
sysinfo_get_int(sysinfo, INT_TEST1, &i);
ut_assertok(sysinfo_get_int(sysinfo, INT_TEST1, &i));
ut_asserteq(0, i);
sysinfo_get_int(sysinfo, INT_TEST2, &i);
ut_assertok(sysinfo_get_int(sysinfo, INT_TEST2, &i));
ut_asserteq(100, i);
sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
str));
ut_assertok(strcmp(str, "Carcosa"));
sysinfo_get_int(sysinfo, INT_TEST1, &i);
ut_assertok(sysinfo_get_int(sysinfo, INT_TEST1, &i));
ut_asserteq(1, i);
sysinfo_get_int(sysinfo, INT_TEST2, &i);
ut_assertok(sysinfo_get_int(sysinfo, INT_TEST2, &i));
ut_asserteq(99, i);
sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
str));
ut_assertok(strcmp(str, "Yuggoth"));
return 0;

1
test/env/Makefile vendored
View File

@ -5,3 +5,4 @@
obj-y += cmd_ut_env.o
obj-y += attr.o
obj-y += hashtable.o
obj-$(CONFIG_ENV_IMPORT_FDT) += fdt.o

20
test/env/fdt.c vendored Normal file
View File

@ -0,0 +1,20 @@
#include <common.h>
#include <command.h>
#include <env_attr.h>
#include <test/env.h>
#include <test/ut.h>
static int env_test_fdt_import(struct unit_test_state *uts)
{
const char *val;
val = env_get("from_fdt");
ut_assertnonnull(val);
ut_asserteq_str("yes", val);
val = env_get("fdt_env_path");
ut_assertnull(val);
return 0;
}
ENV_TEST(env_test_fdt_import, 0);