Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to acess the physical address from linux kernel space?

I am working on rasberry pi board. Is it possible to directly access the GPIO physical address from linux kernel space using inb(), outb()... ?. If yes how ?.

GPIO register address link Page 90 http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

Thank you

like image 817
kar Avatar asked Nov 27 '22 21:11

kar


2 Answers

Yes.

  1. Get a virtual address mapping setup to the registers in question using ioremap
  2. Use readl/writel to manipulate the physical memory.

Beware that ARM processors will fault on unaligned accesses. Linux handles this gracefully, but with a performance penalty.

Tiny example:

void __iomem *regs = ioremap(0xdead0000, 4);

pr_info("0xdead0000: %#x\n", readl(regs));

iounmap(regs);
like image 109
wkz Avatar answered Dec 05 '22 09:12

wkz


Allocation of I/O memory is not the only required step before that memory may be accessed. You must also ensure that this I/O memory has been made accessible to the kernel. So a mapping must be set up first. This is the role of the ioremap function.

void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
void iounmap(void * addr);

The function is designed specifically to assign virtual addresses to I/O memory regions.

The proper way of getting at I/O memory is via a set of functions (defined via ) provided for that purpose.

To read from I/O memory, use one of the following:

unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);

Here, addr should be an address obtained from ioremap and the return value is what was read from the given I/O memory.

There is a similar set of functions for writing to I/O memory:

void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);

As an example:

void __iomem *io = ioremap(PHYSICAL_ADDRESS, SZ_4K);
iowrite32(value, io);

On the other hand, you can do it in user space on this way:

static volatile uint32_t *gpio = NULL;
int   fd;

if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) return -1; 
gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
if ((int32_t)gpio == -1) return -1; 

*(gpio + n) = value;
like image 37
omotto Avatar answered Dec 05 '22 10:12

omotto