summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-08-17 07:59:23 -0400
committerGitHub <[email protected]>2026-08-17 07:59:23 -0400
commitff638dae718eed436d11da9830683adca246e86d (patch)
tree44ad2f9afa5aaea2278ddeb8277f5e4bc5b96751
parent2f6945475baa6acc3e34a74834972d9a0a796e11 (diff)
Configured the LINFlexD console twice, because once is not enough at -O2 (#629)
The console driver runs its configuration sequence a single time, and that works only because this BSP is built without an optimisation flag. Compiled at -O2 the same sequence leaves the line corrupted: every character partially wrong, in the pattern the file already describes for a misconfigured module. What makes it worth guarding against is that the failure is invisible. UARTCR reads back exactly the value written. LINIBRR and LINFBRR read back exactly the values written. linflexd_init returns LINFLEXD_INIT_OK. The registers are right and the line is wrong, so nothing in the returned status tells the caller the console cannot be trusted. Localised by bisection: with every other file at -O2 and this one at -O0 the output is clean, and with only linflexd_init at -O2 it is corrupted, so the fault is in the configuration sequence rather than in the per-byte transmit path. The mechanism is not understood, and this commit does not claim to explain it. Tested and rejected: a 100x larger bound on the wait for initialisation mode, a settling delay before the first LINSR read, a settling delay after leaving initialisation mode, a barrier and read-back between the two UARTCR writes, and waiting for LINSR to report the exit from initialisation mode. None of those makes a single pass work at -O2. A second pass does, at both optimisation levels, which is what this does. Instrumented with a duplicate of the sequence forced to -O2 and reported through a console repaired afterwards, which is how the register read-backs above were obtained. Verified on the S32Z280-594EVB. The boot image passes six of six probes with the console status still reporting 0x00000000, and the reproducer builds clean and prints correctly at both -O0 and -O2. Assisted-by: Claude Code (Opus 5) <[email protected]>
-rw-r--r--ports/cortex_r52/gnu/example_build/s32z280_evb/linflexd.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/ports/cortex_r52/gnu/example_build/s32z280_evb/linflexd.c b/ports/cortex_r52/gnu/example_build/s32z280_evb/linflexd.c
index 0bd78069..cc6a7773 100644
--- a/ports/cortex_r52/gnu/example_build/s32z280_evb/linflexd.c
+++ b/ports/cortex_r52/gnu/example_build/s32z280_evb/linflexd.c
@@ -104,7 +104,10 @@
#define CONSOLE_BASE S32Z_LINFLEX_9_BASE
-unsigned int linflexd_init(void)
+/* One full pass of the configuration sequence. Called twice by
+ linflexd_init; see the comment there for why. */
+
+static unsigned int linflexd_configure_once(void)
{
unsigned int status = LINFLEXD_INIT_OK;
unsigned int guard;
@@ -167,6 +170,37 @@ unsigned int linflexd_init(void)
}
+unsigned int linflexd_init(void)
+{
+ unsigned int status;
+
+ /* The sequence runs twice, and one pass is genuinely not enough.
+ A single pass gives a working console when this file is compiled at -O0
+ and a corrupted one at -O2: every character partially wrong, while UARTCR
+ reads back exactly the value written, LINIBRR and LINFBRR read back
+ exactly the values written, and the returned status is
+ LINFLEXD_INIT_OK. The registers are right and the line is wrong, so the
+ failure is invisible to the caller -- the worst property a console can
+ have, and the reason this is worth two passes at boot.
+
+ The mechanism is not understood. Tested and rejected as explanations:
+ the wait for initialisation mode (a bound 100x larger changes nothing),
+ a settling delay before the first LINSR read, a settling delay after
+ leaving initialisation mode, a barrier and read-back between the two
+ UARTCR writes, and waiting for LINSR to report the exit from
+ initialisation mode. None of those makes a single pass work at -O2.
+ A second pass does, reliably, at both optimisation levels.
+
+ Verified on the S32Z280-594EVB with the whole BSP at -O0 and at -O2.
+ If the underlying behaviour is ever identified, revisit this. */
+
+ status = linflexd_configure_once();
+ status |= linflexd_configure_once();
+
+ return status;
+}
+
+
void linflexd_putc(char c)
{
if (c == '\n')