SPI flash documentation and tidy-ups

Various driver model enhancements
 Fix up some missing unit tests with pytest
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmGkFroRHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIrea7QQgAjSlchhsXmUoBjl8rmpBJryTzeipdp/bw
 FOc5xOu4y9PJCXrO5EMk0qAngUpmzZWdMV67iYnDT8b4CJeuFili9tbuvkVNGeXs
 xpx0VVAb443XdY4QLFHl0w/WrUp6yPTTaT8GI3jpUoHXiWelu8rn8azTjZFZhgtz
 O/7ZfKJy2bWKICAoi9KP17IRnK9IqORgIh1ADJPkmaBCBeOE0TqVpUlSdVwSkJHR
 MtthfqQ57O6r+zZjw9wG/V6TRYjvQRcXDrOMk7myYaK4Hc8s9WHjdgDDmxvNX29J
 Ziix00Lv8EA3sT+bwE88XQYh6NYWcsAJbi676juO4FF871+qJsiTOg==
 =dyds
 -----END PGP SIGNATURE-----

Merge tag 'dm-pull-28nov21' of https://source.denx.de/u-boot/custodians/u-boot-dm into next

SPI flash documentation and tidy-ups
Various driver model enhancements
Fix up some missing unit tests with pytest
This commit is contained in:
Tom Rini 2021-11-28 20:38:01 -05:00
commit c087b5ad97
32 changed files with 670 additions and 69 deletions

View File

@ -211,6 +211,16 @@ int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
return 0;
}
int os_unmap(void *buf, int size)
{
if (munmap(buf, size)) {
printf("Can't unmap %p %x\n", buf, size);
return -EIO;
}
return 0;
}
/* Restore tty state when we exit */
static struct termios orig_term;
static bool term_setup;

View File

@ -207,6 +207,7 @@
test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
test5-gpios = <&gpio_a 19>;
bool-value;
int-value = <1234>;
uint-value = <(-1234)>;
int64-value = /bits/ 64 <0x1111222233334444>;

View File

@ -247,9 +247,9 @@ static int do_verify_mbr(struct blk_desc *dev, const char *str)
if (part_get_info(dev, i + 1, &p))
goto fail;
if ((partitions[i].size && p.size < partitions[i].size) ||
(partitions[i].start && p.start < partitions[i].start) ||
(p.sys_ind != partitions[i].sys_ind))
if ((partitions[i].size && p.size != partitions[i].size) ||
(partitions[i].start && p.start != partitions[i].start) ||
p.sys_ind != partitions[i].sys_ind)
goto fail;
}
ret = 0;

View File

@ -384,7 +384,6 @@ static int do_spi_protect(int argc, char *const argv[])
return ret == 0 ? 0 : 1;
}
#ifdef CONFIG_CMD_SF_TEST
enum {
STAGE_ERASE,
STAGE_CHECK,
@ -394,7 +393,7 @@ enum {
STAGE_COUNT,
};
static char *stage_name[STAGE_COUNT] = {
static const char *stage_name[STAGE_COUNT] = {
"erase",
"check",
"write",
@ -548,7 +547,6 @@ static int do_spi_flash_test(int argc, char *const argv[])
return 0;
}
#endif /* CONFIG_CMD_SF_TEST */
static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
@ -582,10 +580,8 @@ static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
ret = do_spi_flash_erase(argc, argv);
else if (strcmp(cmd, "protect") == 0)
ret = do_spi_protect(argc, argv);
#ifdef CONFIG_CMD_SF_TEST
else if (!strcmp(cmd, "test"))
else if (IS_ENABLED(CONFIG_CMD_SF_TEST) && !strcmp(cmd, "test"))
ret = do_spi_flash_test(argc, argv);
#endif
else
ret = -1;
@ -597,16 +593,8 @@ usage:
return CMD_RET_USAGE;
}
#ifdef CONFIG_CMD_SF_TEST
#define SF_TEST_HELP "\nsf test offset len " \
"- run a very basic destructive test"
#else
#define SF_TEST_HELP
#endif
U_BOOT_CMD(
sf, 5, 1, do_spi_flash,
"SPI flash sub-system",
#ifdef CONFIG_SYS_LONGHELP
static const char long_help[] =
"probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n"
" and chip select\n"
"sf read addr offset|partition len - read `len' bytes starting at\n"
@ -622,6 +610,14 @@ U_BOOT_CMD(
" at `addr' to flash at `offset'\n"
" or to start of mtd `partition'\n"
"sf protect lock/unlock sector len - protect/unprotect 'len' bytes starting\n"
" at address 'sector'\n"
SF_TEST_HELP
" at address 'sector'"
#ifdef CONFIG_CMD_SF_TEST
"\nsf test offset len - run a very basic destructive test"
#endif
#endif /* CONFIG_SYS_LONGHELP */
;
U_BOOT_CMD(
sf, 5, 1, do_spi_flash,
"SPI flash sub-system", long_help
);

View File

@ -32,6 +32,16 @@ config CONSOLE_RECORD_OUT_SIZE
more data will be recorded until some is removed. The buffer is
allocated immediately after the malloc() region is ready.
config CONSOLE_RECORD_OUT_SIZE_F
hex "Output buffer size before relocation"
depends on CONSOLE_RECORD
default 0x400 if CONSOLE_RECORD
help
Set the size of the console output buffer before relocation. When
this fills up, no more data will be recorded until some is removed.
The buffer is allocated immediately after the early malloc() region is
ready.
config CONSOLE_RECORD_IN_SIZE
hex "Input buffer size"
depends on CONSOLE_RECORD

View File

@ -735,7 +735,9 @@ int console_record_init(void)
int ret;
ret = membuff_new((struct membuff *)&gd->console_out,
CONFIG_CONSOLE_RECORD_OUT_SIZE);
gd->flags & GD_FLG_RELOC ?
CONFIG_CONSOLE_RECORD_OUT_SIZE :
CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
if (ret)
return ret;
ret = membuff_new((struct membuff *)&gd->console_in,

View File

@ -203,6 +203,7 @@ CONFIG_RSA_VERIFY_WITH_PKEY=y
CONFIG_TPM=y
CONFIG_LZ4=y
CONFIG_ERRNO_STR=y
CONFIG_HEXDUMP=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y

View File

@ -459,10 +459,12 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
ext = &p[i];
}
if (i >= 4 && !ext) {
printf("%s: extended partition is needed for more than 4 partitions\n",
__func__);
return -1;
if (count < 4)
return 0;
if (!ext) {
log_err("extended partition is needed for more than 4 partitions\n");
return -EINVAL;
}
/* calculate extended volumes start and size if needed */

View File

@ -0,0 +1,18 @@
Sandbox MMC
===========
Required properties:
- compatible : "sandbox,mmc"
Optional properties:
- filename : Name of backing file, if any. This is mapped into the MMC device
so can be used to provide a filesystem or other test data
Example
-------
mmc2 {
compatible = "sandbox,mmc";
non-removable;
};

View File

@ -45,6 +45,7 @@ Shell commands
qfw
reset
sbi
sf
scp03
setexpr
size

245
doc/usage/sf.rst Normal file
View File

@ -0,0 +1,245 @@
.. SPDX-License-Identifier: GPL-2.0+:
sf command
==========
Synopis
-------
::
sf probe [[[<bus>:]<cs>] [<hz> [<mode>]]]
sf read <addr> <offset>|<partition> <len>
sf write <addr> <offset>|<partition> <len>
sf erase <offset>|<partition> <len>
sf update <addr> <offset>|<partition> <len>
sf protect lock|unlock <sector> <len>
sf test <offset>|<partition> <len>
Description
-----------
The *sf* command is used to access SPI flash, supporting read/write/erase and
a few other functions.
Probe
-----
The flash must first be probed with *sf probe* before any of the other
subcommands can be used. All of the parameters are optional:
bus
SPI bus number containing the SPI-flash chip, e.g. 0. If you don't know
the number, you can use 'dm uclass' to see all the spi devices,
and check the value for 'seq' for each one (here 0 and 2)::
uclass 89: spi
0 spi@0 @ 05484960, seq 0
1 spi@1 @ 05484b40, seq 2
cs
SPI chip-select to use for the chip. This is often 0 and can be omitted,
but in some cases multiple slaves are attached to a SPI controller,
selected by a chip-select line for each one.
hz
Speed of the SPI bus in hertz. This normally defaults to 100000, i.e.
100KHz, which is very slow. Note that if the device exists in the
device tree, there might be a speed provided there, in which case this
setting is ignored.
mode
SPI mode to use:
===== ================
Mode Meaning
===== ================
0 CPOL=0, CPHA=0
1 CPOL=0, CPHA=1
2 CPOL=1, CPHA=0
3 CPOL=1, CPHA=1
===== ================
Clock phase (CPHA) 0 means that data is transferred (sampled) on the
first clock edge; 1 means the second.
Clock polarity (CPOL) controls the idle state of the clock, 0 for low,
1 for high.
The active state is the opposite of idle.
You may find this `SPI documentation`_ useful.
Parameters for other subcommands (described below) are as follows:
addr
Memory address to start transfer
offset
Flash offset to start transfer
partition
If the parameter is not numeric, it is assumed to be a partition
description in the format <dev_type><dev_num>,<part_num> which is not
covered here. This requires CONFIG_CMD_MTDPARTS.
len
Number of bytes to transfer
Read
~~~~
Use *sf read* to read from SPI flash to memory. The read will fail if an
attempt is made to read past the end of the flash.
Write
~~~~~
Use *sf write* to write from memory to SPI flash. The SPI flash should be
erased first, since otherwise the result is undefined.
The write will fail if an attempt is made to read past the end of the flash.
Erase
~~~~~
Use *sf erase* to erase a region of SPI flash. The erase will fail if any part
of the region to be erased is protected or lies past the end of the flash. It
may also fail if the start offset or length are not aligned to an erase region
(e.g. 256 bytes).
Update
~~~~~~
Use *sf update* to automatically erase and update a region of SPI flash from
memory. This works a sector at a time (typical 4KB or 64KB). For each
sector it first checks if the sector already has the right data. If so it is
skipped. If not, the sector is erased and the new data written. Note that if
the length is not a multiple of the erase size, the space after the data in
the last sector will be erased. If the offset does not start at the beginning
of an erase block, the operation will fail.
Speed statistics are shown including the number of bytes that were already
correct.
Protect
~~~~~~~
SPI-flash chips often have a protection feature where the chip is split up into
regions which can be locked or unlocked. With *sf protect* it is possible to
change these settings, if supported by the driver.
lock|unlock
Selects whether to lock or unlock the sectors
<sector>
Start sector number to lock/unlock. This may be the byte offset or some
other value, depending on the chip.
<len>
Number of bytes to lock/unlock
Test
~~~~
A convenient and fast *sf test* subcommand provides a way to check that SPI
flash is working as expected. This works in four stages:
* erase - erases the entire region
* check - checks that the region is erased
* write - writes a test pattern to the region, consisting of the U-Boot code
* read - reads back the test pattern to check that it was written correctly
Memory is allocated for two buffers, each <len> bytes in size. At typical
size is 64KB to 1MB. The offset and size must be aligned to an erase boundary.
Note that this test will fail if any part of the SPI flash is write-protected.
Examples
--------
This first example uses sandbox::
=> sf probe
SF: Detected m25p16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB
=> sf read 1000 1100 80000
device 0 offset 0x1100, size 0x80000
SF: 524288 bytes @ 0x1100 Read: OK
=> md 1000
00001000: edfe0dd0 f33a0000 78000000 84250000 ......:....x..%.
00001010: 28000000 11000000 10000000 00000000 ...(............
00001020: 6f050000 0c250000 00000000 00000000 ...o..%.........
00001030: 00000000 00000000 00000000 00000000 ................
00001040: 00000000 00000000 00000000 00000000 ................
00001050: 00000000 00000000 00000000 00000000 ................
00001060: 00000000 00000000 00000000 00000000 ................
00001070: 00000000 00000000 01000000 00000000 ................
00001080: 03000000 04000000 00000000 01000000 ................
00001090: 03000000 04000000 0f000000 01000000 ................
000010a0: 03000000 08000000 1b000000 646e6173 ............sand
000010b0: 00786f62 03000000 08000000 21000000 box............!
000010c0: 646e6173 00786f62 01000000 61696c61 sandbox.....alia
000010d0: 00736573 03000000 07000000 2c000000 ses............,
000010e0: 6332692f 00003040 03000000 07000000 /i2c@0..........
000010f0: 31000000 6963702f 00003040 03000000 ...1/pci@0......
=> sf erase 0 80000
SF: 524288 bytes @ 0x0 Erased: OK
=> sf read 1000 1100 80000
device 0 offset 0x1100, size 0x80000
SF: 524288 bytes @ 0x1100 Read: OK
=> md 1000
00001000: ffffffff ffffffff ffffffff ffffffff ................
00001010: ffffffff ffffffff ffffffff ffffffff ................
00001020: ffffffff ffffffff ffffffff ffffffff ................
00001030: ffffffff ffffffff ffffffff ffffffff ................
00001040: ffffffff ffffffff ffffffff ffffffff ................
00001050: ffffffff ffffffff ffffffff ffffffff ................
00001060: ffffffff ffffffff ffffffff ffffffff ................
00001070: ffffffff ffffffff ffffffff ffffffff ................
00001080: ffffffff ffffffff ffffffff ffffffff ................
00001090: ffffffff ffffffff ffffffff ffffffff ................
000010a0: ffffffff ffffffff ffffffff ffffffff ................
000010b0: ffffffff ffffffff ffffffff ffffffff ................
000010c0: ffffffff ffffffff ffffffff ffffffff ................
000010d0: ffffffff ffffffff ffffffff ffffffff ................
000010e0: ffffffff ffffffff ffffffff ffffffff ................
000010f0: ffffffff ffffffff ffffffff ffffffff ................
This second example is running on coral, an x86 Chromebook::
=> sf probe
SF: Detected w25q128fw with page size 256 Bytes, erase size 4 KiB, total 16 MiB
=> sf erase 300000 80000
SF: 524288 bytes @ 0x300000 Erased: OK
=> sf update 1110000 300000 80000
device 0 offset 0x300000, size 0x80000
524288 bytes written, 0 bytes skipped in 0.457s, speed 1164578 B/s
# This does nothing as the flash is already updated
=> sf update 1110000 300000 80000
device 0 offset 0x300000, size 0x80000
0 bytes written, 524288 bytes skipped in 0.196s, speed 2684354 B/s
=> sf test 00000 80000 # try a protected region
SPI flash test:
Erase failed (err = -5)
Test failed
=> sf test 800000 80000
SPI flash test:
0 erase: 18 ticks, 28444 KiB/s 227.552 Mbps
1 check: 192 ticks, 2666 KiB/s 21.328 Mbps
2 write: 227 ticks, 2255 KiB/s 18.040 Mbps
3 read: 189 ticks, 2708 KiB/s 21.664 Mbps
Test passed
0 erase: 18 ticks, 28444 KiB/s 227.552 Mbps
1 check: 192 ticks, 2666 KiB/s 21.328 Mbps
2 write: 227 ticks, 2255 KiB/s 18.040 Mbps
3 read: 189 ticks, 2708 KiB/s 21.664 Mbps
.. _SPI documentation:
https://en.wikipedia.org/wiki/Serial_Peripheral_Interface

View File

@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev)
if (ret)
return log_msg_ret("child unbind", ret);
ret = uclass_pre_unbind_device(dev);
if (ret)
return log_msg_ret("uc", ret);
if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
free(dev_get_plat(dev));
dev_set_plat(dev, NULL);
@ -142,10 +145,8 @@ void device_free(struct udevice *dev)
}
if (dev->parent) {
size = dev->parent->driver->per_child_auto;
if (!size) {
size = dev->parent->uclass->uc_drv->
per_child_auto;
}
if (!size)
size = dev->parent->uclass->uc_drv->per_child_auto;
if (size) {
free(dev_get_parent_priv(dev));
dev_set_parent_priv(dev, NULL);

View File

@ -902,15 +902,16 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
return -ENODEV;
}
int device_find_child_by_name(const struct udevice *parent, const char *name,
struct udevice **devp)
int device_find_child_by_namelen(const struct udevice *parent, const char *name,
int len, struct udevice **devp)
{
struct udevice *dev;
*devp = NULL;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
if (!strcmp(dev->name, name)) {
if (!strncmp(dev->name, name, len) &&
strlen(dev->name) == len) {
*devp = dev;
return 0;
}
@ -919,6 +920,12 @@ int device_find_child_by_name(const struct udevice *parent, const char *name,
return -ENODEV;
}
int device_find_child_by_name(const struct udevice *parent, const char *name,
struct udevice **devp)
{
return device_find_child_by_namelen(parent, name, strlen(name), devp);
}
int device_first_child_err(struct udevice *parent, struct udevice **devp)
{
struct udevice *dev;

View File

@ -581,7 +581,8 @@ int of_property_match_string(const struct device_node *np, const char *propname,
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
* @skip: Number of strings to skip over at beginning of list.
* @skip: Number of strings to skip over at beginning of list (cannot be
* negative)
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.

View File

@ -456,6 +456,32 @@ int ofnode_read_string_count(ofnode node, const char *property)
}
}
int ofnode_read_string_list(ofnode node, const char *property,
const char ***listp)
{
const char **prop;
int count;
int i;
*listp = NULL;
count = ofnode_read_string_count(node, property);
if (count < 0)
return count;
if (!count)
return 0;
prop = calloc(count + 1, sizeof(char *));
if (!prop)
return -ENOMEM;
for (i = 0; i < count; i++)
ofnode_read_string_index(node, property, i, &prop[i]);
prop[count] = NULL;
*listp = prop;
return count;
}
static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
struct ofnode_phandle_args *out)
{

View File

@ -205,6 +205,12 @@ int dev_read_string_count(const struct udevice *dev, const char *propname)
return ofnode_read_string_count(dev_ofnode(dev), propname);
}
int dev_read_string_list(const struct udevice *dev, const char *propname,
const char ***listp)
{
return ofnode_read_string_list(dev_ofnode(dev), propname, listp);
}
int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name,
const char *cells_name, int cell_count,
int index, struct ofnode_phandle_args *out_args)

View File

@ -180,20 +180,25 @@ void uclass_set_priv(struct uclass *uc, void *priv)
uc->priv_ = priv;
}
enum uclass_id uclass_get_by_name(const char *name)
enum uclass_id uclass_get_by_name_len(const char *name, int len)
{
int i;
for (i = 0; i < UCLASS_COUNT; i++) {
struct uclass_driver *uc_drv = lists_uclass_lookup(i);
if (uc_drv && !strcmp(uc_drv->name, name))
if (uc_drv && !strncmp(uc_drv->name, name, len))
return i;
}
return UCLASS_INVALID;
}
enum uclass_id uclass_get_by_name(const char *name)
{
return uclass_get_by_name_len(name, strlen(name));
}
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
{
struct udevice *iter;
@ -682,7 +687,7 @@ err:
}
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
int uclass_unbind_device(struct udevice *dev)
int uclass_pre_unbind_device(struct udevice *dev)
{
struct uclass *uc;
int ret;
@ -694,7 +699,13 @@ int uclass_unbind_device(struct udevice *dev)
return ret;
}
return 0;
}
int uclass_unbind_device(struct udevice *dev)
{
list_del(&dev->uclass_node);
return 0;
}
#endif
@ -783,6 +794,18 @@ int uclass_probe_all(enum uclass_id id)
return 0;
}
int uclass_id_count(enum uclass_id id)
{
struct udevice *dev;
struct uclass *uc;
int count = 0;
uclass_id_foreach_dev(id, dev, uc)
count++;
return count;
}
UCLASS_DRIVER(nop) = {
.id = UCLASS_NOP,
.name = "nop",

View File

@ -320,7 +320,7 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
struct blk_desc *desc;
struct udevice *dev;
device_find_first_child(mmc->dev, &dev);
device_find_first_child_by_uclass(mmc->dev, UCLASS_BLK, &dev);
if (!dev)
return NULL;
desc = dev_get_uclass_plat(dev);
@ -425,7 +425,7 @@ int mmc_unbind(struct udevice *dev)
{
struct udevice *bdev;
device_find_first_child(dev, &bdev);
device_find_first_child_by_uclass(dev, UCLASS_BLK, &bdev);
if (bdev) {
device_remove(bdev, DM_REMOVE_NORMAL);
device_unbind(bdev);

View File

@ -9,23 +9,26 @@
#include <errno.h>
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
#include <mmc.h>
#include <os.h>
#include <asm/test.h>
struct sandbox_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
const char *fname;
};
#define MMC_CSIZE 0
#define MMC_CMULT 8 /* 8 because the card is high-capacity */
#define MMC_BL_LEN_SHIFT 10
#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
* MMC_BL_LEN) /* 1 MiB */
#define SIZE_MULTIPLE ((1 << (MMC_CMULT + 2)) * MMC_BL_LEN)
struct sandbox_mmc_priv {
u8 buf[MMC_CAPACITY];
char *buf;
int csize; /* CSIZE value to report */
int size;
};
/**
@ -60,8 +63,8 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
case MMC_CMD_SEND_CSD:
cmd->response[0] = 0;
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
((MMC_CSIZE >> 16) & 0x3f);
cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
((priv->csize >> 16) & 0x3f);
cmd->response[2] = (priv->csize & 0xffff) << 16;
cmd->response[3] = 0;
break;
case SD_CMD_SWITCH_FUNC: {
@ -143,6 +146,8 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
struct blk_desc *blk;
int ret;
plat->fname = dev_read_string(dev, "filename");
ret = mmc_of_parse(dev, cfg);
if (ret)
return ret;
@ -156,10 +161,46 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
static int sandbox_mmc_probe(struct udevice *dev)
{
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
struct sandbox_mmc_priv *priv = dev_get_priv(dev);
int ret;
if (plat->fname) {
ret = os_map_file(plat->fname, OS_O_RDWR | OS_O_CREAT,
(void **)&priv->buf, &priv->size);
if (ret) {
log_err("%s: Unable to map file '%s'\n", dev->name,
plat->fname);
return ret;
}
priv->csize = priv->size / SIZE_MULTIPLE - 1;
} else {
priv->csize = 0;
priv->size = (priv->csize + 1) * SIZE_MULTIPLE; /* 1 MiB */
priv->buf = malloc(priv->size);
if (!priv->buf) {
log_err("%s: Not enough memory (%x bytes)\n",
dev->name, priv->size);
return -ENOMEM;
}
}
return mmc_init(&plat->mmc);
}
static int sandbox_mmc_remove(struct udevice *dev)
{
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
struct sandbox_mmc_priv *priv = dev_get_priv(dev);
if (plat->fname)
os_unmap(priv->buf, priv->size);
else
free(priv->buf);
return 0;
}
static int sandbox_mmc_bind(struct udevice *dev)
{
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
@ -196,6 +237,7 @@ U_BOOT_DRIVER(mmc_sandbox) = {
.unbind = sandbox_mmc_unbind,
.of_to_plat = sandbox_mmc_of_to_plat,
.probe = sandbox_mmc_probe,
.remove = sandbox_mmc_remove,
.priv_auto = sizeof(struct sandbox_mmc_priv),
.plat_auto = sizeof(struct sandbox_mmc_plat),
};

View File

@ -45,7 +45,7 @@ struct cmd_tbl {
char *const argv[]);
char *usage; /* Usage message (short) */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* Help message (long) */
const char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */

View File

@ -758,6 +758,18 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
enum uclass_id uclass_id,
struct udevice **devp);
/**
* device_find_child_by_name() - Find a child by device name
*
* @parent: Parent device to search
* @name: Name to look for
* @len: Length of the name
* @devp: Returns device found, if any
* @return 0 if found, else -ENODEV
*/
int device_find_child_by_namelen(const struct udevice *parent, const char *name,
int len, struct udevice **devp);
/**
* device_find_child_by_name() - Find a child by device name
*

View File

@ -590,11 +590,11 @@ int ofnode_stringlist_search(ofnode node, const char *propname,
*
* @node: node to check
* @propname: name of the property containing the string list
* @index: index of the string to return
* @index: index of the string to return (cannot be negative)
* @lenp: return location for the string length or an error code on failure
*
* @return:
* length of string, if found or -ve error value if not found
* 0 if found or -ve error value if not found
*/
int ofnode_read_string_index(ofnode node, const char *propname, int index,
const char **outp);
@ -609,6 +609,26 @@ int ofnode_read_string_index(ofnode node, const char *propname, int index,
*/
int ofnode_read_string_count(ofnode node, const char *property);
/**
* ofnode_read_string_list() - read a list of strings
*
* This produces a list of string pointers with each one pointing to a string
* in the string list. If the property does not exist, it returns {NULL}.
*
* The data is allocated and the caller is reponsible for freeing the return
* value (the list of string pointers). The strings themselves may not be
* changed as they point directly into the devicetree property.
*
* @node: node to check
* @listp: returns an allocated, NULL-terminated list of strings if the return
* value is > 0, else is set to NULL
* @return number of strings in list, 0 if none, -ENOMEM if out of memory,
* -EINVAL if no such property, -EENODATA if property is empty
* @return: NULL-terminated list of strings (NULL if no property or empty)
*/
int ofnode_read_string_list(ofnode node, const char *property,
const char ***listp);
/**
* ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list
*

View File

@ -371,6 +371,27 @@ int dev_read_string_index(const struct udevice *dev, const char *propname,
* number of strings in the list, or -ve error value if not found
*/
int dev_read_string_count(const struct udevice *dev, const char *propname);
/**
* dev_read_string_list() - read a list of strings
*
* This produces a list of string pointers with each one pointing to a string
* in the string list. If the property does not exist, it returns {NULL}.
*
* The data is allocated and the caller is reponsible for freeing the return
* value (the list of string pointers). The strings themselves may not be
* changed as they point directly into the devicetree property.
*
* @dev: device to examine
* @propname: name of the property containing the string list
* @listp: returns an allocated, NULL-terminated list of strings if the return
* value is > 0, else is set to NULL
* @return number of strings in list, 0 if none, -ENOMEM if out of memory,
* -ENOENT if no such property
*/
int dev_read_string_list(const struct udevice *dev, const char *propname,
const char ***listp);
/**
* dev_read_phandle_with_args() - Find a node pointed by phandle in a list
*
@ -906,6 +927,13 @@ static inline int dev_read_string_count(const struct udevice *dev,
return ofnode_read_string_count(dev_ofnode(dev), propname);
}
static inline int dev_read_string_list(const struct udevice *dev,
const char *propname,
const char ***listp)
{
return ofnode_read_string_list(dev_ofnode(dev), propname, listp);
}
static inline int dev_read_phandle_with_args(const struct udevice *dev,
const char *list_name, const char *cells_name, int cell_count,
int index, struct ofnode_phandle_args *out_args)

View File

@ -243,6 +243,17 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
*/
int uclass_bind_device(struct udevice *dev);
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
/**
* uclass_pre_unbind_device() - Prepare to deassociate device with a uclass
*
* Call any handled needed before uclass_unbind_device() is called
*
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
int uclass_pre_unbind_device(struct udevice *dev);
/**
* uclass_unbind_device() - Deassociate device with a uclass
*
@ -251,9 +262,10 @@ int uclass_bind_device(struct udevice *dev);
* @dev: Pointer to the device
* #return 0 on success, -ve on error
*/
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
int uclass_unbind_device(struct udevice *dev);
#else
static inline int uclass_pre_unbind_device(struct udevice *dev) { return 0; }
static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
#endif

View File

@ -172,6 +172,15 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
*/
const char *uclass_get_name(enum uclass_id id);
/**
* uclass_get_by_name() - Look up a uclass by its driver name
*
* @name: Name to look up
* @len: Length of name
* @returns the associated uclass ID, or UCLASS_INVALID if not found
*/
enum uclass_id uclass_get_by_name_len(const char *name, int len);
/**
* uclass_get_by_name() - Look up a uclass by its driver name
*
@ -416,6 +425,14 @@ int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
*/
int uclass_probe_all(enum uclass_id id);
/**
* uclass_id_count() - Count the number of devices in a uclass
*
* @id: uclass ID to look up
* @return number of devices in that uclass (0 if none)
*/
int uclass_id_count(enum uclass_id id);
/**
* uclass_id_foreach_dev() - Helper function to iteration through devices
*

View File

@ -419,6 +419,15 @@ int os_read_file(const char *name, void **bufp, int *sizep);
*/
int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep);
/**
* os_unmap() - Unmap a file previously mapped
*
* @buf: Mapped address
* @size: Size in bytes
* Return: 0 if OK, -ve on error
*/
int os_unmap(void *buf, int size);
/*
* os_find_text_base() - Find the text section in this running process
*

View File

@ -21,29 +21,39 @@ BEGIN {
# Skip empty lines, as these are generated by the clang preprocessor
NF {
do_output = 0
# Quote quotes
gsub("\"", "\\\"")
# Avoid using the non-POSIX third parameter to match(), by splitting
# the work into several steps.
has_var = match($0, "^([^ \t=][^ =]*)=(.*)$")
# Is this the start of a new environment variable?
if (match($0, "^([^ \t=][^ =]*)=(.*)$", arr)) {
if (has_var) {
if (length(env) != 0) {
# Record the value of the variable now completed
vars[var] = env
do_output = 1
}
var = arr[1]
env = arr[2]
# Collect the variable name. The value follows the '='
match($0, "^([^ \t=][^ =]*)=")
var = substr($0, 1, RLENGTH - 1)
env = substr($0, RLENGTH + 1)
# Deal with += which concatenates the new string to the existing
# variable
if (length(env) != 0 && match(var, "^(.*)[+]$", var_arr))
{
# variable. Again we are careful to use POSIX match()
if (length(env) != 0 && match(var, "^(.*)[+]$")) {
plusname = substr(var, RSTART, RLENGTH - 1)
# Allow var\+=val to indicate that the variable name is
# var+ and this is not actually a concatenation
if (substr(var_arr[1], length(var_arr[1])) == "\\") {
if (substr(plusname, length(plusname)) == "\\") {
# Drop the backslash
sub(/\\[+]$/, "+", var)
} else {
var = var_arr[1]
var = plusname
env = vars[var] env
}
}
@ -65,9 +75,10 @@ END {
# empty it is not set.
if (length(env) != 0) {
vars[var] = env
do_output = 1
}
if (length(vars) != 0) {
if (do_output) {
printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
# Print out all the variables

View File

@ -351,3 +351,99 @@ static int dm_test_ofnode_for_each_compatible_node(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT);
static int dm_test_ofnode_string(struct unit_test_state *uts)
{
const char **val;
const char *out;
ofnode node;
node = ofnode_path("/a-test");
ut_assert(ofnode_valid(node));
/* single string */
ut_asserteq(1, ofnode_read_string_count(node, "str-value"));
ut_assertok(ofnode_read_string_index(node, "str-value", 0, &out));
ut_asserteq_str("test string", out);
ut_asserteq(0, ofnode_stringlist_search(node, "str-value",
"test string"));
ut_asserteq(1, ofnode_read_string_list(node, "str-value", &val));
ut_asserteq_str("test string", val[0]);
ut_assertnull(val[1]);
free(val);
/* list of strings */
ut_asserteq(5, ofnode_read_string_count(node, "mux-control-names"));
ut_assertok(ofnode_read_string_index(node, "mux-control-names", 0,
&out));
ut_asserteq_str("mux0", out);
ut_asserteq(0, ofnode_stringlist_search(node, "mux-control-names",
"mux0"));
ut_asserteq(5, ofnode_read_string_list(node, "mux-control-names",
&val));
ut_asserteq_str("mux0", val[0]);
ut_asserteq_str("mux1", val[1]);
ut_asserteq_str("mux2", val[2]);
ut_asserteq_str("mux3", val[3]);
ut_asserteq_str("mux4", val[4]);
ut_assertnull(val[5]);
free(val);
ut_assertok(ofnode_read_string_index(node, "mux-control-names", 4,
&out));
ut_asserteq_str("mux4", out);
ut_asserteq(4, ofnode_stringlist_search(node, "mux-control-names",
"mux4"));
return 0;
}
DM_TEST(dm_test_ofnode_string, 0);
static int dm_test_ofnode_string_err(struct unit_test_state *uts)
{
const char **val;
const char *out;
ofnode node;
/*
* Test error codes only on livetree, as they are different with
* flattree
*/
node = ofnode_path("/a-test");
ut_assert(ofnode_valid(node));
/* non-existent property */
ut_asserteq(-EINVAL, ofnode_read_string_count(node, "missing"));
ut_asserteq(-EINVAL, ofnode_read_string_index(node, "missing", 0,
&out));
ut_asserteq(-EINVAL, ofnode_read_string_list(node, "missing", &val));
/* empty property */
ut_asserteq(-ENODATA, ofnode_read_string_count(node, "bool-value"));
ut_asserteq(-ENODATA, ofnode_read_string_index(node, "bool-value", 0,
&out));
ut_asserteq(-ENODATA, ofnode_read_string_list(node, "bool-value",
&val));
/* badly formatted string list */
ut_asserteq(-EILSEQ, ofnode_read_string_count(node, "int64-value"));
ut_asserteq(-EILSEQ, ofnode_read_string_index(node, "int64-value", 0,
&out));
ut_asserteq(-EILSEQ, ofnode_read_string_list(node, "int64-value",
&val));
/* out of range / not found */
ut_asserteq(-ENODATA, ofnode_read_string_index(node, "str-value", 1,
&out));
ut_asserteq(-ENODATA, ofnode_stringlist_search(node, "str-value",
"other"));
/* negative value for index is not allowed, so don't test for that */
ut_asserteq(-ENODATA, ofnode_read_string_index(node,
"mux-control-names", 5,
&out));
return 0;
}
DM_TEST(dm_test_ofnode_string_err, UT_TESTF_LIVE_TREE);

View File

@ -226,7 +226,7 @@ def pytest_configure(config):
import u_boot_console_exec_attach
console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
re_ut_test_list = re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_test_2_\1_test_(.*)\s*$')
re_ut_test_list = re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_test_2_(.*)\s*$')
def generate_ut_subtest(metafunc, fixture_name, sym_path):
"""Provide parametrization for a ut_subtest fixture.

View File

@ -109,7 +109,7 @@ class RunAndLog(object):
"""Clean up any resources managed by this object."""
pass
def run(self, cmd, cwd=None, ignore_errors=False):
def run(self, cmd, cwd=None, ignore_errors=False, stdin=None):
"""Run a command as a sub-process, and log the results.
The output is available at self.output which can be useful if there is
@ -123,6 +123,7 @@ class RunAndLog(object):
function will simply return if the command cannot be executed
or exits with an error code, otherwise an exception will be
raised if such problems occur.
stdin: Input string to pass to the command as stdin (or None)
Returns:
The output as a string.
@ -135,8 +136,9 @@ class RunAndLog(object):
try:
p = subprocess.Popen(cmd, cwd=cwd,
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
(stdout, stderr) = p.communicate()
stdin=subprocess.PIPE if stdin else None,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
(stdout, stderr) = p.communicate(input=stdin)
if stdout is not None:
stdout = stdout.decode('utf-8')
if stderr is not None:
@ -163,7 +165,7 @@ class RunAndLog(object):
if output and not output.endswith('\n'):
output += '\n'
if exit_status and not exception and not ignore_errors:
exception = Exception('Exit code: ' + str(exit_status))
exception = ValueError('Exit code: ' + str(exit_status))
if exception:
output += str(exception) + '\n'
self.logfile.write(self, output)

View File

@ -154,7 +154,7 @@ def wait_until_file_open_fails(fn, ignore_errors):
return
raise Exception('File can still be opened')
def run_and_log(u_boot_console, cmd, ignore_errors=False):
def run_and_log(u_boot_console, cmd, ignore_errors=False, stdin=None):
"""Run a command and log its output.
Args:
@ -166,6 +166,7 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False):
will simply return if the command cannot be executed or exits with
an error code, otherwise an exception will be raised if such
problems occur.
stdin: Input string to pass to the command as stdin (or None)
Returns:
The output as a string.
@ -173,7 +174,7 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False):
if isinstance(cmd, str):
cmd = cmd.split()
runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
output = runner.run(cmd, ignore_errors=ignore_errors)
output = runner.run(cmd, ignore_errors=ignore_errors, stdin=stdin)
runner.close()
return output

View File

@ -355,6 +355,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
Returns:
List of EntryInfo records that were written
"""
image_fname = os.path.abspath(image_fname)
image = Image.FromFile(image_fname)
# Replace an entry from a single file, as a special case