Merge branch '2022-04-28-led-updates'

- DM GPIO bugfix
- LED related code clean-ups
- Fix some of the DM/LED tests
- Update the LED dt binding doc
diff --git a/board/aristainetos/aristainetos.c b/board/aristainetos/aristainetos.c
index 19af596..514cb60 100644
--- a/board/aristainetos/aristainetos.c
+++ b/board/aristainetos/aristainetos.c
@@ -418,7 +418,6 @@
 	int x, y;
 	int ret;
 
-	led_default_state();
 	splash_get_pos(&x, &y);
 	bmp_display((ulong)&bmp_logo_bitmap[0], x, y);
 
diff --git a/board/bosch/guardian/board.c b/board/bosch/guardian/board.c
index 105b75e..68f2744 100644
--- a/board/bosch/guardian/board.c
+++ b/board/bosch/guardian/board.c
@@ -327,9 +327,6 @@
 	int ret;
 	struct udevice *cdev;
 
-#ifdef CONFIG_LED_GPIO
-	led_default_state();
-#endif
 	set_bootmode_env();
 
 	ret = uclass_get_device(UCLASS_PANEL, 0, &cdev);
diff --git a/board/dhelectronics/dh_stm32mp1/board.c b/board/dhelectronics/dh_stm32mp1/board.c
index f44afb0..67273f9 100644
--- a/board/dhelectronics/dh_stm32mp1/board.c
+++ b/board/dhelectronics/dh_stm32mp1/board.c
@@ -607,9 +607,6 @@
 
 	board_init_fmc2();
 
-	if (CONFIG_IS_ENABLED(LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/gardena/smart-gateway-at91sam/board.c b/board/gardena/smart-gateway-at91sam/board.c
index 3f402cf..c6eb11e 100644
--- a/board/gardena/smart-gateway-at91sam/board.c
+++ b/board/gardena/smart-gateway-at91sam/board.c
@@ -24,9 +24,6 @@
 {
 	at91_prepare_cpu_var();
 
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/gardena/smart-gateway-mt7688/board.c b/board/gardena/smart-gateway-mt7688/board.c
index 8a3a6e3..aa833a0 100644
--- a/board/gardena/smart-gateway-mt7688/board.c
+++ b/board/gardena/smart-gateway-mt7688/board.c
@@ -183,9 +183,6 @@
 
 int board_late_init(void)
 {
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	factory_data_env_config();
 
 	return 0;
diff --git a/board/gateworks/venice/venice.c b/board/gateworks/venice/venice.c
index 4290a69..f1efabb 100644
--- a/board/gateworks/venice/venice.c
+++ b/board/gateworks/venice/venice.c
@@ -128,8 +128,6 @@
 	u8 enetaddr[6];
 	char fdt[64];
 
-	led_default_state();
-
 	/* Set board serial/model */
 	if (!env_get("serial#"))
 		env_set_ulong("serial#", eeprom_get_serial());
diff --git a/board/k+p/kp_imx6q_tpc/kp_imx6q_tpc.c b/board/k+p/kp_imx6q_tpc/kp_imx6q_tpc.c
index 110496d..e6877e4 100644
--- a/board/k+p/kp_imx6q_tpc/kp_imx6q_tpc.c
+++ b/board/k+p/kp_imx6q_tpc/kp_imx6q_tpc.c
@@ -137,9 +137,6 @@
 	add_board_boot_modes(board_boot_modes);
 #endif
 
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	env_set("boardname", "kp-tpc");
 	env_set("boardsoc", "imx6q");
 	return 0;
diff --git a/board/mscc/jr2/jr2.c b/board/mscc/jr2/jr2.c
index 1c516aa..6abf08b 100644
--- a/board/mscc/jr2/jr2.c
+++ b/board/mscc/jr2/jr2.c
@@ -30,10 +30,6 @@
 	/* Address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
 
-	/* LED setup */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/mscc/luton/luton.c b/board/mscc/luton/luton.c
index 038902d..76e3f2e 100644
--- a/board/mscc/luton/luton.c
+++ b/board/mscc/luton/luton.c
@@ -31,10 +31,6 @@
 	/* Address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
 
-	/* LED setup */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/mscc/ocelot/ocelot.c b/board/mscc/ocelot/ocelot.c
index c462890..2a75ec2 100644
--- a/board/mscc/ocelot/ocelot.c
+++ b/board/mscc/ocelot/ocelot.c
@@ -79,10 +79,6 @@
 	/* Address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
 
-	/* LED setup */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/mscc/serval/serval.c b/board/mscc/serval/serval.c
index 94c1c42..87e7907 100644
--- a/board/mscc/serval/serval.c
+++ b/board/mscc/serval/serval.c
@@ -24,10 +24,6 @@
 	/* Address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
 
-	/* LED setup */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/mscc/servalt/servalt.c b/board/mscc/servalt/servalt.c
index 252d8e3..bd8c7e8 100644
--- a/board/mscc/servalt/servalt.c
+++ b/board/mscc/servalt/servalt.c
@@ -24,10 +24,6 @@
 	/* Address of boot parameters */
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
 
-	/* LED setup */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/phytec/pcm052/pcm052.c b/board/phytec/pcm052/pcm052.c
index f9cf4ab..0f72359 100644
--- a/board/phytec/pcm052/pcm052.c
+++ b/board/phytec/pcm052/pcm052.c
@@ -360,9 +360,6 @@
 	struct src *psrc = (struct src *)SRC_BASE_ADDR;
 	u32 reg;
 
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	/*
 	 * BK4r1 handle emergency/service SD card boot
 	 * Checking the SBMR1 register BOOTCFG1 byte:
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index 28ad6ef..e054f30 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -107,9 +107,6 @@
 
 int board_init(void)
 {
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	return 0;
 }
 
diff --git a/board/siemens/capricorn/board.c b/board/siemens/capricorn/board.c
index dcbab8e..4a02d64 100644
--- a/board/siemens/capricorn/board.c
+++ b/board/siemens/capricorn/board.c
@@ -244,10 +244,6 @@
 	u8 pca_led[2] = { 0x00, 0x00 };
 	int ret;
 
-	/* init all GPIO LED's */
-	if (IS_ENABLED(CONFIG_LED))
-		led_default_state();
-
 	/* enable all leds on PCA9552 */
 	ret = uclass_get_device_by_seq(UCLASS_I2C, PCA9552_1_I2C_BUS, &bus);
 	if (ret) {
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index fff1880..7466e1c 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -666,9 +666,6 @@
 	if (IS_ENABLED(CONFIG_ARMV7_NONSEC))
 		sysconf_init();
 
-	if (CONFIG_IS_ENABLED(LED))
-		led_default_state();
-
 	setup_led(LEDST_ON);
 
 	return 0;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index e09c12f..17dd120 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -361,6 +361,28 @@
 }
 #endif
 
+static int dm_probe_devices(struct udevice *dev, bool pre_reloc_only)
+{
+	u32 mask = DM_FLAG_PROBE_AFTER_BIND;
+	u32 flags = dev_get_flags(dev);
+	struct udevice *child;
+	int ret;
+
+	if (pre_reloc_only)
+		mask |= DM_FLAG_PRE_RELOC;
+
+	if ((flags & mask) == mask) {
+		ret = device_probe(dev);
+		if (ret)
+			return ret;
+	}
+
+	list_for_each_entry(child, &dev->child_head, sibling_node)
+		dm_probe_devices(child, pre_reloc_only);
+
+	return 0;
+}
+
 /**
  * dm_scan() - Scan tables to bind devices
  *
@@ -393,7 +415,7 @@
 	if (ret)
 		return ret;
 
-	return 0;
+	return dm_probe_devices(gd->dm_root, pre_reloc_only);
 }
 
 int dm_init_and_scan(bool pre_reloc_only)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
index 5d7bf40..68ca3c2 100644
--- a/drivers/led/led-uclass.c
+++ b/drivers/led/led-uclass.c
@@ -66,12 +66,6 @@
 }
 #endif
 
-/* This is superseded by led_post_bind()/led_post_probe() below. */
-int led_default_state(void)
-{
-	return 0;
-}
-
 static int led_post_bind(struct udevice *dev)
 {
 	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
@@ -98,7 +92,9 @@
 	 * In case the LED has default-state DT property, trigger
 	 * probe() to configure its default state during startup.
 	 */
-	return device_probe(dev);
+	dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
+	return 0;
 }
 
 static int led_post_probe(struct udevice *dev)
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
index 958dbd3..fbed151 100644
--- a/drivers/led/led_gpio.c
+++ b/drivers/led/led_gpio.c
@@ -57,19 +57,9 @@
 
 static int led_gpio_probe(struct udevice *dev)
 {
-	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
 	struct led_gpio_priv *priv = dev_get_priv(dev);
-	int ret;
 
-	/* Ignore the top-level LED node */
-	if (!uc_plat->label)
-		return 0;
-
-	ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
-	if (ret)
-		return ret;
-
-	return 0;
+	return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
 }
 
 static int led_gpio_remove(struct udevice *dev)
@@ -110,18 +100,23 @@
 	.get_state	= gpio_led_get_state,
 };
 
+U_BOOT_DRIVER(led_gpio) = {
+	.name	= "gpio_led",
+	.id	= UCLASS_LED,
+	.ops	= &gpio_led_ops,
+	.priv_auto	= sizeof(struct led_gpio_priv),
+	.probe	= led_gpio_probe,
+	.remove	= led_gpio_remove,
+};
+
 static const struct udevice_id led_gpio_ids[] = {
 	{ .compatible = "gpio-leds" },
 	{ }
 };
 
-U_BOOT_DRIVER(led_gpio) = {
-	.name	= "gpio_led",
-	.id	= UCLASS_LED,
+U_BOOT_DRIVER(led_gpio_wrap) = {
+	.name	= "gpio_led_wrap",
+	.id	= UCLASS_NOP,
 	.of_match = led_gpio_ids,
-	.ops	= &gpio_led_ops,
-	.priv_auto	= sizeof(struct led_gpio_priv),
 	.bind	= led_gpio_bind,
-	.probe	= led_gpio_probe,
-	.remove	= led_gpio_remove,
 };
diff --git a/include/dm/device.h b/include/dm/device.h
index b474888..5bdb106 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -80,6 +80,9 @@
  */
 #define DM_FLAG_VITAL			(1 << 14)
 
+/* Device must be probed after it was bound */
+#define DM_FLAG_PROBE_AFTER_BIND	(1 << 15)
+
 /*
  * One or multiple of these flags are passed to device_remove() so that
  * a selective device removal as specified by the remove-stage and the
diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h
index 9e1256a..3be89a7 100644
--- a/include/dt-bindings/leds/common.h
+++ b/include/dt-bindings/leds/common.h
@@ -6,6 +6,7 @@
  * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * Copyright (C) 2019 Jacek Anaszewski <jacek.anaszewski@gmail.com>
+ * Copyright (C) 2020 Pavel Machek <pavel@ucw.cz>
  */
 
 #ifndef __DT_BINDINGS_LEDS_H
@@ -29,19 +30,51 @@
 #define LED_COLOR_ID_VIOLET	5
 #define LED_COLOR_ID_YELLOW	6
 #define LED_COLOR_ID_IR		7
-#define LED_COLOR_ID_MAX	8
+#define LED_COLOR_ID_MULTI	8	/* For multicolor LEDs */
+#define LED_COLOR_ID_RGB	9	/* For multicolor LEDs that can do arbitrary color,
+					   so this would include RGBW and similar */
+#define LED_COLOR_ID_MAX	10
 
 /* Standard LED functions */
+/* Keyboard LEDs, usually it would be input4::capslock etc. */
+/*   Obsolete equivalent: "shift-key-light" */
+#define LED_FUNCTION_CAPSLOCK "capslock"
+#define LED_FUNCTION_SCROLLLOCK "scrolllock"
+#define LED_FUNCTION_NUMLOCK "numlock"
+/*   Obsolete equivalents: "tpacpi::thinklight" (IBM/Lenovo Thinkpads),
+     "lp5523:kb{1,2,3,4,5,6}" (Nokia N900) */
+#define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight"
+
+/* System LEDs, usually found on system body.
+   platform::mute (etc) is sometimes seen, :mute would be better */
+#define LED_FUNCTION_POWER "power"
+#define LED_FUNCTION_DISK "disk"
+
+/*   Obsolete: "platform:*:charging" (allwinner sun50i) */
+#define LED_FUNCTION_CHARGING "charging"
+/*   Used RGB notification LEDs common on phones.
+     Obsolete equivalents: "status-led:{red,green,blue}" (Motorola Droid 4),
+     "lp5523:{r,g,b}" (Nokia N900) */
+#define LED_FUNCTION_STATUS "status"
+
+#define LED_FUNCTION_MICMUTE "micmute"
+#define LED_FUNCTION_MUTE "mute"
+
+/* Used for player LEDs as found on game controllers from e.g. Nintendo, Sony. */
+#define LED_FUNCTION_PLAYER1 "player-1"
+#define LED_FUNCTION_PLAYER2 "player-2"
+#define LED_FUNCTION_PLAYER3 "player-3"
+#define LED_FUNCTION_PLAYER4 "player-4"
+#define LED_FUNCTION_PLAYER5 "player-5"
+
+/* Miscelleaus functions. Use functions above if you can. */
 #define LED_FUNCTION_ACTIVITY "activity"
 #define LED_FUNCTION_ALARM "alarm"
 #define LED_FUNCTION_BACKLIGHT "backlight"
 #define LED_FUNCTION_BLUETOOTH "bluetooth"
 #define LED_FUNCTION_BOOT "boot"
 #define LED_FUNCTION_CPU "cpu"
-#define LED_FUNCTION_CAPSLOCK "capslock"
-#define LED_FUNCTION_CHARGING "charging"
 #define LED_FUNCTION_DEBUG "debug"
-#define LED_FUNCTION_DISK "disk"
 #define LED_FUNCTION_DISK_ACTIVITY "disk-activity"
 #define LED_FUNCTION_DISK_ERR "disk-err"
 #define LED_FUNCTION_DISK_READ "disk-read"
@@ -50,21 +83,14 @@
 #define LED_FUNCTION_FLASH "flash"
 #define LED_FUNCTION_HEARTBEAT "heartbeat"
 #define LED_FUNCTION_INDICATOR "indicator"
-#define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight"
 #define LED_FUNCTION_LAN "lan"
 #define LED_FUNCTION_MAIL "mail"
 #define LED_FUNCTION_MTD "mtd"
-#define LED_FUNCTION_MICMUTE "micmute"
-#define LED_FUNCTION_MUTE "mute"
-#define LED_FUNCTION_NUMLOCK "numlock"
 #define LED_FUNCTION_PANIC "panic"
 #define LED_FUNCTION_PROGRAMMING "programming"
-#define LED_FUNCTION_POWER "power"
 #define LED_FUNCTION_RX "rx"
 #define LED_FUNCTION_SD "sd"
-#define LED_FUNCTION_SCROLLLOCK "scrolllock"
 #define LED_FUNCTION_STANDBY "standby"
-#define LED_FUNCTION_STATUS "status"
 #define LED_FUNCTION_TORCH "torch"
 #define LED_FUNCTION_TX "tx"
 #define LED_FUNCTION_USB "usb"
diff --git a/include/led.h b/include/led.h
index 43acca8..3290410 100644
--- a/include/led.h
+++ b/include/led.h
@@ -110,13 +110,4 @@
  */
 int led_set_period(struct udevice *dev, int period_ms);
 
-/**
- * led_default_state() - set the default state for all the LED
- *
- * This enables all leds which have default state.
- * see Documentation/devicetree/bindings/leds/common.txt
- *
- */
-int led_default_state(void);
-
 #endif
diff --git a/test/cmd/pinmux.c b/test/cmd/pinmux.c
index de3bb0d..df40bb7 100644
--- a/test/cmd/pinmux.c
+++ b/test/cmd/pinmux.c
@@ -7,12 +7,17 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <dm/test.h>
 #include <test/test.h>
 #include <test/ut.h>
 
 static int dm_test_cmd_pinmux_status_pinname(struct unit_test_state *uts)
 {
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev));
+
 	/* Test that 'pinmux status <pinname>' displays the selected pin. */
 	console_record_reset();
 	run_command("pinmux status a5", 0);
diff --git a/test/dm/led.c b/test/dm/led.c
index ac6ee36..eed3f46 100644
--- a/test/dm/led.c
+++ b/test/dm/led.c
@@ -21,8 +21,7 @@
 	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
 	ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev));
 	ut_assertok(uclass_get_device(UCLASS_LED, 3, &dev));
-	ut_assertok(uclass_get_device(UCLASS_LED, 4, &dev));
-	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 5, &dev));
+	ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 4, &dev));
 
 	return 0;
 }
@@ -33,9 +32,6 @@
 {
 	struct udevice *dev;
 
-	/* configure the default state (auto-probe) */
-	led_default_state();
-
 	/* Check that we handle the default-state property correctly. */
 	ut_assertok(led_get_by_label("sandbox:default_on", &dev));
 	ut_asserteq(LEDST_ON, led_get_state(dev));
@@ -55,10 +51,10 @@
 	struct udevice *dev, *gpio;
 
 	/*
-	 * Check that we can manipulate an LED. LED 1 is connected to GPIO
+	 * Check that we can manipulate an LED. LED 0 is connected to GPIO
 	 * bank gpio_a, offset 1.
 	 */
-	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
 	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
 	ut_assertok(led_set_state(dev, LEDST_ON));
@@ -80,10 +76,10 @@
 	struct udevice *dev, *gpio;
 
 	/*
-	 * Check that we can manipulate an LED. LED 1 is connected to GPIO
+	 * Check that we can manipulate an LED. LED 0 is connected to GPIO
 	 * bank gpio_a, offset 1.
 	 */
-	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
 	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
 	ut_assertok(led_set_state(dev, LEDST_TOGGLE));
@@ -105,12 +101,12 @@
 
 	ut_assertok(led_get_by_label("sandbox:red", &dev));
 	ut_asserteq(1, device_active(dev));
-	ut_assertok(uclass_get_device(UCLASS_LED, 1, &cmp));
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &cmp));
 	ut_asserteq_ptr(dev, cmp);
 
 	ut_assertok(led_get_by_label("sandbox:green", &dev));
 	ut_asserteq(1, device_active(dev));
-	ut_assertok(uclass_get_device(UCLASS_LED, 2, &cmp));
+	ut_assertok(uclass_get_device(UCLASS_LED, 1, &cmp));
 	ut_asserteq_ptr(dev, cmp);
 
 	ut_asserteq(-ENODEV, led_get_by_label("sandbox:blue", &dev));
@@ -130,7 +126,7 @@
 	 * Check that we get an error when trying to blink an LED, since it is
 	 * not supported by the GPIO LED driver.
 	 */
-	ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
 	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
 	ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
 	ut_asserteq(-ENOSYS, led_set_state(dev, LEDST_BLINK));