Search code examples
linux-device-driverkernel-modulememory-mapped-io

How to access MMIO registers in Linux kernel with `ioremap()`?


I am working on an embedded Linux system (kernel v5.10.24). And I want to access registers in the SoC which are MMIO based.

So I worked a test module to access them, as follows,

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>

int mmiowr_init(void)
{
    volatile u32 *addr = NULL;
    int ret = 0;

    printk(KERN_INFO "Hello World!\n");
    addr = ioremap_wc(0x11003000, 0x40);
    if (!addr) {
        printk("Error: Failed to remap 0x11003000\n");
    } else {
        printk("XXXXXX Data_0: 0x%x, Data_1: 0x%d\n", addr[0], addr[1]);
    }
    iounmap(addr);
    return ret;
}

void mmiowr_exit(void)
{
    printk(KERN_INFO "Bye World!\n");
}

module_init(mmiowr_init);
module_exit(mmiowr_exit);
MODULE_LICENSE("GPL");

But I did NOT get the expected value in this way. This is out of my surprise! Then I tried using memtool md 0x11003000, it got the same value as the above code! Finally, I loaded the official driver module for these registers, then both above module and memtool can show the expected data.

I checked the driver module, the workflow is as follows,

of_match_node(...);
platform_get_resource(pdev, IORESOURCE_MEM, 0);
request_mem_region(start, size, "xxxx");
ioremap(start, size);

I inserted my ioremap(0x11003000, 0x40); printk("Data_0: %x,....); into above codes to check where I can really access the hardware registers, and found after platform_get_resource(), my codes can read the expected data from the MMIO.

So, what is wrong my test module listed above, and what is the necessary step to access MMIOed register from either kernel or user space?


Solution

  • With tests, I finally figured it out.
    Using ioremap and readl() to access MMIO registers are correct.

    The problem I hit is because the MMIO registers are gated by another register (for security and safety).
    So to access the MMIO registers with ioremap() and readl()/writel(), it needs to firstly set the right gate to enable the MMIO space, before doing remapping and accessing.