Merge branch '2022-04-14-assorted-updates'

- Apple M1 Ultra support, TI power domain fix, atsha204a big endian
  support, LED cleanups and support for default-state, increase malloc
  pool on sandbox, ubifs bugfix, further serial cleanup / semihost
  support, fix a few cases around enabling/disabling FS support in SPL,
  clean up duplication of table_compute_checksum()
diff --git a/Kconfig b/Kconfig
index 0ee3068..b45e60a 100644
--- a/Kconfig
+++ b/Kconfig
@@ -263,6 +263,7 @@
 
 config SYS_MALLOC_LEN
 	hex "Define memory for Dynamic allocation"
+	default 0x4000000 if SANDBOX
 	default 0x2000000 if ARCH_ROCKCHIP || ARCH_OMAP2PLUS || ARCH_MESON
 	default 0x200000 if ARCH_BMIPS || X86
 	default 0x120000 if MACH_SUNIV
diff --git a/arch/arm/mach-apple/board.c b/arch/arm/mach-apple/board.c
index 722dff1..ffc1301 100644
--- a/arch/arm/mach-apple/board.c
+++ b/arch/arm/mach-apple/board.c
@@ -177,6 +177,171 @@
 	}
 };
 
+/* Apple M1 Ultra */
+
+static struct mm_region t6002_mem_map[] = {
+	{
+		/* I/O */
+		.virt = 0x280000000,
+		.phys = 0x280000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x380000000,
+		.phys = 0x380000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x580000000,
+		.phys = 0x580000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x5a0000000,
+		.phys = 0x5a0000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x5c0000000,
+		.phys = 0x5c0000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x700000000,
+		.phys = 0x700000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0xb00000000,
+		.phys = 0xb00000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0xf00000000,
+		.phys = 0xf00000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x1300000000,
+		.phys = 0x1300000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2280000000,
+		.phys = 0x2280000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2380000000,
+		.phys = 0x2380000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2580000000,
+		.phys = 0x2580000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x25a0000000,
+		.phys = 0x25a0000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x25c0000000,
+		.phys = 0x25c0000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2700000000,
+		.phys = 0x2700000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2b00000000,
+		.phys = 0x2b00000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x2f00000000,
+		.phys = 0x2f00000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x3300000000,
+		.phys = 0x3300000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* RAM */
+		.virt = 0x10000000000,
+		.phys = 0x10000000000,
+		.size = 16UL * SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_INNER_SHARE
+	}, {
+		/* Framebuffer */
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* List terminator */
+		0,
+	}
+};
+
 struct mm_region *mem_map;
 
 int board_init(void)
@@ -216,6 +381,8 @@
 		mem_map = t6000_mem_map;
 	else if (of_machine_is_compatible("apple,t6001"))
 		mem_map = t6000_mem_map;
+	else if (of_machine_is_compatible("apple,t6002"))
+		mem_map = t6002_mem_map;
 	else
 		panic("Unsupported SoC\n");
 
diff --git a/arch/sandbox/include/asm/serial.h b/arch/sandbox/include/asm/serial.h
index bc82aeb..16589a1 100644
--- a/arch/sandbox/include/asm/serial.h
+++ b/arch/sandbox/include/asm/serial.h
@@ -17,6 +17,28 @@
 };
 
 /**
+ * sandbox_serial_written() - Get the total number of characters written
+ *
+ * This returns the number of characters written by the sandbox serial
+ * device. It is intended for performing tests of the serial subsystem
+ * where a console buffer cannot be used. The absolute number should not be
+ * relied upon; call this function twice and compare the difference.
+ *
+ * Return: The number of characters written
+ */
+size_t sandbox_serial_written(void);
+
+/**
+ * sandbox_serial_endisable() - Enable or disable serial output
+ * @enabled: Whether serial output should be enabled or not
+ *
+ * This allows tests to enable or disable the sandbox serial output. All
+ * processes relating to writing output (except the actual writing) will be
+ * performed.
+ */
+void sandbox_serial_endisable(bool enabled);
+
+/**
  * struct sandbox_serial_priv - Private data for this driver
  *
  * @buf: holds input characters available to be read by this driver
diff --git a/arch/sandbox/include/asm/tables.h b/arch/sandbox/include/asm/tables.h
deleted file mode 100644
index e69de29..0000000
--- a/arch/sandbox/include/asm/tables.h
+++ /dev/null
diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h
index aa93883..37be012 100644
--- a/arch/x86/include/asm/tables.h
+++ b/arch/x86/include/asm/tables.h
@@ -17,19 +17,6 @@
 #define CB_TABLE_ADDR	0x800
 
 /**
- * table_compute_checksum() - Compute a table checksum
- *
- * This computes an 8-bit checksum for the configuration table.
- * All bytes in the configuration table, including checksum itself and
- * reserved bytes must add up to zero.
- *
- * @v:		configuration table base address
- * @len:	configuration table size
- * @return:	the 8-bit checksum
- */
-u8 table_compute_checksum(void *v, int len);
-
-/**
  * table_fill_string() - Fill a string with pad in the configuration table
  *
  * This fills a string in the configuration table. It copies number of bytes
diff --git a/cmd/ubi.c b/cmd/ubi.c
index fe8ac58..fccbfdf 100644
--- a/cmd/ubi.c
+++ b/cmd/ubi.c
@@ -511,6 +511,11 @@
 	struct mtd_info *mtd;
 	int err = 0;
 
+	if (ubi && ubi->mtd && !strcmp(ubi->mtd->name, part_name)) {
+		printf("UBI partition '%s' already selected\n", part_name);
+		return 0;
+	}
+
 	ubi_detach();
 
 	mtd_probe_devices();
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 88f9ecb..a13fa2e 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x2000
 CONFIG_DEFAULT_DEVICE_TREE="sandbox64"
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index cb8d590..4d3e4f3 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x2000
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 24b2720..d799f7d 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x2000
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig
index 9eefe4f..c9430da 100644
--- a/configs/sandbox_noinst_defconfig
+++ b/configs/sandbox_noinst_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0x200000
-CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 0092fea..13a76e8 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0x200000
-CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
index 7e298db..5d7bf40 100644
--- a/drivers/led/led-uclass.c
+++ b/drivers/led/led-uclass.c
@@ -66,37 +66,56 @@
 }
 #endif
 
+/* This is superseded by led_post_bind()/led_post_probe() below. */
 int led_default_state(void)
 {
-	struct udevice *dev;
-	struct uclass *uc;
+	return 0;
+}
+
+static int led_post_bind(struct udevice *dev)
+{
+	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
 	const char *default_state;
-	int ret;
 
-	ret = uclass_get(UCLASS_LED, &uc);
-	if (ret)
-		return ret;
-	for (uclass_find_first_device(UCLASS_LED, &dev);
-	     dev;
-	     uclass_find_next_device(&dev)) {
-		default_state = dev_read_string(dev, "default-state");
-		if (!default_state)
-			continue;
-		ret = device_probe(dev);
-		if (ret)
-			return ret;
-		if (!strncmp(default_state, "on", 2))
-			led_set_state(dev, LEDST_ON);
-		else if (!strncmp(default_state, "off", 3))
-			led_set_state(dev, LEDST_OFF);
-		/* default-state = "keep" : device is only probed */
-	}
+	uc_plat->label = dev_read_string(dev, "label");
+	if (!uc_plat->label)
+		uc_plat->label = ofnode_get_name(dev_ofnode(dev));
 
-	return ret;
+	uc_plat->default_state = LEDST_COUNT;
+
+	default_state = dev_read_string(dev, "default-state");
+	if (!default_state)
+		return 0;
+
+	if (!strncmp(default_state, "on", 2))
+		uc_plat->default_state = LEDST_ON;
+	else if (!strncmp(default_state, "off", 3))
+		uc_plat->default_state = LEDST_OFF;
+	else
+		return 0;
+
+	/*
+	 * In case the LED has default-state DT property, trigger
+	 * probe() to configure its default state during startup.
+	 */
+	return device_probe(dev);
+}
+
+static int led_post_probe(struct udevice *dev)
+{
+	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+
+	if (uc_plat->default_state == LEDST_ON ||
+	    uc_plat->default_state == LEDST_OFF)
+		led_set_state(dev, uc_plat->default_state);
+
+	return 0;
 }
 
 UCLASS_DRIVER(led) = {
 	.id		= UCLASS_LED,
 	.name		= "led",
 	.per_device_plat_auto	= sizeof(struct led_uc_plat),
+	.post_bind	= led_post_bind,
+	.post_probe	= led_post_probe,
 };
diff --git a/drivers/led/led_bcm6328.c b/drivers/led/led_bcm6328.c
index bf8207d..f59a92f 100644
--- a/drivers/led/led_bcm6328.c
+++ b/drivers/led/led_bcm6328.c
@@ -204,26 +204,14 @@
 	ofnode node;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
 		struct udevice *dev;
-		const char *label;
 		int ret;
 
-		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
-
 		ret = device_bind_driver_to_node(parent, "bcm6328-led",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_bcm6358.c b/drivers/led/led_bcm6358.c
index 3e57cdf..25aa399 100644
--- a/drivers/led/led_bcm6358.c
+++ b/drivers/led/led_bcm6358.c
@@ -174,26 +174,14 @@
 	ofnode node;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
 		struct udevice *dev;
-		const char *label;
 		int ret;
 
-		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
-
 		ret = device_bind_driver_to_node(parent, "bcm6358-led",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_bcm6753.c b/drivers/led/led_bcm6753.c
index a32bd82..88b650c 100644
--- a/drivers/led/led_bcm6753.c
+++ b/drivers/led/led_bcm6753.c
@@ -229,26 +229,14 @@
 	ofnode node;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
 		struct udevice *dev;
-		const char *label;
 		int ret;
 
-		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
-
 		ret = device_bind_driver_to_node(parent, "bcm6753-led",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_bcm6858.c b/drivers/led/led_bcm6858.c
index 3ca6c5b..6b36986 100644
--- a/drivers/led/led_bcm6858.c
+++ b/drivers/led/led_bcm6858.c
@@ -241,26 +241,14 @@
 	ofnode node;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
 		struct udevice *dev;
-		const char *label;
 		int ret;
 
-		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
-
 		ret = device_bind_driver_to_node(parent, "bcm6858-led",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_cortina.c b/drivers/led/led_cortina.c
index 598c0a0..bcbe78d 100644
--- a/drivers/led/led_cortina.c
+++ b/drivers/led/led_cortina.c
@@ -256,25 +256,14 @@
 	ofnode node;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
 		struct udevice *dev;
-		const char *label;
 		int ret;
 
-		label = ofnode_read_string(node, "label");
-		if (!label) {
-			debug("%s: node %s has no label\n", __func__,
-			      ofnode_get_name(node));
-			return -EINVAL;
-		}
-
 		ret = device_bind_driver_to_node(parent, "ca-leds",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
index 67ece3c..958dbd3 100644
--- a/drivers/led/led_gpio.c
+++ b/drivers/led/led_gpio.c
@@ -95,19 +95,11 @@
 	int ret;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
-		const char *label;
-
-		label = ofnode_read_string(node, "label");
-		if (!label)
-			label = ofnode_get_name(node);
 		ret = device_bind_driver_to_node(parent, "gpio_led",
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 
 	return 0;
diff --git a/drivers/led/led_pwm.c b/drivers/led/led_pwm.c
index 4e50272..10bd163 100644
--- a/drivers/led/led_pwm.c
+++ b/drivers/led/led_pwm.c
@@ -151,21 +151,11 @@
 	int ret;
 
 	dev_for_each_subnode(node, parent) {
-		struct led_uc_plat *uc_plat;
-		const char *label;
-
-		label = ofnode_read_string(node, "label");
-		if (!label)
-			label = ofnode_get_name(node);
-
 		ret = device_bind_driver_to_node(parent, LEDS_PWM_DRIVER_NAME,
 						 ofnode_get_name(node),
 						 node, &dev);
 		if (ret)
 			return ret;
-
-		uc_plat = dev_get_uclass_plat(dev);
-		uc_plat->label = label;
 	}
 	return 0;
 }
diff --git a/drivers/misc/atsha204a-i2c.c b/drivers/misc/atsha204a-i2c.c
index b89463b..63fe541 100644
--- a/drivers/misc/atsha204a-i2c.c
+++ b/drivers/misc/atsha204a-i2c.c
@@ -146,7 +146,7 @@
 	while (len--)
 		crc = crc16_byte(crc, *buffer++);
 
-	return cpu_to_le16(crc);
+	return crc;
 }
 
 static int atsha204a_send(struct udevice *dev, const u8 *buf, u8 len)
diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c
index 677841a..1d54b75 100644
--- a/drivers/misc/qfw.c
+++ b/drivers/misc/qfw.c
@@ -15,9 +15,6 @@
 #include <dm.h>
 #include <misc.h>
 #include <tables_csum.h>
-#ifdef CONFIG_GENERATE_ACPI_TABLE
-#include <asm/tables.h>
-#endif
 
 #if defined(CONFIG_GENERATE_ACPI_TABLE) && !defined(CONFIG_SANDBOX)
 /*
diff --git a/drivers/power/domain/ti-power-domain.c b/drivers/power/domain/ti-power-domain.c
index a7dadf2..752e76b 100644
--- a/drivers/power/domain/ti-power-domain.c
+++ b/drivers/power/domain/ti-power-domain.c
@@ -16,7 +16,9 @@
 #include <linux/iopoll.h>
 
 #define PSC_PTCMD		0x120
+#define PSC_PTCMD_H		0x124
 #define PSC_PTSTAT		0x128
+#define PSC_PTSTAT_H		0x12C
 #define PSC_PDSTAT		0x200
 #define PSC_PDCTL		0x300
 #define PSC_MDSTAT		0x800
@@ -120,10 +122,17 @@
 static int ti_pd_wait(struct ti_pd *pd)
 {
 	u32 ptstat;
+	u32 pdoffset = 0;
+	u32 ptstatreg = PSC_PTSTAT;
 	int ret;
 
-	ret = readl_poll_timeout(pd->psc->base + PSC_PTSTAT, ptstat,
-				 !(ptstat & BIT(pd->id)), PD_TIMEOUT);
+	if (pd->id > 31) {
+		pdoffset = 32;
+		ptstatreg = PSC_PTSTAT_H;
+	}
+
+	ret = readl_poll_timeout(pd->psc->base + ptstatreg, ptstat,
+				 !(ptstat & BIT(pd->id - pdoffset)), PD_TIMEOUT);
 
 	if (ret)
 		printf("%s: psc%d, pd%d failed to transition.\n", __func__,
@@ -134,7 +143,15 @@
 
 static void ti_pd_transition(struct ti_pd *pd)
 {
-	psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
+	u32 pdoffset = 0;
+	u32 ptcmdreg = PSC_PTCMD;
+
+	if (pd->id > 31) {
+		pdoffset = 32;
+		ptcmdreg = PSC_PTCMD_H;
+	}
+
+	psc_write(BIT(pd->id - pdoffset), pd->psc, ptcmdreg);
 }
 
 u8 ti_pd_state(struct ti_pd *pd)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 286c998..dc514c9 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -779,6 +779,7 @@
 config SANDBOX_SERIAL
 	bool "Sandbox UART support"
 	depends on SANDBOX
+	imply SERIAL_PUTS
 	help
 	  Select this to enable a seral UART for sandbox. This is required to
 	  operate correctly, otherwise you will see no serial output from
@@ -833,6 +834,7 @@
 config SEMIHOSTING_SERIAL
 	bool "Semihosting UART support"
 	depends on SEMIHOSTING && !SERIAL_RX_BUFFER
+	imply SERIAL_PUTS
 	help
 	  Select this to enable a serial UART using semihosting. Special halt
 	  instructions will be issued which an external debugger (such as a
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index 0b1756f..e726e19 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -23,6 +23,19 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static size_t _sandbox_serial_written = 1;
+static bool sandbox_serial_enabled = true;
+
+size_t sandbox_serial_written(void)
+{
+	return _sandbox_serial_written;
+}
+
+void sandbox_serial_endisable(bool enabled)
+{
+	sandbox_serial_enabled = enabled;
+}
+
 /**
  * output_ansi_colour() - Output an ANSI colour code
  *
@@ -67,7 +80,7 @@
 	return 0;
 }
 
-static int sandbox_serial_putc(struct udevice *dev, const char ch)
+static void sandbox_print_color(struct udevice *dev)
 {
 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
 	struct sandbox_serial_plat *plat = dev_get_plat(dev);
@@ -78,14 +91,44 @@
 		priv->start_of_line = false;
 		output_ansi_colour(plat->colour);
 	}
+}
 
-	os_write(1, &ch, 1);
+static int sandbox_serial_putc(struct udevice *dev, const char ch)
+{
+	struct sandbox_serial_priv *priv = dev_get_priv(dev);
+
 	if (ch == '\n')
 		priv->start_of_line = true;
 
+	if (sandbox_serial_enabled) {
+		sandbox_print_color(dev);
+		os_write(1, &ch, 1);
+	}
+	_sandbox_serial_written += 1;
 	return 0;
 }
 
+static ssize_t sandbox_serial_puts(struct udevice *dev, const char *s,
+				   size_t len)
+{
+	struct sandbox_serial_priv *priv = dev_get_priv(dev);
+	ssize_t ret;
+
+	if (s[len - 1] == '\n')
+		priv->start_of_line = true;
+
+	if (sandbox_serial_enabled) {
+		sandbox_print_color(dev);
+		ret = os_write(1, s, len);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = len;
+	}
+	_sandbox_serial_written += ret;
+	return ret;
+}
+
 static int sandbox_serial_pending(struct udevice *dev, bool input)
 {
 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
@@ -212,6 +255,7 @@
 
 static const struct dm_serial_ops sandbox_serial_ops = {
 	.putc = sandbox_serial_putc,
+	.puts = sandbox_serial_puts,
 	.pending = sandbox_serial_pending,
 	.getc = sandbox_serial_getc,
 	.getconfig = sandbox_serial_getconfig,
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 10d6b80..30650e3 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -198,6 +198,22 @@
 	} while (err == -EAGAIN);
 }
 
+static int __serial_puts(struct udevice *dev, const char *str, size_t len)
+{
+	struct dm_serial_ops *ops = serial_get_ops(dev);
+
+	do {
+		ssize_t written = ops->puts(dev, str, len);
+
+		if (written < 0)
+			return written;
+		str += written;
+		len -= written;
+	} while (len);
+
+	return 0;
+}
+
 static void _serial_puts(struct udevice *dev, const char *str)
 {
 	struct dm_serial_ops *ops = serial_get_ops(dev);
@@ -210,19 +226,15 @@
 
 	do {
 		const char *newline = strchrnul(str, '\n');
-		size_t len = newline - str + !!*newline;
+		size_t len = newline - str;
 
-		do {
-			ssize_t written = ops->puts(dev, str, len);
+		if (__serial_puts(dev, str, len))
+			return;
 
-			if (written < 0)
-				return;
-			str += written;
-			len -= written;
-		} while (len);
+		if (*newline && __serial_puts(dev, "\r\n", 2))
+			return;
 
-		if (*newline)
-			_serial_putc(dev, '\r');
+		str += len + !!*newline;
 	} while (*str);
 }
 
diff --git a/drivers/serial/serial_semihosting.c b/drivers/serial/serial_semihosting.c
index 62b1b22..4328b3d 100644
--- a/drivers/serial/serial_semihosting.c
+++ b/drivers/serial/serial_semihosting.c
@@ -5,12 +5,14 @@
 
 #include <common.h>
 #include <dm.h>
+#include <malloc.h>
 #include <serial.h>
 #include <semihosting.h>
 
 /**
  * struct smh_serial_priv - Semihosting serial private data
  * @infd: stdin file descriptor (or error)
+ * @outfd: stdout file descriptor (or error)
  */
 struct smh_serial_priv {
 	int infd;
@@ -36,8 +38,36 @@
 	return 0;
 }
 
+static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len)
+{
+	int ret;
+	struct smh_serial_priv *priv = dev_get_priv(dev);
+	unsigned long written;
+
+	if (priv->outfd < 0) {
+		char *buf;
+
+		/* Try and avoid a copy if we can */
+		if (!s[len + 1]) {
+			smh_puts(s);
+			return len;
+		}
+
+		buf = strndup(s, len);
+		smh_puts(buf);
+		free(buf);
+		return len;
+	}
+
+	ret = smh_write(priv->outfd, s, len, &written);
+	if (written)
+		return written;
+	return ret;
+}
+
 static const struct dm_serial_ops smh_serial_ops = {
 	.putc = smh_serial_putc,
+	.puts = smh_serial_puts,
 	.getc = smh_serial_getc,
 };
 
@@ -53,6 +83,7 @@
 	struct smh_serial_priv *priv = dev_get_priv(dev);
 
 	priv->infd = smh_open(":tt", MODE_READ);
+	priv->outfd = smh_open(":tt", MODE_WRITE);
 	return 0;
 }
 
diff --git a/fs/fs.c b/fs/fs.c
index c3a2ed9..c67a1c7 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -177,7 +177,7 @@
 };
 
 static struct fstype_info fstypes[] = {
-#ifdef CONFIG_FS_FAT
+#if CONFIG_IS_ENABLED(FS_FAT)
 	{
 		.fstype = FS_TYPE_FAT,
 		.name = "fat",
@@ -267,6 +267,7 @@
 		.ln = fs_ln_unsupported,
 	},
 #endif
+#ifndef CONFIG_SPL_BUILD
 #ifdef CONFIG_CMD_UBIFS
 	{
 		.fstype = FS_TYPE_UBIFS,
@@ -286,6 +287,7 @@
 		.ln = fs_ln_unsupported,
 	},
 #endif
+#endif
 #ifdef CONFIG_FS_BTRFS
 	{
 		.fstype = FS_TYPE_BTRFS,
diff --git a/include/led.h b/include/led.h
index 8eeb5a7..43acca8 100644
--- a/include/led.h
+++ b/include/led.h
@@ -9,24 +9,6 @@
 
 struct udevice;
 
-/**
- * struct led_uc_plat - Platform data the uclass stores about each device
- *
- * @label:	LED label
- */
-struct led_uc_plat {
-	const char *label;
-};
-
-/**
- * struct led_uc_priv - Private data the uclass stores about each device
- *
- * @period_ms:	Flash period in milliseconds
- */
-struct led_uc_priv {
-	int period_ms;
-};
-
 enum led_state_t {
 	LEDST_OFF = 0,
 	LEDST_ON = 1,
@@ -38,6 +20,26 @@
 	LEDST_COUNT,
 };
 
+/**
+ * struct led_uc_plat - Platform data the uclass stores about each device
+ *
+ * @label:	LED label
+ * @default_state:	LED default state
+ */
+struct led_uc_plat {
+	const char *label;
+	enum led_state_t default_state;
+};
+
+/**
+ * struct led_uc_priv - Private data the uclass stores about each device
+ *
+ * @period_ms:	Flash period in milliseconds
+ */
+struct led_uc_priv {
+	int period_ms;
+};
+
 struct led_ops {
 	/**
 	 * set_state() - set the state of an LED
diff --git a/include/tables_csum.h b/include/tables_csum.h
index 5f7edc4..4812333 100644
--- a/include/tables_csum.h
+++ b/include/tables_csum.h
@@ -6,16 +6,17 @@
 #ifndef _TABLES_CSUM_H_
 #define _TABLES_CSUM_H_
 
-static inline u8 table_compute_checksum(void *v, int len)
-{
-	u8 *bytes = v;
-	u8 checksum = 0;
-	int i;
-
-	for (i = 0; i < len; i++)
-		checksum -= bytes[i];
-
-	return checksum;
-}
+/**
+ * table_compute_checksum() - Compute a table checksum
+ *
+ * This computes an 8-bit checksum for the configuration table.
+ * All bytes in the configuration table, including checksum itself and
+ * reserved bytes must add up to zero.
+ *
+ * @v:		configuration table base address
+ * @len:	configuration table size
+ * @return:	the 8-bit checksum
+ */
+u8 table_compute_checksum(void *v, int len);
 
 #endif
diff --git a/test/cmd/pinmux.c b/test/cmd/pinmux.c
index ba338b8..de3bb0d 100644
--- a/test/cmd/pinmux.c
+++ b/test/cmd/pinmux.c
@@ -16,7 +16,7 @@
 	/* Test that 'pinmux status <pinname>' displays the selected pin. */
 	console_record_reset();
 	run_command("pinmux status a5", 0);
-	ut_assert_nextlinen("a5        : gpio input .");
+	ut_assert_nextlinen("a5        : gpio output .");
 	ut_assert_console_end();
 
 	console_record_reset();
diff --git a/test/dm/serial.c b/test/dm/serial.c
index 0662b5f..37d17a6 100644
--- a/test/dm/serial.c
+++ b/test/dm/serial.c
@@ -7,14 +7,22 @@
 #include <log.h>
 #include <serial.h>
 #include <dm.h>
+#include <asm/serial.h>
 #include <dm/test.h>
 #include <test/test.h>
 #include <test/ut.h>
 
+static const char test_message[] =
+	"This is a test message\n"
+	"consisting of multiple lines\n";
+
 static int dm_test_serial(struct unit_test_state *uts)
 {
+	int i;
 	struct serial_device_info info_serial = {0};
 	struct udevice *dev_serial;
+	size_t start, putc_written;
+
 	uint value_serial;
 
 	ut_assertok(uclass_get_device_by_name(UCLASS_SERIAL, "serial",
@@ -66,6 +74,17 @@
 						   SERIAL_8_BITS,
 						   SERIAL_TWO_STOP)));
 
+	/* Verify that putc and puts print the same number of characters */
+	sandbox_serial_endisable(false);
+	start = sandbox_serial_written();
+	for (i = 0; i < sizeof(test_message) - 1; i++)
+		serial_putc(test_message[i]);
+	putc_written = sandbox_serial_written();
+	serial_puts(test_message);
+	sandbox_serial_endisable(true);
+	ut_asserteq(putc_written - start,
+		    sandbox_serial_written() - putc_written);
+
 	return 0;
 }