mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-14 04:46:01 +01:00
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:
commit
c087b5ad97
@ -211,6 +211,16 @@ int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
|
|||||||
return 0;
|
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 */
|
/* Restore tty state when we exit */
|
||||||
static struct termios orig_term;
|
static struct termios orig_term;
|
||||||
static bool term_setup;
|
static bool term_setup;
|
||||||
|
@ -207,6 +207,7 @@
|
|||||||
test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
|
test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
|
||||||
test5-gpios = <&gpio_a 19>;
|
test5-gpios = <&gpio_a 19>;
|
||||||
|
|
||||||
|
bool-value;
|
||||||
int-value = <1234>;
|
int-value = <1234>;
|
||||||
uint-value = <(-1234)>;
|
uint-value = <(-1234)>;
|
||||||
int64-value = /bits/ 64 <0x1111222233334444>;
|
int64-value = /bits/ 64 <0x1111222233334444>;
|
||||||
|
@ -244,12 +244,12 @@ static int do_verify_mbr(struct blk_desc *dev, const char *str)
|
|||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
struct disk_partition p;
|
struct disk_partition p;
|
||||||
|
|
||||||
if (part_get_info(dev, i+1, &p))
|
if (part_get_info(dev, i + 1, &p))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ((partitions[i].size && p.size < partitions[i].size) ||
|
if ((partitions[i].size && p.size != partitions[i].size) ||
|
||||||
(partitions[i].start && p.start < partitions[i].start) ||
|
(partitions[i].start && p.start != partitions[i].start) ||
|
||||||
(p.sys_ind != partitions[i].sys_ind))
|
p.sys_ind != partitions[i].sys_ind)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
32
cmd/sf.c
32
cmd/sf.c
@ -384,7 +384,6 @@ static int do_spi_protect(int argc, char *const argv[])
|
|||||||
return ret == 0 ? 0 : 1;
|
return ret == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CMD_SF_TEST
|
|
||||||
enum {
|
enum {
|
||||||
STAGE_ERASE,
|
STAGE_ERASE,
|
||||||
STAGE_CHECK,
|
STAGE_CHECK,
|
||||||
@ -394,7 +393,7 @@ enum {
|
|||||||
STAGE_COUNT,
|
STAGE_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *stage_name[STAGE_COUNT] = {
|
static const char *stage_name[STAGE_COUNT] = {
|
||||||
"erase",
|
"erase",
|
||||||
"check",
|
"check",
|
||||||
"write",
|
"write",
|
||||||
@ -548,7 +547,6 @@ static int do_spi_flash_test(int argc, char *const argv[])
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_CMD_SF_TEST */
|
|
||||||
|
|
||||||
static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
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);
|
ret = do_spi_flash_erase(argc, argv);
|
||||||
else if (strcmp(cmd, "protect") == 0)
|
else if (strcmp(cmd, "protect") == 0)
|
||||||
ret = do_spi_protect(argc, argv);
|
ret = do_spi_protect(argc, argv);
|
||||||
#ifdef CONFIG_CMD_SF_TEST
|
else if (IS_ENABLED(CONFIG_CMD_SF_TEST) && !strcmp(cmd, "test"))
|
||||||
else if (!strcmp(cmd, "test"))
|
|
||||||
ret = do_spi_flash_test(argc, argv);
|
ret = do_spi_flash_test(argc, argv);
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
@ -597,16 +593,8 @@ usage:
|
|||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CMD_SF_TEST
|
#ifdef CONFIG_SYS_LONGHELP
|
||||||
#define SF_TEST_HELP "\nsf test offset len " \
|
static const char long_help[] =
|
||||||
"- 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",
|
|
||||||
"probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n"
|
"probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n"
|
||||||
" and chip select\n"
|
" and chip select\n"
|
||||||
"sf read addr offset|partition len - read `len' bytes starting at\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"
|
" at `addr' to flash at `offset'\n"
|
||||||
" or to start of mtd `partition'\n"
|
" or to start of mtd `partition'\n"
|
||||||
"sf protect lock/unlock sector len - protect/unprotect 'len' bytes starting\n"
|
"sf protect lock/unlock sector len - protect/unprotect 'len' bytes starting\n"
|
||||||
" at address 'sector'\n"
|
" at address 'sector'"
|
||||||
SF_TEST_HELP
|
#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
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,16 @@ config CONSOLE_RECORD_OUT_SIZE
|
|||||||
more data will be recorded until some is removed. The buffer is
|
more data will be recorded until some is removed. The buffer is
|
||||||
allocated immediately after the malloc() region is ready.
|
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
|
config CONSOLE_RECORD_IN_SIZE
|
||||||
hex "Input buffer size"
|
hex "Input buffer size"
|
||||||
depends on CONSOLE_RECORD
|
depends on CONSOLE_RECORD
|
||||||
|
@ -735,7 +735,9 @@ int console_record_init(void)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = membuff_new((struct membuff *)&gd->console_out,
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = membuff_new((struct membuff *)&gd->console_in,
|
ret = membuff_new((struct membuff *)&gd->console_in,
|
||||||
|
@ -203,6 +203,7 @@ CONFIG_RSA_VERIFY_WITH_PKEY=y
|
|||||||
CONFIG_TPM=y
|
CONFIG_TPM=y
|
||||||
CONFIG_LZ4=y
|
CONFIG_LZ4=y
|
||||||
CONFIG_ERRNO_STR=y
|
CONFIG_ERRNO_STR=y
|
||||||
|
CONFIG_HEXDUMP=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
|
||||||
|
@ -459,10 +459,12 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
|
|||||||
ext = &p[i];
|
ext = &p[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= 4 && !ext) {
|
if (count < 4)
|
||||||
printf("%s: extended partition is needed for more than 4 partitions\n",
|
return 0;
|
||||||
__func__);
|
|
||||||
return -1;
|
if (!ext) {
|
||||||
|
log_err("extended partition is needed for more than 4 partitions\n");
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate extended volumes start and size if needed */
|
/* calculate extended volumes start and size if needed */
|
||||||
|
18
doc/device-tree-bindings/mmc/sandbox,mmc.txt
Normal file
18
doc/device-tree-bindings/mmc/sandbox,mmc.txt
Normal 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;
|
||||||
|
};
|
@ -45,6 +45,7 @@ Shell commands
|
|||||||
qfw
|
qfw
|
||||||
reset
|
reset
|
||||||
sbi
|
sbi
|
||||||
|
sf
|
||||||
scp03
|
scp03
|
||||||
setexpr
|
setexpr
|
||||||
size
|
size
|
||||||
|
245
doc/usage/sf.rst
Normal file
245
doc/usage/sf.rst
Normal 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
|
@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("child unbind", 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) {
|
if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
|
||||||
free(dev_get_plat(dev));
|
free(dev_get_plat(dev));
|
||||||
dev_set_plat(dev, NULL);
|
dev_set_plat(dev, NULL);
|
||||||
@ -142,10 +145,8 @@ void device_free(struct udevice *dev)
|
|||||||
}
|
}
|
||||||
if (dev->parent) {
|
if (dev->parent) {
|
||||||
size = dev->parent->driver->per_child_auto;
|
size = dev->parent->driver->per_child_auto;
|
||||||
if (!size) {
|
if (!size)
|
||||||
size = dev->parent->uclass->uc_drv->
|
size = dev->parent->uclass->uc_drv->per_child_auto;
|
||||||
per_child_auto;
|
|
||||||
}
|
|
||||||
if (size) {
|
if (size) {
|
||||||
free(dev_get_parent_priv(dev));
|
free(dev_get_parent_priv(dev));
|
||||||
dev_set_parent_priv(dev, NULL);
|
dev_set_parent_priv(dev, NULL);
|
||||||
|
@ -902,15 +902,16 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_find_child_by_name(const struct udevice *parent, const char *name,
|
int device_find_child_by_namelen(const struct udevice *parent, const char *name,
|
||||||
struct udevice **devp)
|
int len, struct udevice **devp)
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
*devp = NULL;
|
*devp = NULL;
|
||||||
|
|
||||||
list_for_each_entry(dev, &parent->child_head, sibling_node) {
|
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;
|
*devp = dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -919,6 +920,12 @@ int device_find_child_by_name(const struct udevice *parent, const char *name,
|
|||||||
return -ENODEV;
|
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)
|
int device_first_child_err(struct udevice *parent, struct udevice **devp)
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
@ -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.
|
* @propname: name of the property to be searched.
|
||||||
* @out_strs: output array of string pointers.
|
* @out_strs: output array of string pointers.
|
||||||
* @sz: number of array elements to read.
|
* @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
|
* Don't call this function directly. It is a utility helper for the
|
||||||
* of_property_read_string*() family of functions.
|
* of_property_read_string*() family of functions.
|
||||||
|
@ -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,
|
static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
|
||||||
struct ofnode_phandle_args *out)
|
struct ofnode_phandle_args *out)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
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,
|
int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name,
|
||||||
const char *cells_name, int cell_count,
|
const char *cells_name, int cell_count,
|
||||||
int index, struct ofnode_phandle_args *out_args)
|
int index, struct ofnode_phandle_args *out_args)
|
||||||
|
@ -180,20 +180,25 @@ void uclass_set_priv(struct uclass *uc, void *priv)
|
|||||||
uc->priv_ = 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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < UCLASS_COUNT; i++) {
|
for (i = 0; i < UCLASS_COUNT; i++) {
|
||||||
struct uclass_driver *uc_drv = lists_uclass_lookup(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 i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UCLASS_INVALID;
|
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)
|
int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
|
||||||
{
|
{
|
||||||
struct udevice *iter;
|
struct udevice *iter;
|
||||||
@ -682,7 +687,7 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
|
#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;
|
struct uclass *uc;
|
||||||
int ret;
|
int ret;
|
||||||
@ -694,7 +699,13 @@ int uclass_unbind_device(struct udevice *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uclass_unbind_device(struct udevice *dev)
|
||||||
|
{
|
||||||
list_del(&dev->uclass_node);
|
list_del(&dev->uclass_node);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -783,6 +794,18 @@ int uclass_probe_all(enum uclass_id id)
|
|||||||
return 0;
|
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) = {
|
UCLASS_DRIVER(nop) = {
|
||||||
.id = UCLASS_NOP,
|
.id = UCLASS_NOP,
|
||||||
.name = "nop",
|
.name = "nop",
|
||||||
|
@ -320,7 +320,7 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
|
|||||||
struct blk_desc *desc;
|
struct blk_desc *desc;
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
|
||||||
device_find_first_child(mmc->dev, &dev);
|
device_find_first_child_by_uclass(mmc->dev, UCLASS_BLK, &dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
desc = dev_get_uclass_plat(dev);
|
desc = dev_get_uclass_plat(dev);
|
||||||
@ -425,7 +425,7 @@ int mmc_unbind(struct udevice *dev)
|
|||||||
{
|
{
|
||||||
struct udevice *bdev;
|
struct udevice *bdev;
|
||||||
|
|
||||||
device_find_first_child(dev, &bdev);
|
device_find_first_child_by_uclass(dev, UCLASS_BLK, &bdev);
|
||||||
if (bdev) {
|
if (bdev) {
|
||||||
device_remove(bdev, DM_REMOVE_NORMAL);
|
device_remove(bdev, DM_REMOVE_NORMAL);
|
||||||
device_unbind(bdev);
|
device_unbind(bdev);
|
||||||
|
@ -9,23 +9,26 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
|
#include <malloc.h>
|
||||||
#include <mmc.h>
|
#include <mmc.h>
|
||||||
|
#include <os.h>
|
||||||
#include <asm/test.h>
|
#include <asm/test.h>
|
||||||
|
|
||||||
struct sandbox_mmc_plat {
|
struct sandbox_mmc_plat {
|
||||||
struct mmc_config cfg;
|
struct mmc_config cfg;
|
||||||
struct mmc mmc;
|
struct mmc mmc;
|
||||||
|
const char *fname;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MMC_CSIZE 0
|
|
||||||
#define MMC_CMULT 8 /* 8 because the card is high-capacity */
|
#define MMC_CMULT 8 /* 8 because the card is high-capacity */
|
||||||
#define MMC_BL_LEN_SHIFT 10
|
#define MMC_BL_LEN_SHIFT 10
|
||||||
#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
|
#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
|
||||||
#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
|
#define SIZE_MULTIPLE ((1 << (MMC_CMULT + 2)) * MMC_BL_LEN)
|
||||||
* MMC_BL_LEN) /* 1 MiB */
|
|
||||||
|
|
||||||
struct sandbox_mmc_priv {
|
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:
|
case MMC_CMD_SEND_CSD:
|
||||||
cmd->response[0] = 0;
|
cmd->response[0] = 0;
|
||||||
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
|
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
|
||||||
((MMC_CSIZE >> 16) & 0x3f);
|
((priv->csize >> 16) & 0x3f);
|
||||||
cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
|
cmd->response[2] = (priv->csize & 0xffff) << 16;
|
||||||
cmd->response[3] = 0;
|
cmd->response[3] = 0;
|
||||||
break;
|
break;
|
||||||
case SD_CMD_SWITCH_FUNC: {
|
case SD_CMD_SWITCH_FUNC: {
|
||||||
@ -143,6 +146,8 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
|
|||||||
struct blk_desc *blk;
|
struct blk_desc *blk;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
plat->fname = dev_read_string(dev, "filename");
|
||||||
|
|
||||||
ret = mmc_of_parse(dev, cfg);
|
ret = mmc_of_parse(dev, cfg);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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)
|
static int sandbox_mmc_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct sandbox_mmc_plat *plat = dev_get_plat(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);
|
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)
|
static int sandbox_mmc_bind(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
|
struct sandbox_mmc_plat *plat = dev_get_plat(dev);
|
||||||
@ -196,6 +237,7 @@ U_BOOT_DRIVER(mmc_sandbox) = {
|
|||||||
.unbind = sandbox_mmc_unbind,
|
.unbind = sandbox_mmc_unbind,
|
||||||
.of_to_plat = sandbox_mmc_of_to_plat,
|
.of_to_plat = sandbox_mmc_of_to_plat,
|
||||||
.probe = sandbox_mmc_probe,
|
.probe = sandbox_mmc_probe,
|
||||||
|
.remove = sandbox_mmc_remove,
|
||||||
.priv_auto = sizeof(struct sandbox_mmc_priv),
|
.priv_auto = sizeof(struct sandbox_mmc_priv),
|
||||||
.plat_auto = sizeof(struct sandbox_mmc_plat),
|
.plat_auto = sizeof(struct sandbox_mmc_plat),
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ struct cmd_tbl {
|
|||||||
char *const argv[]);
|
char *const argv[]);
|
||||||
char *usage; /* Usage message (short) */
|
char *usage; /* Usage message (short) */
|
||||||
#ifdef CONFIG_SYS_LONGHELP
|
#ifdef CONFIG_SYS_LONGHELP
|
||||||
char *help; /* Help message (long) */
|
const char *help; /* Help message (long) */
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_AUTO_COMPLETE
|
#ifdef CONFIG_AUTO_COMPLETE
|
||||||
/* do auto completion on the arguments */
|
/* do auto completion on the arguments */
|
||||||
|
@ -758,6 +758,18 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
|
|||||||
enum uclass_id uclass_id,
|
enum uclass_id uclass_id,
|
||||||
struct udevice **devp);
|
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
|
* device_find_child_by_name() - Find a child by device name
|
||||||
*
|
*
|
||||||
|
@ -590,11 +590,11 @@ int ofnode_stringlist_search(ofnode node, const char *propname,
|
|||||||
*
|
*
|
||||||
* @node: node to check
|
* @node: node to check
|
||||||
* @propname: name of the property containing the string list
|
* @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
|
* @lenp: return location for the string length or an error code on failure
|
||||||
*
|
*
|
||||||
* @return:
|
* @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,
|
int ofnode_read_string_index(ofnode node, const char *propname, int index,
|
||||||
const char **outp);
|
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);
|
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
|
* ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list
|
||||||
*
|
*
|
||||||
|
@ -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
|
* 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);
|
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
|
* 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);
|
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,
|
static inline int dev_read_phandle_with_args(const struct udevice *dev,
|
||||||
const char *list_name, const char *cells_name, int cell_count,
|
const char *list_name, const char *cells_name, int cell_count,
|
||||||
int index, struct ofnode_phandle_args *out_args)
|
int index, struct ofnode_phandle_args *out_args)
|
||||||
|
@ -243,6 +243,17 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
|
|||||||
*/
|
*/
|
||||||
int uclass_bind_device(struct udevice *dev);
|
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
|
* uclass_unbind_device() - Deassociate device with a uclass
|
||||||
*
|
*
|
||||||
@ -251,9 +262,10 @@ int uclass_bind_device(struct udevice *dev);
|
|||||||
* @dev: Pointer to the device
|
* @dev: Pointer to the device
|
||||||
* #return 0 on success, -ve on error
|
* #return 0 on success, -ve on error
|
||||||
*/
|
*/
|
||||||
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
|
|
||||||
int uclass_unbind_device(struct udevice *dev);
|
int uclass_unbind_device(struct udevice *dev);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
static inline int uclass_pre_unbind_device(struct udevice *dev) { return 0; }
|
||||||
static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
|
static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -172,6 +172,15 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
|
|||||||
*/
|
*/
|
||||||
const char *uclass_get_name(enum uclass_id id);
|
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
|
* 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);
|
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
|
* uclass_id_foreach_dev() - Helper function to iteration through devices
|
||||||
*
|
*
|
||||||
|
@ -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);
|
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
|
* os_find_text_base() - Find the text section in this running process
|
||||||
*
|
*
|
||||||
|
@ -21,29 +21,39 @@ BEGIN {
|
|||||||
|
|
||||||
# Skip empty lines, as these are generated by the clang preprocessor
|
# Skip empty lines, as these are generated by the clang preprocessor
|
||||||
NF {
|
NF {
|
||||||
|
do_output = 0
|
||||||
|
|
||||||
# Quote quotes
|
# Quote quotes
|
||||||
gsub("\"", "\\\"")
|
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?
|
# Is this the start of a new environment variable?
|
||||||
if (match($0, "^([^ \t=][^ =]*)=(.*)$", arr)) {
|
if (has_var) {
|
||||||
if (length(env) != 0) {
|
if (length(env) != 0) {
|
||||||
# Record the value of the variable now completed
|
# Record the value of the variable now completed
|
||||||
vars[var] = env
|
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
|
# Deal with += which concatenates the new string to the existing
|
||||||
# variable
|
# variable. Again we are careful to use POSIX match()
|
||||||
if (length(env) != 0 && match(var, "^(.*)[+]$", var_arr))
|
if (length(env) != 0 && match(var, "^(.*)[+]$")) {
|
||||||
{
|
plusname = substr(var, RSTART, RLENGTH - 1)
|
||||||
# Allow var\+=val to indicate that the variable name is
|
# Allow var\+=val to indicate that the variable name is
|
||||||
# var+ and this is not actually a concatenation
|
# 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
|
# Drop the backslash
|
||||||
sub(/\\[+]$/, "+", var)
|
sub(/\\[+]$/, "+", var)
|
||||||
} else {
|
} else {
|
||||||
var = var_arr[1]
|
var = plusname
|
||||||
env = vars[var] env
|
env = vars[var] env
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,9 +75,10 @@ END {
|
|||||||
# empty it is not set.
|
# empty it is not set.
|
||||||
if (length(env) != 0) {
|
if (length(env) != 0) {
|
||||||
vars[var] = env
|
vars[var] = env
|
||||||
|
do_output = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length(vars) != 0) {
|
if (do_output) {
|
||||||
printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
|
printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
|
||||||
|
|
||||||
# Print out all the variables
|
# Print out all the variables
|
||||||
|
@ -351,3 +351,99 @@ static int dm_test_ofnode_for_each_compatible_node(struct unit_test_state *uts)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT);
|
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);
|
||||||
|
@ -226,7 +226,7 @@ def pytest_configure(config):
|
|||||||
import u_boot_console_exec_attach
|
import u_boot_console_exec_attach
|
||||||
console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
|
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):
|
def generate_ut_subtest(metafunc, fixture_name, sym_path):
|
||||||
"""Provide parametrization for a ut_subtest fixture.
|
"""Provide parametrization for a ut_subtest fixture.
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class RunAndLog(object):
|
|||||||
"""Clean up any resources managed by this object."""
|
"""Clean up any resources managed by this object."""
|
||||||
pass
|
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.
|
"""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
|
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
|
function will simply return if the command cannot be executed
|
||||||
or exits with an error code, otherwise an exception will be
|
or exits with an error code, otherwise an exception will be
|
||||||
raised if such problems occur.
|
raised if such problems occur.
|
||||||
|
stdin: Input string to pass to the command as stdin (or None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The output as a string.
|
The output as a string.
|
||||||
@ -135,8 +136,9 @@ class RunAndLog(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd, cwd=cwd,
|
p = subprocess.Popen(cmd, cwd=cwd,
|
||||||
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
stdin=subprocess.PIPE if stdin else None,
|
||||||
(stdout, stderr) = p.communicate()
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
(stdout, stderr) = p.communicate(input=stdin)
|
||||||
if stdout is not None:
|
if stdout is not None:
|
||||||
stdout = stdout.decode('utf-8')
|
stdout = stdout.decode('utf-8')
|
||||||
if stderr is not None:
|
if stderr is not None:
|
||||||
@ -163,7 +165,7 @@ class RunAndLog(object):
|
|||||||
if output and not output.endswith('\n'):
|
if output and not output.endswith('\n'):
|
||||||
output += '\n'
|
output += '\n'
|
||||||
if exit_status and not exception and not ignore_errors:
|
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:
|
if exception:
|
||||||
output += str(exception) + '\n'
|
output += str(exception) + '\n'
|
||||||
self.logfile.write(self, output)
|
self.logfile.write(self, output)
|
||||||
|
@ -154,7 +154,7 @@ def wait_until_file_open_fails(fn, ignore_errors):
|
|||||||
return
|
return
|
||||||
raise Exception('File can still be opened')
|
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.
|
"""Run a command and log its output.
|
||||||
|
|
||||||
Args:
|
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
|
will simply return if the command cannot be executed or exits with
|
||||||
an error code, otherwise an exception will be raised if such
|
an error code, otherwise an exception will be raised if such
|
||||||
problems occur.
|
problems occur.
|
||||||
|
stdin: Input string to pass to the command as stdin (or None)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The output as a string.
|
The output as a string.
|
||||||
@ -173,7 +174,7 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False):
|
|||||||
if isinstance(cmd, str):
|
if isinstance(cmd, str):
|
||||||
cmd = cmd.split()
|
cmd = cmd.split()
|
||||||
runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
|
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()
|
runner.close()
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
@ -355,6 +355,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
|
|||||||
Returns:
|
Returns:
|
||||||
List of EntryInfo records that were written
|
List of EntryInfo records that were written
|
||||||
"""
|
"""
|
||||||
|
image_fname = os.path.abspath(image_fname)
|
||||||
image = Image.FromFile(image_fname)
|
image = Image.FromFile(image_fname)
|
||||||
|
|
||||||
# Replace an entry from a single file, as a special case
|
# Replace an entry from a single file, as a special case
|
||||||
|
Loading…
x
Reference in New Issue
Block a user