MMIO Register Access¶
Overview¶
Memory-Mapped I/O (MMIO) is the primary mechanism used by Linux platform drivers to access hardware registers.
Instead of using dedicated I/O instructions, peripheral registers are mapped into the CPU address space and accessed through memory operations.
Device Tree MMIO Resource¶
A Device Tree node describes a register block through the reg property.
Example:
Meaning:
Resource Flow¶
Linux converts Device Tree MMIO information into a platform resource.
Example:
Device Tree Address Translation¶
The address stored in reg is not always a CPU physical address.
Address translation may occur through the parent bus ranges property.
Example:
Kernel resources and /proc/iomem reflect the translated address.
MMIO Mapping¶
Before a driver can access registers, the MMIO resource must be mapped into kernel virtual address space.
Traditional Method¶
Cleanup:
Managed Method¶
Benefits:
Modern platform drivers should prefer:
__iomem¶
Mapped MMIO addresses use:
Example:
Purpose:
Used by:
It does not change pointer size.
Register Access Model¶
Hardware registers are accessed through:
Example:
Definitions:
Access:
readl() and writel()¶
Linux drivers should use:
instead of:
Reasons:
Typical usage:
Read-Modify-Write¶
Most drivers update only part of a register.
Pattern:
Example:
BIT()¶
Single-bit definitions:
#define CTRL_ENABLE BIT(0)
#define CTRL_IRQ_EN BIT(1)
#define CTRL_RESET BIT(2)
#define CTRL_DMA_EN BIT(3)
Enable:
Disable:
Toggle:
Register Fields¶
Registers often contain multi-bit fields.
Example:
GENMASK()¶
Generate field mask.
Result:
FIELD_PREP()¶
Prepare a value for a field.
Equivalent to:
FIELD_GET()¶
Extract field value.
Returns:
Example:
#define CTRL_MODE_MASK GENMASK(1, 0)
#define CTRL_DIV_MASK GENMASK(4, 2)
#define CTRL_DRV_MASK GENMASK(7, 5)
reg |= FIELD_PREP(CTRL_MODE_MASK, 2);
reg |= FIELD_PREP(CTRL_DIV_MASK, 5);
reg |= FIELD_PREP(CTRL_DRV_MASK, 3);
mode = FIELD_GET(CTRL_MODE_MASK, reg);
div = FIELD_GET(CTRL_DIV_MASK, reg);
drv = FIELD_GET(CTRL_DRV_MASK, reg);
Typical Platform Driver Flow¶
Device Tree reg
↓
platform_get_resource()
↓
struct resource
↓
devm_ioremap_resource()
↓
void __iomem *base
↓
Register Offset
↓
readl()/writel()
↓
BIT()
↓
Read-Modify-Write
↓
GENMASK()
FIELD_PREP()
FIELD_GET()
Related Topics¶
- Linux Driver Model Fundamentals
- Platform Driver and Device Tree Binding
- GPIO Controller Architecture
- Linux GPIO Driver (gpiod)
Related APIs¶
- platform_get_resource()
- devm_ioremap_resource()
- ioremap()
- iounmap()
- readl()
- writel()
- BIT()
- GENMASK()
- FIELD_PREP()
- FIELD_GET()