Reading the 0xfed815a0 from Linux userspace:
See example program below:
// mmio_dev_mem.c
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc != 4) {
fprintf(stderr, "Usage: %s <phys_addr_hex> <offset_hex> <length>\n", argv[0]);
return 2;
}
unsigned long phys = strtoul(argv[1], NULL, 0);
unsigned long offset = strtoul(argv[2], NULL, 0);
size_t length = (size_t)strtoul(argv[3], NULL, 0);
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0) {
fprintf(stderr, "open /dev/mem failed: %s\n", strerror(errno));
return 1;
}
unsigned long page_size = sysconf(_SC_PAGESIZE);
unsigned long page_base = phys & ~(page_size - 1);
unsigned long page_offset = phys - page_base;
size_t map_len = page_offset + length;
void *map = mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);
if (map == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
return 1;
}
volatile uint32_t *reg = (volatile uint32_t *)((char *)map + page_offset + offset);
// Read 32-bit register
uint32_t val = *reg;
__sync_synchronize(); // compiler memory barrier
printf("Read 0x%08x from phys 0x%lx + 0x%lx\n", val, phys, offset);
// Write 32-bit register (example)
//uint32_t newval = 0xA5A5A5A5;
//*reg = newval;
//__sync_synchronize();
// printf("Wrote 0x%08x\n", newval);
if (munmap(map, map_len) != 0) {
fprintf(stderr, "munmap failed: %s\n", strerror(errno));
}
close(fd);
return 0;
}
compile with:
gcc -O2 -Wall -o mmio_dev_mem mmio_dev_mem.c
Read the mmio 0xfed815a0 value:
sudo ./mmio_dev_mem 0xFED81000 0x05a0 0x1000
Read 0x00e50000 from phys 0xfed81000 + 0x5a0
Note: You can also write values, see the commented out write bit in the C code.
It uses “/dev/mem”. Some kernel / Linux configurations block it, so you might need to unblock it before the program works.
I think it will be difficult to program, unless we know what each bit does, because my guess is that some bits set the GPIO for in/out/tristate, whether it triggers an interrupt, if the interrupt is level or edge triggered etc. with only 1 of the 32 bits being the actual set it high or low bit.