Skip to content

Day74 - MMIO Access and Register Operations

Date: 2026-06-10

Summary

Today I learned how Linux platform drivers access hardware registers through Memory-Mapped I/O (MMIO).

Starting from the Device Tree reg property, I followed the complete resource path:

Device Tree
    reg
platform_get_resource()
struct resource
MMIO resource
__iomem pointer
readl() / writel()

I also investigated how Device Tree bus addresses are translated into CPU physical addresses through the ranges property and examined real MMIO resources on Raspberry Pi 5.

In addition, I built a simulated register block to understand register offsets, bit operations, read-modify-write patterns, and Linux register field helpers.

Topics Learned

  • Memory-Mapped I/O (MMIO)
  • Device Tree reg property
  • platform_get_resource()
  • IORESOURCE_MEM
  • struct resource
  • Device Tree ranges translation
  • /proc/iomem
  • __iomem
  • ioremap()
  • devm_ioremap_resource()
  • Register offset model
  • readl() / writel()
  • BIT()
  • Read-Modify-Write (RMW)
  • GENMASK()
  • FIELD_PREP()
  • FIELD_GET()

Experiments

Lab1 - MMIO Resource Inspection

Created a platform driver that retrieves an MMIO resource from Device Tree using:

platform_get_resource(pdev, IORESOURCE_MEM, 0);

Verified:

reg
struct resource
start / end / size

Lab2 - devm_ioremap_resource()

Attempted to map a fake MMIO resource using:

devm_ioremap_resource()

Observed:

-EBUSY

Learned that the helper performs both resource ownership checks and MMIO mapping.

Lab3 - Real MMIO Resource Investigation

Inspected Raspberry Pi 5 Device Tree nodes:

gpio@7d508500
gpio@7d517c00
pinctrl@7d504100
pinctrl@7d510700

Verified corresponding entries in:

/proc/iomem

Lab4 - Device Tree Address Translation

Examined:

ranges
#address-cells
#size-cells

Verified that Device Tree bus addresses are translated into CPU physical addresses before becoming kernel resources.

Lab5 - __iomem

Verified:

sizeof(void *)
sizeof(void __iomem *)

Learned that __iomem is an address-space annotation used by kernel tooling rather than a different pointer type.

Lab6 - Register Offset Model

Built a fake register map and verified:

Base Address
    +
Register Offset
    =
Register

Lab7 - Simulated readl() / writel()

Implemented helper functions to simulate register access:

demo_readl()
demo_writel()

Verified register reads and writes using offset-based addressing.

Lab8 - Bit Operations

Practiced:

BIT()

and read-modify-write patterns:

reg |= BIT(...)
reg &= ~BIT(...)

Lab9 - Register Fields

Practiced:

GENMASK()
FIELD_PREP()
FIELD_GET()

for encoding and decoding register fields.

Key Takeaways

  • Device Tree reg describes bus addresses, not necessarily CPU physical addresses.
  • MMIO resources are represented by struct resource.
  • devm_ioremap_resource() performs resource ownership checks in addition to mapping.
  • Linux drivers access registers using:
readl()
writel()

rather than direct pointer dereferencing.

  • Register access is fundamentally:
MMIO Base
    +
Register Offset
  • Most Linux drivers rely heavily on:
  • BIT()
  • Read-Modify-Write
  • GENMASK()
  • FIELD_PREP()
  • FIELD_GET()

Next Step

Day75 - GPIO Controller Architecture

Planned topics:

  • GPIO controller structure
  • GPIO register blocks
  • Direction and data registers
  • GPIO lines and numbering
  • Relationship between GPIO subsystem and MMIO registers