board: stm32mp1: board: add include for dfu
[oweals/u-boot.git] / board / st / stm32mp1 / stm32mp1.c
index 360b0df9f6bcc8c2db0e056f9d5464ea9bd5c376..1b8ad1ef5315ef655fad9ba67e246612460934be 100644 (file)
@@ -4,21 +4,37 @@
  */
 #include <common.h>
 #include <adc.h>
-#include <config.h>
+#include <bootm.h>
 #include <clk.h>
+#include <config.h>
+#include <dfu.h>
 #include <dm.h>
+#include <env.h>
+#include <env_internal.h>
 #include <g_dnl.h>
 #include <generic-phy.h>
+#include <hang.h>
 #include <i2c.h>
+#include <init.h>
 #include <led.h>
+#include <malloc.h>
+#include <memalign.h>
 #include <misc.h>
+#include <mtd.h>
+#include <mtd_node.h>
+#include <netdev.h>
 #include <phy.h>
+#include <remoteproc.h>
 #include <reset.h>
 #include <syscon.h>
 #include <usb.h>
+#include <watchdog.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <asm/arch/stm32.h>
+#include <asm/arch/sys_proto.h>
+#include <jffs2/load_kernel.h>
+#include <linux/err.h>
 #include <power/regulator.h>
 #include <usb/dwc2_udc.h>
 
 #define SYSCFG_PMCSETR_ETH_SELMII      BIT(20)
 
 #define SYSCFG_PMCSETR_ETH_SEL_MASK    GENMASK(23, 21)
-#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII        (0 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RGMII   (1 << 21)
-#define SYSCFG_PMCSETR_ETH_SEL_RMII    (4 << 21)
+#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII        0
+#define SYSCFG_PMCSETR_ETH_SEL_RGMII   BIT(21)
+#define SYSCFG_PMCSETR_ETH_SEL_RMII    BIT(23)
 
 /*
  * Get a global data pointer
  */
 DECLARE_GLOBAL_DATA_PTR;
 
+#define USB_LOW_THRESHOLD_UV           200000
 #define USB_WARNING_LOW_THRESHOLD_UV   660000
 #define USB_START_LOW_THRESHOLD_UV     1230000
-#define USB_START_HIGH_THRESHOLD_UV    2100000
+#define USB_START_HIGH_THRESHOLD_UV    2150000
 
 int checkboard(void)
 {
@@ -73,7 +90,9 @@ int checkboard(void)
        const char *fdt_compat;
        int fdt_compat_len;
 
-       if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
+       if (IS_ENABLED(CONFIG_STM32MP1_OPTEE))
+               mode = "trusted with OP-TEE";
+       else if (IS_ENABLED(CONFIG_STM32MP1_TRUSTED))
                mode = "trusted";
        else
                mode = "basic";
@@ -92,7 +111,7 @@ int checkboard(void)
        if (!ret)
                ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
                                &otp, sizeof(otp));
-       if (!ret && otp) {
+       if (ret > 0 && otp) {
                printf("Board: MB%04x Var%d Rev.%c-%02d\n",
                       otp >> 16,
                       (otp >> 12) & 0xF,
@@ -220,8 +239,26 @@ int g_dnl_board_usb_cable_connected(void)
 
        return dwc2_udc_B_session_valid(dwc2_udc_otg);
 }
+
+#define STM32MP1_G_DNL_DFU_PRODUCT_NUM 0xdf11
+#define STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM 0x0afb
+
+int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
+{
+       if (!strcmp(name, "usb_dnl_dfu"))
+               put_unaligned(STM32MP1_G_DNL_DFU_PRODUCT_NUM, &dev->idProduct);
+       else if (!strcmp(name, "usb_dnl_fastboot"))
+               put_unaligned(STM32MP1_G_DNL_FASTBOOT_PRODUCT_NUM,
+                             &dev->idProduct);
+       else
+               put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct);
+
+       return 0;
+}
+
 #endif /* CONFIG_USB_GADGET */
 
+#ifdef CONFIG_LED
 static int get_led(struct udevice **dev, char *led_string)
 {
        char *led_name;
@@ -254,18 +291,49 @@ static int setup_led(enum led_state_t cmd)
        ret = led_set_state(dev, cmd);
        return ret;
 }
+#endif
+
+static void __maybe_unused led_error_blink(u32 nb_blink)
+{
+#ifdef CONFIG_LED
+       int ret;
+       struct udevice *led;
+       u32 i;
+#endif
+
+       if (!nb_blink)
+               return;
+
+#ifdef CONFIG_LED
+       ret = get_led(&led, "u-boot,error-led");
+       if (!ret) {
+               /* make u-boot,error-led blinking */
+               /* if U32_MAX and 125ms interval, for 17.02 years */
+               for (i = 0; i < 2 * nb_blink; i++) {
+                       led_set_state(led, LEDST_TOGGLE);
+                       mdelay(125);
+                       WATCHDOG_RESET();
+               }
+       }
+#endif
+
+       /* infinite: the boot process must be stopped */
+       if (nb_blink == U32_MAX)
+               hang();
+}
 
+#ifdef CONFIG_ADC
 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 min_uV = USB_START_HIGH_THRESHOLD_UV;
        int ret, uV, adc_count;
-       u8 i, nb_blink;
-
+       u32 nb_blink;
+       u8 i;
        node = ofnode_path("/config");
        if (!ofnode_valid(node)) {
                debug("%s: no /config node?\n", __func__);
@@ -317,6 +385,8 @@ static int board_check_usb_power(void)
                if (!adc_raw_to_uV(adc, raw, &uV)) {
                        if (uV > max_uV)
                                max_uV = uV;
+                       if (uV < min_uV)
+                               min_uV = uV;
                        pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__,
                                 adc->name, adc_args.args[0], raw, uV);
                } else {
@@ -331,35 +401,62 @@ static int board_check_usb_power(void)
         * continue.
         */
        if (max_uV > USB_START_LOW_THRESHOLD_UV &&
-           max_uV < USB_START_HIGH_THRESHOLD_UV)
+           max_uV <= USB_START_HIGH_THRESHOLD_UV &&
+           min_uV <= USB_LOW_THRESHOLD_UV)
                return 0;
 
-       /* Display warning message and make u-boot,error-led blinking */
-       pr_err("\n*******************************************\n");
+       pr_err("****************************************************\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;
+       /*
+        * If highest and lowest value are either both below
+        * USB_LOW_THRESHOLD_UV or both above USB_LOW_THRESHOLD_UV, that
+        * means USB TYPE-C is in unattached mode, this is an issue, make
+        * u-boot,error-led blinking and stop boot process.
+        */
+       if ((max_uV > USB_LOW_THRESHOLD_UV &&
+            min_uV > USB_LOW_THRESHOLD_UV) ||
+            (max_uV <= USB_LOW_THRESHOLD_UV &&
+            min_uV <= USB_LOW_THRESHOLD_UV)) {
+               pr_err("* ERROR USB TYPE-C connection in unattached mode   *\n");
+               pr_err("* Check that USB TYPE-C cable is correctly plugged *\n");
+               /* with 125ms interval, led will blink for 17.02 years ....*/
+               nb_blink = U32_MAX;
        }
 
-       pr_err("* Current too low, use a 3A power supply! *\n");
-       pr_err("*******************************************\n\n");
+       if (max_uV > USB_LOW_THRESHOLD_UV &&
+           max_uV <= USB_WARNING_LOW_THRESHOLD_UV &&
+           min_uV <= USB_LOW_THRESHOLD_UV) {
+               pr_err("*        WARNING 500mA power supply detected       *\n");
+               nb_blink = 2;
+       }
 
-       ret = get_led(&led, "u-boot,error-led");
-       if (ret)
-               return ret;
+       if (max_uV > USB_WARNING_LOW_THRESHOLD_UV &&
+           max_uV <= USB_START_LOW_THRESHOLD_UV &&
+           min_uV <= USB_LOW_THRESHOLD_UV) {
+               pr_err("*       WARNING 1.5mA power supply detected        *\n");
+               nb_blink = 3;
+       }
 
-       for (i = 0; i < nb_blink * 2; i++) {
-               led_set_state(led, LEDST_TOGGLE);
-               mdelay(125);
+       /*
+        * If highest value is above 2.15 Volts that means that the USB TypeC
+        * supplies more than 3 Amp, this is not compliant with TypeC specification
+        */
+       if (max_uV > USB_START_HIGH_THRESHOLD_UV) {
+               pr_err("*      USB TYPE-C charger not compliant with       *\n");
+               pr_err("*                   specification                  *\n");
+               pr_err("****************************************************\n\n");
+               /* with 125ms interval, led will blink for 17.02 years ....*/
+               nb_blink = U32_MAX;
+       } else {
+               pr_err("*     Current too low, use a 3A power supply!      *\n");
+               pr_err("****************************************************\n\n");
        }
-       led_set_state(led, LEDST_ON);
+
+       led_error_blink(nb_blink);
 
        return 0;
 }
+#endif /* CONFIG_ADC */
 
 static void sysconf_init(void)
 {
@@ -402,7 +499,9 @@ static void sysconf_init(void)
         *   => U-Boot set the register only if VDD < 2.7V (in DT)
         *      but this value need to be consistent with board design
         */
-       ret = syscon_get_by_driver_data(STM32MP_SYSCON_PWR, &pwr_dev);
+       ret = uclass_get_device_by_driver(UCLASS_PMIC,
+                                         DM_GET_DRIVER(stm32mp_pwr_pmic),
+                                         &pwr_dev);
        if (!ret) {
                ret = uclass_get_device_by_driver(UCLASS_MISC,
                                                  DM_GET_DRIVER(stm32mp_bsec),
@@ -413,11 +512,11 @@ static void sysconf_init(void)
                }
 
                ret = misc_read(dev, STM32_BSEC_SHADOW(18), &otp, 4);
-               if (!ret)
+               if (ret > 0)
                        otp = otp & BIT(13);
 
-               /* get VDD = pwr-supply */
-               ret = device_get_supply_regulator(pwr_dev, "pwr-supply",
+               /* get VDD = vdd-supply */
+               ret = device_get_supply_regulator(pwr_dev, "vdd-supply",
                                                  &pwr_reg);
 
                /* check if VDD is Low Voltage */
@@ -453,6 +552,73 @@ static void sysconf_init(void)
 #endif
 }
 
+#ifdef CONFIG_DM_REGULATOR
+/* Fix to make I2C1 usable on DK2 for touchscreen usage in kernel */
+static int dk2_i2c1_fix(void)
+{
+       ofnode node;
+       struct gpio_desc hdmi, audio;
+       int ret = 0;
+
+       node = ofnode_path("/soc/i2c@40012000/hdmi-transmitter@39");
+       if (!ofnode_valid(node)) {
+               pr_debug("%s: no hdmi-transmitter@39 ?\n", __func__);
+               return -ENOENT;
+       }
+
+       if (gpio_request_by_name_nodev(node, "reset-gpios", 0,
+                                      &hdmi, GPIOD_IS_OUT)) {
+               pr_debug("%s: could not find reset-gpios\n",
+                        __func__);
+               return -ENOENT;
+       }
+
+       node = ofnode_path("/soc/i2c@40012000/cs42l51@4a");
+       if (!ofnode_valid(node)) {
+               pr_debug("%s: no cs42l51@4a ?\n", __func__);
+               return -ENOENT;
+       }
+
+       if (gpio_request_by_name_nodev(node, "reset-gpios", 0,
+                                      &audio, GPIOD_IS_OUT)) {
+               pr_debug("%s: could not find reset-gpios\n",
+                        __func__);
+               return -ENOENT;
+       }
+
+       /* before power up, insure that HDMI and AUDIO IC is under reset */
+       ret = dm_gpio_set_value(&hdmi, 1);
+       if (ret) {
+               pr_err("%s: can't set_value for hdmi_nrst gpio", __func__);
+               goto error;
+       }
+       ret = dm_gpio_set_value(&audio, 1);
+       if (ret) {
+               pr_err("%s: can't set_value for audio_nrst gpio", __func__);
+               goto error;
+       }
+
+       /* power-up audio IC */
+       regulator_autoset_by_name("v1v8_audio", NULL);
+
+       /* power-up HDMI IC */
+       regulator_autoset_by_name("v1v2_hdmi", NULL);
+       regulator_autoset_by_name("v3v3_hdmi", NULL);
+
+error:
+       return ret;
+}
+
+static bool board_is_dk2(void)
+{
+       if (CONFIG_IS_ENABLED(TARGET_ST_STM32MP15x) &&
+           of_machine_is_compatible("st,stm32mp157c-dk2"))
+               return true;
+
+       return false;
+}
+#endif
+
 /* board dependent setup after realloc */
 int board_init(void)
 {
@@ -470,9 +636,16 @@ int board_init(void)
 
        board_key_check();
 
+#ifdef CONFIG_DM_REGULATOR
+       if (board_is_dk2())
+               dk2_i2c1_fix();
+
+       regulators_enable_boot_on(_DEBUG);
+#endif
+
        sysconf_init();
 
-       if (IS_ENABLED(CONFIG_LED))
+       if (CONFIG_IS_ENABLED(CONFIG_LED))
                led_default_state();
 
        return 0;
@@ -480,9 +653,14 @@ int board_init(void)
 
 int board_late_init(void)
 {
+       char *boot_device;
 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
        const void *fdt_compat;
        int fdt_compat_len;
+       int ret;
+       u32 otp;
+       struct udevice *dev;
+       char buf[10];
 
        fdt_compat = fdt_getprop(gd->fdt_blob, 0, "compatible",
                                 &fdt_compat_len);
@@ -492,19 +670,162 @@ int board_late_init(void)
                else
                        env_set("board_name", fdt_compat + 3);
        }
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                                         DM_GET_DRIVER(stm32mp_bsec),
+                                         &dev);
+
+       if (!ret)
+               ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_BOARD),
+                               &otp, sizeof(otp));
+       if (!ret && otp) {
+               snprintf(buf, sizeof(buf), "0x%04x", otp >> 16);
+               env_set("board_id", buf);
+
+               snprintf(buf, sizeof(buf), "0x%04x",
+                        ((otp >> 8) & 0xF) - 1 + 0xA);
+               env_set("board_rev", buf);
+       }
 #endif
 
+#ifdef CONFIG_ADC
        /* for DK1/DK2 boards */
        board_check_usb_power();
+#endif /* CONFIG_ADC */
+
+       /* Check the boot-source to disable bootdelay */
+       boot_device = env_get("boot_device");
+       if (!strcmp(boot_device, "serial") || !strcmp(boot_device, "usb"))
+               env_set("bootdelay", "0");
 
        return 0;
 }
 
 void board_quiesce_devices(void)
 {
+#ifdef CONFIG_LED
        setup_led(LEDST_OFF);
+#endif
 }
 
+/* eth init function : weak called in eqos driver */
+int board_interface_eth_init(struct udevice *dev,
+                            phy_interface_t interface_type)
+{
+       u8 *syscfg;
+       u32 value;
+       bool eth_clk_sel_reg = false;
+       bool eth_ref_clk_sel_reg = false;
+
+       /* Gigabit Ethernet 125MHz clock selection. */
+       eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
+
+       /* Ethernet 50Mhz RMII clock selection */
+       eth_ref_clk_sel_reg =
+               dev_read_bool(dev, "st,eth_ref_clk_sel");
+
+       syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
+
+       if (!syscfg)
+               return -ENODEV;
+
+       switch (interface_type) {
+       case PHY_INTERFACE_MODE_MII:
+               value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
+                       SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
+               debug("%s: PHY_INTERFACE_MODE_MII\n", __func__);
+               break;
+       case PHY_INTERFACE_MODE_GMII:
+               if (eth_clk_sel_reg)
+                       value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII |
+                               SYSCFG_PMCSETR_ETH_CLK_SEL;
+               else
+                       value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII;
+               debug("%s: PHY_INTERFACE_MODE_GMII\n", __func__);
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               if (eth_ref_clk_sel_reg)
+                       value = SYSCFG_PMCSETR_ETH_SEL_RMII |
+                               SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
+               else
+                       value = SYSCFG_PMCSETR_ETH_SEL_RMII;
+               debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__);
+               break;
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               if (eth_clk_sel_reg)
+                       value = SYSCFG_PMCSETR_ETH_SEL_RGMII |
+                               SYSCFG_PMCSETR_ETH_CLK_SEL;
+               else
+                       value = SYSCFG_PMCSETR_ETH_SEL_RGMII;
+               debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__);
+               break;
+       default:
+               debug("%s: Do not manage %d interface\n",
+                     __func__, interface_type);
+               /* Do not manage others interfaces */
+               return -EINVAL;
+       }
+
+       /* clear and set ETH configuration bits */
+       writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
+              SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
+              syscfg + SYSCFG_PMCCLRR);
+       writel(value, syscfg + SYSCFG_PMCSETR);
+
+       return 0;
+}
+
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+       u32 bootmode = get_bootmode();
+
+       if (prio)
+               return ENVL_UNKNOWN;
+
+       switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
+#ifdef CONFIG_ENV_IS_IN_EXT4
+       case BOOT_FLASH_SD:
+       case BOOT_FLASH_EMMC:
+               return ENVL_EXT4;
+#endif
+#ifdef CONFIG_ENV_IS_IN_UBI
+       case BOOT_FLASH_NAND:
+               return ENVL_UBI;
+#endif
+#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
+       case BOOT_FLASH_NOR:
+               return ENVL_SPI_FLASH;
+#endif
+       default:
+               return ENVL_NOWHERE;
+       }
+}
+
+#if defined(CONFIG_ENV_IS_IN_EXT4)
+const char *env_ext4_get_intf(void)
+{
+       u32 bootmode = get_bootmode();
+
+       switch (bootmode & TAMP_BOOT_DEVICE_MASK) {
+       case BOOT_FLASH_SD:
+       case BOOT_FLASH_EMMC:
+               return "mmc";
+       default:
+               return "";
+       }
+}
+
+const char *env_ext4_get_dev_part(void)
+{
+       static char *const dev_part[] = {"0:auto", "1:auto", "2:auto"};
+       u32 bootmode = get_bootmode();
+
+       return dev_part[(bootmode & TAMP_BOOT_INSTANCE_MASK) - 1];
+}
+#endif
+
 #ifdef CONFIG_SYS_MTDPARTS_RUNTIME
 
 #define MTDPARTS_LEN           256
@@ -563,8 +884,9 @@ static void board_get_mtdparts(const char *dev,
 
 void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 {
+       struct mtd_info *mtd;
        struct udevice *dev;
-       static char parts[2 * MTDPARTS_LEN + 1];
+       static char parts[3 * MTDPARTS_LEN + 1];
        static char ids[MTDIDS_LEN + 1];
        static bool mtd_initialized;
 
@@ -577,8 +899,24 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
        memset(parts, 0, sizeof(parts));
        memset(ids, 0, sizeof(ids));
 
-       if (!uclass_get_device(UCLASS_MTD, 0, &dev))
+       /* probe all MTD devices */
+       for (uclass_first_device(UCLASS_MTD, &dev);
+            dev;
+            uclass_next_device(&dev)) {
+               pr_debug("mtd device = %s\n", dev->name);
+       }
+
+       mtd = get_mtd_device_nm("nand0");
+       if (!IS_ERR_OR_NULL(mtd)) {
                board_get_mtdparts("nand0", ids, parts);
+               put_mtd_device(mtd);
+       }
+
+       mtd = get_mtd_device_nm("spi-nand0");
+       if (!IS_ERR_OR_NULL(mtd)) {
+               board_get_mtdparts("spi-nand0", ids, parts);
+               put_mtd_device(mtd);
+       }
 
        if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev))
                board_get_mtdparts("nor0", ids, parts);
@@ -589,3 +927,181 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
        debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts);
 }
 #endif
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_FDT_FIXUP_PARTITIONS
+       struct node_info nodes[] = {
+               { "st,stm32f469-qspi",          MTD_DEV_TYPE_NOR,  },
+               { "st,stm32mp15-fmc2",          MTD_DEV_TYPE_NAND, },
+       };
+       fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+#endif
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_SET_DFU_ALT_INFO
+#define DFU_ALT_BUF_LEN SZ_1K
+
+static void board_get_alt_info(const char *dev, char *buff)
+{
+       char var_name[32] = "dfu_alt_info_";
+       int ret;
+
+       ALLOC_CACHE_ALIGN_BUFFER(char, tmp_alt, DFU_ALT_BUF_LEN);
+
+       /* name of env variable to read = dfu_alt_info_<dev> */
+       strcat(var_name, dev);
+       ret = env_get_f(var_name, tmp_alt, DFU_ALT_BUF_LEN);
+       if (ret) {
+               if (buff[0] != '\0')
+                       strcat(buff, "&");
+               strncat(buff, tmp_alt, DFU_ALT_BUF_LEN);
+       }
+}
+
+void set_dfu_alt_info(char *interface, char *devstr)
+{
+       struct udevice *dev;
+       struct mtd_info *mtd;
+
+       ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN);
+
+       if (env_get("dfu_alt_info"))
+               return;
+
+       memset(buf, 0, sizeof(buf));
+
+       /* probe all MTD devices */
+       mtd_probe_devices();
+
+       board_get_alt_info("ram", buf);
+
+       if (!uclass_get_device(UCLASS_MMC, 0, &dev))
+               board_get_alt_info("mmc0", buf);
+
+       if (!uclass_get_device(UCLASS_MMC, 1, &dev))
+               board_get_alt_info("mmc1", buf);
+
+       if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev))
+               board_get_alt_info("nor0", buf);
+
+       mtd = get_mtd_device_nm("nand0");
+       if (!IS_ERR_OR_NULL(mtd))
+               board_get_alt_info("nand0", buf);
+
+       mtd = get_mtd_device_nm("spi-nand0");
+       if (!IS_ERR_OR_NULL(mtd))
+               board_get_alt_info("spi-nand0", buf);
+
+#ifdef CONFIG_DFU_VIRT
+       strncat(buf, "&virt 0=OTP", DFU_ALT_BUF_LEN);
+
+       if (IS_ENABLED(CONFIG_PMIC_STPMIC1))
+               strncat(buf, "&virt 1=PMIC", DFU_ALT_BUF_LEN);
+#endif
+
+       env_set("dfu_alt_info", buf);
+       puts("DFU alt info setting: done\n");
+}
+
+#if CONFIG_IS_ENABLED(DFU_VIRT)
+#include <dfu.h>
+#include <power/stpmic1.h>
+
+int dfu_otp_read(u64 offset, u8 *buffer, long *size)
+{
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                                         DM_GET_DRIVER(stm32mp_bsec),
+                                         &dev);
+       if (ret)
+               return ret;
+
+       ret = misc_read(dev, offset + STM32_BSEC_OTP_OFFSET, buffer, *size);
+       if (ret >= 0) {
+               *size = ret;
+               ret = 0;
+       }
+
+       return 0;
+}
+
+int dfu_pmic_read(u64 offset, u8 *buffer, long *size)
+{
+       int ret;
+#ifdef CONFIG_PMIC_STPMIC1
+       struct udevice *dev;
+
+       ret = uclass_get_device_by_driver(UCLASS_MISC,
+                                         DM_GET_DRIVER(stpmic1_nvm),
+                                         &dev);
+       if (ret)
+               return ret;
+
+       ret = misc_read(dev, 0xF8 + offset, buffer, *size);
+       if (ret >= 0) {
+               *size = ret;
+               ret = 0;
+       }
+       if (ret == -EACCES) {
+               *size = 0;
+               ret = 0;
+       }
+#else
+       pr_err("PMIC update not supported");
+       ret = -EOPNOTSUPP;
+#endif
+
+       return ret;
+}
+
+int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
+                        void *buf, long *len)
+{
+       switch (dfu->data.virt.dev_num) {
+       case 0x0:
+               return dfu_otp_read(offset, buf, len);
+       case 0x1:
+               return dfu_pmic_read(offset, buf, len);
+       }
+       *len = 0;
+       return 0;
+}
+
+int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
+{
+       *size = SZ_1K;
+
+       return 0;
+}
+
+#endif
+
+#endif
+
+static void board_copro_image_process(ulong fw_image, size_t fw_size)
+{
+       int ret, id = 0; /* Copro id fixed to 0 as only one coproc on mp1 */
+
+       if (!rproc_is_initialized())
+               if (rproc_init()) {
+                       printf("Remote Processor %d initialization failed\n",
+                              id);
+                       return;
+               }
+
+       ret = rproc_load(id, fw_image, fw_size);
+       printf("Load Remote Processor %d with data@addr=0x%08lx %u bytes:%s\n",
+              id, fw_image, fw_size, ret ? " Failed!" : " Success!");
+
+       if (!ret)
+               rproc_start(id);
+}
+
+U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_COPRO, board_copro_image_process);