![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
Syscon is a small DM helper for a shared MMIO register block that several drivers touch (reboot magic, boot mode, LED bits, strap latches). One **struct rt_syscon** maps the region once and serializes 32-bit accesses with a per-instance spinlock.
| Piece | Path |
|---|---|
| API | components/drivers/include/drivers/syscon.h |
| Provider | components/drivers/mfd/mfd-syscon.c |
| Kconfig | **RT_USING_MFD** → **RT_MFD_SYSCON** (needs **RT_USING_DM**, **RT_USING_OFW**) |
Lazy probe: If a node was not probed at init but is **compatible = "syscon"** or **"simple-mfd"**, **rt_syscon_find_by_ofw_node** can run **syscon_probe** on a stack **rt_platform_device** and then return **rt_ofw_data(np)**. Prefer normal DT probe for the syscon node so **iomem_base** exists before consumers start.
| Field | Set by |
|---|---|
np | Syscon DT node |
iomem_base / iomem_size | First **reg** region in **syscon_probe** |
list | Global registry **_syscon_nodes** (lookup under **_syscon_nodes_lock**) |
Published to OFW: **rt_ofw_data(syscon_np) = syscon** after probe.
Step (syscon_probe) | Action |
|---|---|
| Map | **rt_ofw_get_address(np, 0, &addr, &size)** → **rt_ioremap** |
| Register | Insert into **_syscon_nodes**, init **rw_lock** |
| Publish | **rt_ofw_data(np) = syscon**, **pdev->parent.user_data = syscon** |
**compatible = "simple-mfd"** is not in **syscon_ofw_ids**; those nodes are only handled via **rt_syscon_find_by_ofw_node** lazy probe (or as parent of children that call **find** on the parent).
All three functions use byte offset into **iomem_base** (must satisfy **offset < iomem_size**). Each access is one 32-bit **HWREG32** — offsets are not auto-scaled to word index.
**rt_syscon_update_bits** (under spinlock):
Only bits set in **mask** are changed; **val** bits outside **mask** are ignored. Safe for typical RMW glue; W1C / hardware that ignores read data may need a dedicated driver instead of blind **update_bits**.
Callable from thread or ISR context (spinlock-based); keep critical sections short.
| API | Use |
|---|---|
**rt_syscon_find_by_ofw_node(np)** | Direct syscon (or **simple-mfd**) node; walks global list, else lazy **syscon_probe** |
**rt_syscon_find_by_ofw_phandle(np, "regmap")** | Consumer node property → target syscon (Linux-style **regmap** phandle) |
**rt_syscon_find_by_ofw_compatible("vendor,foo-syscon")** | First matching compatible in DT |
Returns **RT_NULL** if map fails or compatible is not **syscon** / **simple-mfd** (for lazy path).
Kconfig: **RT_POWER_RESET_SYSCON_REBOOT**. Installs **rt_dm_machine_reset** hook that calls **rt_syscon_update_bits**.
Same pattern with **compatible = "syscon-poweroff"** → **rt_dm_machine_poweroff**.
Child under syscon (or parent resolved via **rt_ofw_get_parent**); writes boot mode magic via **reboot-mode** helper.
**led-syscon.c**: **rt_syscon_find_by_ofw_node(parent)**, **rt_syscon_read / update_bits** for on/off. See LED device model (DM).
| Option | Role |
|---|---|
**RT_USING_MFD** | MFD menu (requires **RT_USING_DM**) |
**RT_MFD_SYSCON** | Build **mfd-syscon.c** |
**RT_POWER_RESET_SYSCON_REBOOT** | power/reset/syscon-reboot.c |
**RT_POWER_RESET_SYSCON_POWEROFF** | power/reset/syscon-poweroff.c |
**RT_POWER_RESET_SYSCON_REBOOT_MODE** | power/reset/syscon-reboot-mode.c |
**RT_LED_SYSCON** | led/led-syscon.c |
probe**, obtain **struct rt_syscon *** via phandle or parent node — do not **rt_ioremap** the same **reg** again.offset**, **mask**, **value** (or chip-specific properties) from your DT node.rt_syscon_read** for status; **rt_syscon_update_bits** for controlled bit changes.rt_dm_machine_reset** / **rt_dm_machine_poweroff** (only one handler).N * 4** depending on TRM.offset >= iomem_size** → **-RT_EINVAL** — extend **reg** in DTS if layout needs more space.find** before syscon **INIT_PLATFORM** probe may rely on lazy probe; ordering bugs are easier if the syscon node is a normal platform device probed first.update_bits(..., mask, val)** clears all **mask** bits then sets **val & mask** — do not use for status bits that clear on read (W1C).ioremap** the same physical address without syscon → races; centralize on one **rt_syscon**.RT_PLATFORM_DRIVER_EXPORT**, probe orderregister-bit-led**rt_ofw_data**components/drivers/include/drivers/syscon.hcomponents/drivers/mfd/mfd-syscon.c