mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 05:50:17 +00: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 SIZE_MULTIPLE		((1 << (MMC_CMULT + 2)) * MMC_BL_LEN)
 | 
				
			||||||
#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
 | 
					 | 
				
			||||||
		      * 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