[U-Boot] [PATCH 3/4] Board: stm32mp1: Add supply current boot information

Patrice Chotard patrice.chotard at st.com
Tue Feb 12 15:50:40 UTC 2019


For DK1/DK2 boards, check if power supply provides enough current
to allow the board to boot correctly.
ADC at 0 channel 18 and 19 are connected to USB type-C CC1 and CC2
signals. The table below shows the behavior for different range of
CC1 or CC2:

  range       | power supply | red led |          console message
  (Volts)     |   (Amps)     | blinks  |
--------------|--------------|---------|-----------------------------------
[2.10 - 1.23[ |     3        |   NO    |    NO
[1.23 - 0.66[ |     1.5      | 3 times | WARNING 1.5A power supply detected
[0.66 - 0]    |     0.5      | 2 times | WARNING 500mA power supply detected

If detected current is < 3A, red led is kept ON after blinking.

Signed-off-by: Patrice Chotard <patrice.chotard at st.com>
---

 board/st/stm32mp1/stm32mp1.c | 154 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index 07d1addb2a83..253094e6b418 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -2,9 +2,10 @@
 /*
  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
  */
+#include <common.h>
+#include <adc.h>
 #include <config.h>
 #include <clk.h>
-#include <common.h>
 #include <dm.h>
 #include <generic-phy.h>
 #include <led.h>
@@ -27,6 +28,10 @@ DECLARE_GLOBAL_DATA_PTR;
 #define STM32MP_GGPIO 0x38
 #define STM32MP_GGPIO_VBUS_SENSING BIT(21)
 
+#define USB_WARNING_LOW_THRESHOLD_UV	660000
+#define USB_START_LOW_THRESHOLD_UV	1230000
+#define USB_START_HIGH_THRESHOLD_UV	2100000
+
 int checkboard(void)
 {
 	int ret;
@@ -210,6 +215,145 @@ clk_err:
 	return ret;
 }
 
+static int get_led(struct udevice **dev, char *led_string)
+{
+	char *led_name;
+	int ret;
+
+	led_name = fdtdec_get_config_string(gd->fdt_blob, led_string);
+	if (!led_name) {
+		pr_debug("%s: could not find %s config string\n",
+			 __func__, led_string);
+		return -ENOENT;
+	}
+	ret = led_get_by_label(led_name, dev);
+	if (ret) {
+		debug("%s: get=%d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int setup_led(enum led_state_t cmd)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = get_led(&dev, "u-boot,boot-led");
+	if (ret)
+		return ret;
+
+	ret = led_set_state(dev, cmd);
+	return ret;
+}
+
+static int board_check_usb_power(void)
+{
+	struct ofnode_phandle_args adc_args;
+	struct udevice *adc;
+	struct udevice *led;
+	ofnode node;
+	unsigned int raw;
+	int max_uV = 0;
+	int ret, uV, adc_count;
+	u8 i, nb_blink;
+
+	node = ofnode_path("/config");
+	if (!ofnode_valid(node)) {
+		debug("%s: no /config node?\n", __func__);
+		return -ENOENT;
+	}
+
+	/*
+	 * Retrieve the ADC channels devices and get measurement
+	 * for each of them
+	 */
+	adc_count = ofnode_count_phandle_with_args(node, "st,adc_usb_pd",
+						   "#io-channel-cells");
+	if (adc_count < 0) {
+		if (adc_count == -ENOENT)
+			return 0;
+
+		pr_err("%s: can't find adc channel (%d)\n", __func__,
+		       adc_count);
+
+		return adc_count;
+	}
+
+	for (i = 0; i < adc_count; i++) {
+		if (ofnode_parse_phandle_with_args(node, "st,adc_usb_pd",
+						   "#io-channel-cells", 0, i,
+						   &adc_args)) {
+			pr_debug("%s: can't find /config/st,adc_usb_pd\n",
+				 __func__);
+			return 0;
+		}
+
+		ret = uclass_get_device_by_ofnode(UCLASS_ADC, adc_args.node,
+						  &adc);
+
+		if (ret) {
+			pr_err("%s: Can't get adc device(%d)\n", __func__,
+			       ret);
+			return ret;
+		}
+
+		ret = adc_channel_single_shot(adc->name, adc_args.args[0],
+					      &raw);
+		if (ret) {
+			pr_err("%s: single shot failed for %s[%d]!\n",
+			       __func__, adc->name, adc_args.args[0]);
+			return ret;
+		}
+		/* Convert to uV */
+		if (!adc_raw_to_uV(adc, raw, &uV)) {
+			if (uV > max_uV)
+				max_uV = uV;
+			pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__,
+				 adc->name, adc_args.args[0], raw, uV);
+		} else {
+			pr_err("%s: Can't get uV value for %s[%d]\n",
+			       __func__, adc->name, adc_args.args[0]);
+		}
+	}
+
+	/*
+	 * If highest value is inside 1.23 Volts and 2.10 Volts, that means
+	 * board is plugged on an USB-C 3A power supply and boot process can
+	 * continue.
+	 */
+	if (max_uV > USB_START_LOW_THRESHOLD_UV &&
+	    max_uV < USB_START_HIGH_THRESHOLD_UV)
+		return 0;
+
+	/* Display warning message and make u-boot,error-led blinking */
+	pr_err("\n*******************************************\n");
+
+	if (max_uV < USB_WARNING_LOW_THRESHOLD_UV) {
+		pr_err("*   WARNING 500mA power supply detected   *\n");
+		nb_blink = 2;
+	} else {
+		pr_err("* WARNING 1.5A power supply detected      *\n");
+		nb_blink = 3;
+	}
+
+	pr_err("* Current too low, use a 3A power supply! *\n");
+	pr_err("*******************************************\n\n");
+
+	ret = get_led(&led, "u-boot,error-led");
+	if (ret)
+		return ret;
+
+	for (i = 0; i < nb_blink * 2; i++) {
+		led_set_state(led, LEDST_TOGGLE);
+		mdelay(125);
+	}
+	led_set_state(led, LEDST_ON);
+
+	return 0;
+}
+
 int board_usb_cleanup(int index, enum usb_init_type init)
 {
 	/* Reset usbotg */
@@ -234,5 +378,13 @@ int board_init(void)
 	if (IS_ENABLED(CONFIG_LED))
 		led_default_state();
 
+	/* for DK1/DK2 boards */
+	board_check_usb_power();
+
 	return 0;
 }
+
+void board_quiesce_devices(void)
+{
+	setup_led(LEDST_OFF);
+}
-- 
1.9.1



More information about the U-Boot mailing list