Align LED initialization behavior with other WAGO products. The
bootloader illuminates all LEDs in orange to signal early boot.
Resetting the strip to black upon kernel driver initialization
provides clear visual feedback that the Linux kernel has taken control.
Introduce the 'wago,reset-on-init' DT property to trigger this reset
when the RPMsg channel is established.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Reserve 4 KB at 0x9c900000 (uboot-ipc-shm) in the Linux device tree so
the kernel never allocates pages over the DDR region that U-Boot uses
to pass LED commands to the M4 Zephyr firmware via the sidecar IPC
channel.
This region is written exclusively by U-Boot (A53) and read by the M4.
Linux only needs to know to stay away from it.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
The message fired as dev_err_ratelimited during the normal window
between probe() and RPMsg channel announcement (trigger active,
rpdev not yet set). This is expected behaviour, not an error.
Demote to dev_dbg to keep the kernel log clean on every boot.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
The previous approach tried to peek at the rproc state in probe() to
decide whether to use delay=0 (SPL path) or 5000ms (Linux-boot path).
This did not work because the remoteproc subsystem registers the rproc
device ~140ms after the LED driver probes, so rproc_get_by_phandle()
always returned NULL at probe() time and the 5000ms delay was always
used.
New approach:
- Schedule boot_work with delay=0 unconditionally from probe().
- Reduce WAGO_BOOT_RETRY_MS from 2000ms to 200ms so the rproc handle
is found within one retry after it becomes available (~200ms total).
- Increase WAGO_BOOT_MAX_RETRIES from 30 to 150 to keep the same
total worst-case timeout (150 x 200ms = 30s for rproc polling).
- For the Linux-boot path (-ENOENT, firmware file not found), switch
directly to WAGO_BOOT_INITIAL_DELAY_MS (5000ms) per retry instead
of the short rproc-poll interval to avoid hammering the filesystem.
Expected boot timeline (SPL path):
[0.797] probe() -> boot_work scheduled, delay=0
[0.797] boot_work #1 -> rproc not yet available, retry in 200ms
[0.997] boot_work #2 -> rproc DETACHED, attach immediately
[~1.0 ] RPMsg channel up -> LED strip active
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Previously LED class devices were registered inside wago_rpmsg_probe(),
which is called only after the RPMsg channel is announced by the M4.
With the M4 firmware loaded by U-Boot/SPL the channel still takes a
few hundred ms to appear, and before that no LED trigger could run.
This change makes the driver register all LED class devices directly
in wago_m4_led_probe() so that kernel triggers (timer, pattern, ...)
start working immediately at probe time, independently of the RPMsg
channel state. wago_led_set() already drops frames silently when
rpdev == NULL, so the trigger runs without error until the channel
comes up and real hardware updates start flowing.
Additionally, probe() now peeks at the rproc state via a temporary
rproc_get_by_phandle() call: when the rproc is already in
RPROC_DETACHED state (U-Boot/SPL loaded the firmware), boot_work is
scheduled with delay=0 instead of WAGO_BOOT_INITIAL_DELAY_MS so that
the RPMsg attach happens as fast as possible.
Summary of changes:
- wago_m4_led_probe(): call wago_led_register_leds() before the rpmsg
driver registration; detect RPROC_DETACHED and set boot_delay_ms=0.
- wago_rpmsg_probe(): remove wago_led_register_leds() call; only store
rpdev so wago_led_set() can begin sending real frames.
- Update header comment to document both boot paths.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
The 'led-default-intensity' property now accepts an optional 4th cell
for the initial LED brightness, in addition to the three R/G/B cells:
led-default-intensity = <R G B>; /* colour only (unchanged) */
led-default-intensity = <R G B brightness>; /* colour + brightness */
Both forms are accepted; existing 3-cell entries are unaffected.
Driver (drivers/leds/rgb/wago-m4-led-wrapper.c):
- Use fwnode_property_count_u32() to detect 3- vs. 4-cell form.
- When 4 cells are present, apply the 4th value to
led_cdev.brightness via clamp_val(rgba[3], 0, LED_FULL).
DTS (arch/arm64/boot/dts/ti/k3-am623-pfc-750-8400.dts):
- Set sys LED to <255 80 0 64> so it blinks orange at brightness 64/255
instead of the default full brightness.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
The kernel LED multicolor core has no standard DT property to set the
initial sub-LED intensities (multi_intensity). Add a WAGO-specific
optional property 'led-default-intensity = <R G B>' that is read once
at registration time and applied to subled_info[].intensity.
If the property is absent the previous default (255 255 255 — white)
is kept, so existing DT nodes without the property are unaffected.
Driver (drivers/leds/rgb/wago-m4-led-wrapper.c):
- Add wago_led_apply_default_intensity() which reads the three-cell
array property via fwnode_property_read_u32_array() and clamps each
value to [0..255] via clamp_val().
- Call it from wago_led_register_leds() after wago_led_init_subled(),
in the DT child-node path only.
DTS (arch/arm64/boot/dts/ti/k3-am623-pfc-750-8400.dts):
- Set led@0 (sys) to linux,default-trigger = "timer" and
led-default-intensity = <255 80 0> so the sys LED blinks orange
out of the box.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Bash/sh script (BusyBox compatible) to stress-test the WAGO M4 RGB LED
strip driver by activating kernel LED triggers on all ten strip LEDs
(sys, run, io, em, u1-u6).
Three trigger modes selectable via --trigger=<mode>:
pattern (default)
Phase 1 - FADE: staggered smooth brightness ramp (200 ms
offset per LED) using the pattern trigger
Phase 2 - FAST FLASH: 50 ms on/off in distinct colours per LED
Phase 3 - SLOW FLASH: 400 ms on/off with colour cycling
timer
Simple on/off blink with staggered delay_on/delay_off values
(50 ms .. 500 ms) and per-LED colours.
heartbeat
Kernel heartbeat trigger, all LEDs white.
Additional options:
--duration=<sec> Total test duration in seconds (default: 30)
--version Print version string
--help Print usage
Cleanup handler (trap INT/TERM) restores trigger=none + brightness=0
on all LEDs when the test ends or is interrupted.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Set init_data.devicename = NULL in the DT child-node registration path
so that led_compose_name() uses the fwnode 'label' property directly as
the LED class device name, without prepending the driver name.
This changes the sysfs entries from:
/sys/class/leds/wago-m4-led-wrapper:sys
to:
/sys/class/leds/sys
matching the naming convention of the PCA9552 multicolor LED groups.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add Device Tree child-node parsing to the wago-m4-led-wrapper driver so
that individual LEDs on the M4 strip can be named from DTS, matching the
convention used by drivers such as nxp,pca9552.
Driver changes (drivers/leds/rgb/wago-m4-led-wrapper.c):
- Add #include <linux/property.h> for fwnode helpers.
- Extract common sub-LED initialisation into wago_led_init_subled().
- In wago_led_register_leds(), count child nodes first:
* If child nodes are present, iterate them with
device_for_each_child_node(); read the 'reg' property to determine
the strip index, populate led_init_data.fwnode, and register via
devm_led_classdev_multicolor_register_ext(). The LED core then
reads the 'label' and 'linux,default-trigger' properties from the
child node automatically.
* If no child nodes are present, fall back to the previous hard-coded
'wago-m4-led-wrapper:<m4-ledN>' naming so existing deployments are
unaffected.
DTS change (arch/arm64/boot/dts/ti/k3-am623-pfc-750-8400.dts):
- Add #address-cells = <1> / #size-cells = <0> to the leds-m4 node.
- Add led@0 .. led@9 child nodes with 'reg' and 'label' properties,
using the same names as the PCA9552 multicolor LED groups (sys, run,
io, em, u1 .. u6) so /sys/class/leds/ entries match across both
LED controllers.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Enable CONFIG_DYNAMIC_DEBUG to allow fine-grained, runtime-controlled
debug message filtering via debugfs. This reduces noise in production
while preserving the ability to activate pr_debug()/dev_dbg() messages
selectively without rebuilding the kernel.
Example-Usage:
mount -t debugfs nodev /sys/kernel/debug
echo 'file wago-m4-led-wrapper.c +p' > /sys/kernel/debug/dynamic_debug/control
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Pattern-based LED trigger support is needed to allow flexible
LED blinking sequences without relying on userspace timers.
CONFIG_LEDS_TRIGGER_PATTERN enables kernel-side pattern control
via sysfs, which is required for hardware-specific LED signaling
on AM6xxx-based platforms.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
- Extend pattern trigger to parse optional RGB per tuple
- Plumb color data through include/linux/leds.h
- Preserve existing tuple semantics when color omitted
Signed-off-by: Maxim Laschinsky <maxim.laschinsky@wago.com>
The pattern trigger updates mc_cdev->subled_info[i].intensity directly.
By using these intensities directly instead of recalculating from the static multi_intensity values, we correctly support RGB-aware patterns.
Enable multicolor LED class and WAGO M4 wrapper LED driver options
for am6xxx platform. The M4 wrapper driver requires multicolor class
support, and sysfs passthrough is needed for userspace LED control
on WAGO hardware variants based on AM6xxx SoCs.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Active kernel LED triggers (e.g. "heartbeat") periodically invoke
brightness_set(), which re-lights LEDs immediately after the M4
firmware clears them via CMD-IDL. This causes a visible flicker and
prevents the M4 from taking full control of the LED strip.
Cancel all kernel-side triggers and set brightness to zero before
forwarding CMD-IDL through the sysfs passthrough interface, ensuring
the LED core no longer interferes with M4 firmware LED state.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Replace the ASCII text-based command protocol with a compact binary
frame format defined in wago-m4-led-protocol.h. The Zephyr firmware
no longer exposes a generic rpmsg-tty channel; instead it announces
a dedicated "wago-led" RPMsg endpoint.
The ASCII protocol required up to three CMD-WLED messages plus a
CMD-IDL per brightness_set call and encoded colour values as decimal
strings. The binary protocol replaces this with fixed-size packed
structs (CMD_SET_LED: 5 bytes, CMD_IDL: 1 byte), reducing per-update
overhead and eliminating string formatting from the hot path.
CMD_SET_LED (0x01) addresses a single LED by index and carries R/G/B
values directly, allowing the M4 to update one pixel without
disturbing the rest of the strip buffer it maintains internally.
New frame types CMD_SET_STRIP (0x02) and CMD_SET_ALL (0x03) are
defined for future strip-wide updates.
The sysfs passthrough path is preserved for legacy ASCII animation
commands (CMD-CYC, CMD-BLK, CMD-FAD, etc.) via a thin
wago_send_ascii() wrapper around the new wago_send() helper.
The RX callback comment is updated to reflect that no ACKs are
expected in the binary protocol, and the rx log is adjusted to print
byte count rather than attempting to print binary data as a string.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
The sysfs `wago_led_cmd` passthrough attribute was always compiled in,
exposing a direct raw RPMsg command path to userspace with no way to
restrict it for production builds. Guard it behind the new
`CONFIG_LEDS_WAGO_M4_WRAPPER_SYSFS_PASSTHROUGH` Kconfig bool so it
can be excluded from production images that should only allow LED
access through the standard multiclass interface.
Also correct the RPMsg channel name in the Kconfig help text from
`"rpmsg-tty"` to `"wago-led"` to match the actual channel used by
the driver.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add a `wago_led_cmd` sysfs attribute to the leds-m4 platform device
that allows raw ASCII commands to be forwarded directly to the M4
co-processor via RPMsg. This is useful for testing and debugging
M4 LED firmware without going through the LED class abstraction.
The attribute strips trailing whitespace and re-appends a single
newline before forwarding, matching the protocol expected by the
Zephyr application. A read of the attribute reports the RPMsg
channel state (online/offline).
The sysfs group is created during probe and removed on teardown.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Change the RPMsg endpoint name from the generic "rpmsg-tty" to
"wago-led" to match the endpoint announced by the Zephyr
wago-led-server-app, which is required to establish the channel.
Add a comment noting that the name must stay in sync with
RPMSG_TTY_NAME in the Zephyr application source.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Disable automatic boot of the MCU M4F subsystem on the PFC
750-8xxx board by adding the 'ti,no-auto-boot' property. This
allows the M4F core to be loaded and started under explicit
control of the application processor rather than being booted
automatically during system initialization.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add a new optional boolean device tree property 'ti,no-auto-boot' for
the TI K3 M4F remoteproc driver. When present, this property disables
automatic firmware loading and booting at probe time by setting the
rproc->auto_boot flag to false.
This is useful in scenarios where the M4F firmware depends on resources
that are only available after the filesystem is mounted (e.g. firmware
files in /lib/firmware). In such cases, an external driver such as
'wago,m4-led-wrapper' can explicitly call rproc_boot() once all
dependencies are satisfied.
The corresponding YAML binding documentation is updated to describe the
new property and its intended use case.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add a new LED multicolor driver for the WS2812 RGB LED strip (10 LEDs)
controlled by the TI AM62x M4 coprocessor running the Zephyr
wago-led-server-app.
The driver communicates with the M4 via the RPMsg "rpmsg-tty" channel
using ASCII text commands (CMD-WLED / CMD-IDL). Each LED is exposed as
a Linux LED multiclass (RGB) device under /sys/class/leds/m4-led<N>/.
The M4 firmware may either be pre-loaded by the bootloader, in which
case the driver attaches to the already-running core via remoteproc, or
it may be loaded by the driver itself from /lib/firmware.
New files:
- drivers/leds/rgb/wago-m4-led-wrapper.c: platform driver implementing
remoteproc boot/attach, RPMsg channel setup and LED brightness_set_blocking
callbacks.
- Documentation/devicetree/bindings/leds/wago,m4-led-wrapper.yaml:
DT binding schema for the new compatible "wago,m4-led-wrapper".
The DTS for the PFC 750-8400 board is updated to instantiate the node
referencing the existing mcu_m4fss remoteproc handle.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add a new example utility that maps a physical MMIO address range using
/dev/mem and mmap, reads 32-bit register values, and dumps a
user-specified number of bytes in hexadecimal format.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Replace devm_ioremap_wc() with memremap(MEMREMAP_WB) for no-map
reserved-memory regions that have struct page backing.
Using ioremap_wc() on a region backed by struct pages violates
ARM64 memory aliasing rules by creating conflicting cached and
write-combining mappings of the same physical pages. This can
cause SIGBUS faults in unrelated userspace processes.
Add a devm cleanup action to call memunmap() on the mapped
region when the device is released.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Add missing no-map property to ramoops region to prevent Linux
from managing it as regular memory.
Reserve gap regions adjacent to ioremap_wc-mapped M4 memory to
avoid ARM64 cache aliasing issues caused by Linux allocating
pages next to these regions.
Also reserve a gap between r5f-dma-memory and TF-A region to
prevent potential memory conflicts.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
This commit adds sysfs support for ksz9477 register acccess in
userspace. Although access is possible through the use of regmap it
showed to be uncomfortable to work with whole register dumps and also
or security reasons write access is prohibited by deault.
Do a 16-bit read access:
echo 16 0x040C > ksz_read
A 32-bit wirte access:
echo 32 0x0120 0x0115 > ksz_write
Results will be logged in the kernel buffer.
Signed-off-by: Heinrich Toews <ht@twx-software.de>
Two mailbox messages are added to facilitate handshake between the
remote processors to ensure graceful stop of the remote processors.
Signed-off-by: Hari Nagalla <hnagalla@ti.com>
The remote core has to be able to query the DM for the next system mode
in the suspend path. To support this, ti_sci.c has to send the
prepare_sleep command before the suspend message is sent to the remote
core. This patch moves the suspend to suspend_late to be executed after
ti_sci's suspend call.
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Introduce suspend/resume handling to m4 remoteproc driver. The driver
registers for pm notifications. And on SUSPEND_PREPARE event a i
RP_MBOX_SUSPEND_SYSTEM mailbox message is sent to the remote core.
a) If the remote core does n't respond to the SUSPEND message, the
driver sets a device on constraint and returns.
b) If the remote core responds with 'RP_MBOX_SUSPEND_ACK', the driver
initiates a stop of the remote core and returns from the suspend
handler.
c) On the other hand, if the remote core responds with
RP_MBOX_SUSPEND_AUTO or RP_MBOX_SUSPEND_CANCEL, the driver simply
returns.
On the Resume path, driver queries DM to determine the state of the
remote core and if it is Off, turns on the remote core.
Signed-off-by: Hari Nagalla <hnagalla@ti.com>
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Upon a stop request, K3-M4 remote proc driver sends a RP_MBOX_SHUTDOWN
mailbox message to the remote R5 core.
The remote core is expected to:
- relinquish all the resources acquired through Device Manager (DM)
- disable its interrupts
- send back a mailbox acknowledgment RP_MBOX_SHUDOWN_ACK
- enter WFI state.
Meanwhile, the K3-M4 remote proc driver does:
- wait for the RP_MBOX_SHUTDOWN_ACK from the remote core
- wait for the remote proc to enter WFI state
- reset the remote core through device manager
Signed-off-by: Hari Nagalla <hnagalla@ti.com>
The AM62x and AM64x SoCs of the TI K3 family has a Cortex M4F core in
the MCU domain. This core is typically used for safety applications in a
stand alone mode. However, some application (non safety related) may
want to use the M4F core as a generic remote processor with IPC to the
host processor. The M4F core has internal IRAM and DRAM memories and are
exposed to the system bus for code and data loading.
A remote processor driver is added to support this subsystem, including
being able to load and boot the M4F core. Loading includes to M4F
internal memories and predefined external code/data memories. The
carve outs for external contiguous memory is defined in the M4F device
node and should match with the external memory declarations in the M4F
image binary. The M4F subsystem has two resets. One reset is for the
entire subsystem i.e including the internal memories and the other, a
local reset is only for the M4F processing core. When loading the image,
the driver first releases the subsystem reset, loads the firmware image
and then releases the local reset to let the M4F processing core run.
Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
Signed-off-by: Andrew Davis <afd@ti.com>
Signed-off-by: Hari Nagalla <hnagalla@ti.com>