2023-11-13 04:37 AM - edited 2023-11-13 04:39 AM
Custom board based on stm32mp151a. Migrating from kirkstone to mickledore and from SP_MIN to OPTEE. usart1 assigned for debuging, uart4 and uart7 for modbus communication.
I cannot boot uboot with usart1 assigned as stdout-path. It boots with uart4 and uart7, but not usart1. I thought it was some error with security context, but linux can use usart1 as stdout-path. Uboot(uart4) + Linux(usart1) works, but Uboot(usart1) + Linux(usart1) doesn't.
I tried to debug with early trace and lot's of printf. Uboot calls serial_init() (board_f.c) and ends up in device_probe() (device.c) and it never leaves device_probe(). The last debug message was from optee for rcc-reset and then it hangs indefinitely. I couldn't catch it in uboot so I assume it hangs in optee.
Solved! Go to Solution.
2023-11-18 05:40 AM
;) had the same issue today, non-secure-world is not allowed to change that rcc reset register.
Please see my post here:
Issue with USART1 Reset in U-Boot on STM32MP15 with TZEN
and just have a look at TRM 10.7.107: "If TZEN = '1', this register can only be modified in secure mode."
2023-11-13 04:38 AM
2023-11-13 11:20 PM
I configured TF-A to UART4, Optee to UART4, Uboot to USART1 and added printf messages to uboot source code.
/* serial-uclass.c */
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
static int serial_check_stdout(const void *blob, struct udevice **devp)
{
int node = -1;
const char *str, *p, *name;
int namelen;
/* Check for a chosen console */
str = fdtdec_get_chosen_prop(blob, "stdout-path");
if (str) {
p = strchr(str, ':');
namelen = p ? p - str : strlen(str);
node = fdt_path_offset_namelen(blob, str, namelen);
if (node < 0) {
/*
* Deal with things like
* stdout-path = "serial0:115200n8";
*
* We need to look up the alias and then follow it to
* the correct node.
*/
name = fdt_get_alias_namelen(blob, str, namelen);
if (name)
node = fdt_path_offset(blob, name);
}
}
if (node < 0)
node = fdt_path_offset(blob, "console");
if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, devp))
return 0;
/*
* If the console is not marked to be bound before relocation, bind it
* anyway.
*/
if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
devp, NULL, false)) {
if (device_get_uclass_id(*devp) == UCLASS_SERIAL) {
printf("\nserial_check_stdout: probing %s\n", (*devp)->name);
int result = !device_probe(*devp);
printf("\nserial_check_stdout: finished probing %s\n", (*devp)->name);
if (result)
return 0;
}
}
return -ENODEV;
}
/* device.c */
int device_probe(struct udevice *dev)
{
const struct driver *drv;
int ret;
if (!dev)
return -EINVAL;
if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
return 0;
ret = device_notify(dev, EVT_DM_PRE_PROBE);
if (ret)
return ret;
drv = dev->driver;
assert(drv);
printf("\ndevice_probe: probing %s\n", dev->name);
ret = device_of_to_plat(dev);
if (ret)
goto fail;
/* Ensure all parents are probed */
if (dev->parent) {
printf("\ndevice_probe: about to probe %s\n", dev->parent->name);
ret = device_probe(dev->parent);
printf("\ndevice_probe: probed %s, exit code %i\n", dev->parent->name, ret);
if (ret)
goto fail;
/*
* The device might have already been probed during
* the call to device_probe() on its parent device
* (e.g. PCI bridge devices). Test the flags again
* so that we don't mess up the device.
*/
if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
return 0;
}
dev_or_flags(dev, DM_FLAG_ACTIVATED);
if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
(device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) &&
!(drv->flags & DM_FLAG_DEFAULT_PD_CTRL_OFF)) {
ret = dev_power_domain_on(dev);
if (ret)
goto fail;
}
/*
* Process pinctrl for everything except the root device, and
* continue regardless of the result of pinctrl. Don't process pinctrl
* settings for pinctrl devices since the device may not yet be
* probed.
*
* This call can produce some non-intuitive results. For example, on an
* x86 device where dev is the main PCI bus, the pinctrl device may be
* child or grandchild of that bus, meaning that the child will be
* probed here. If the child happens to be the P2SB and the pinctrl
* device is a child of that, then both the pinctrl and P2SB will be
* probed by this call. This works because the DM_FLAG_ACTIVATED flag
* is set just above. However, the PCI bus' probe() method and
* associated uclass methods have not yet been called.
*/
if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) {
ret = pinctrl_select_state(dev, "default");
if (ret && ret != -ENOSYS)
log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n",
dev->name, ret, errno_str(ret));
}
if (CONFIG_IS_ENABLED(IOMMU) && dev->parent &&
(device_get_uclass_id(dev) != UCLASS_IOMMU)) {
ret = dev_iommu_enable(dev);
if (ret)
goto fail;
}
ret = device_get_dma_constraints(dev);
if (ret)
goto fail;
ret = uclass_pre_probe_device(dev);
if (ret)
goto fail;
if (dev->parent && dev->parent->driver->child_pre_probe) {
ret = dev->parent->driver->child_pre_probe(dev);
if (ret)
goto fail;
}
/* Only handle devices that have a valid ofnode */
if (dev_has_ofnode(dev)) {
/*
* Process 'assigned-{clocks/clock-parents/clock-rates}'
* properties
*/
ret = clk_set_defaults(dev, CLK_DEFAULTS_PRE);
if (ret)
goto fail;
}
if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto fail;
}
ret = uclass_post_probe_device(dev);
if (ret)
goto fail_uclass;
if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) {
ret = pinctrl_select_state(dev, "default");
if (ret && ret != -ENOSYS)
log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n",
dev->name, ret, errno_str(ret));
}
ret = device_notify(dev, EVT_DM_POST_PROBE);
if (ret)
return ret;
printf("\ndevice_probe: probing %s finished with 0 code\n", dev->name);
return 0;
fail_uclass:
if (device_remove(dev, DM_REMOVE_NORMAL)) {
dm_warn("%s: Device '%s' failed to remove on error path\n",
__func__, dev->name);
}
fail:
dev_bic_flags(dev, DM_FLAG_ACTIVATED);
device_free(dev);
printf("\ndevice_probe: reached fail while probing %s\n", dev->name);
return ret;
}
/* log.h */
//#ifdef LOG_DEBUG
#define _LOG_DEBUG LOGL_FORCE_DEBUG
#ifndef DEBUG
#define DEBUG
#endif
//#else
//#define _LOG_DEBUG 0
//#endif
/* stm32mp15_defconfig */
CONFIG_LOG=y
CONFIG_LOG_CONSOLE=y
CONFIG_LOG_MAX_LEVEL=7
CONFIG_DEBUG_UART_BOARD_INIT=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_STM32=y
CONFIG_DEBUG_UART_CLOCK=64000000
CONFIG_DEBUG_UART_SKIP_INIT=y
CONFIG_TRACE_EARLY=y
CONFIG_CMD_TRACE=y
For log_uboot_uart4.txt I removed modifications in log.h because there was too much verbosity.
2023-11-13 11:42 PM
2023-11-18 05:40 AM
;) had the same issue today, non-secure-world is not allowed to change that rcc reset register.
Please see my post here:
Issue with USART1 Reset in U-Boot on STM32MP15 with TZEN
and just have a look at TRM 10.7.107: "If TZEN = '1', this register can only be modified in secure mode."
2023-11-19 09:53 PM
Yeah, I already tried scmi reset.
&usart1 {
clocks = <&scmi_clk CK_SCMI_USART1>;
resets = <&scmi_reset RST_SCMI_USART1>;
};
But unfortunately that didn't wok in my case. Tried it again just now and still nothing.
I decompiled dtb just to be sure and it looks ok to me.
serial@5c000000 {
compatible = "st,stm32h7-uart";
reg = <0x5c000000 0x400>;
interrupts-extended = <0x09 0x1a 0x04>;
clocks = <0x03 0x14>;
wakeup-source;
power-domains = <0x0a>;
feature-domains = <0x1c 0x03>;
status = "okay";
pinctrl-names = "default\0idle\0sleep";
pinctrl-0 = <0x45>;
pinctrl-1 = <0x46>;
pinctrl-2 = <0x47>;
resets = <0x10 0x03>;
phandle = <0xb5>;
};
2023-11-19 10:36 PM
Oh, never mind. I messed too much with my defconfig, so I had to fallback to default one. And now it works! Thanks!
2023-11-19 11:11 PM - edited 2023-11-19 11:24 PM
Checked again. Previously I added resets to *-scmi.dtsi and that didn't work, but adding it to *-u-boot.dtsi works, because resets are being overridden in stm32mp15-scmi-u-boot.dtsi.
2023-11-20 09:52 AM
:beaming_face_with_smiling_eyes:let's see what we stumble upon next together, so funny that you also tried *-scmi.dtsi first...