Skip to content

Instantly share code, notes, and snippets.

@SamJakob
Last active October 10, 2022 11:18
Show Gist options
  • Save SamJakob/0102e81c5bb4403ef124acddad821060 to your computer and use it in GitHub Desktop.
Save SamJakob/0102e81c5bb4403ef124acddad821060 to your computer and use it in GitHub Desktop.
Raspberry Pi ARM32 GPIO using Device Tree
// This does not work under Linux because we lack the ability to access the MMIO/GPIO memory via DMA.
.global initializeGPIO
initializeGPIO:
PROLOGUE
/* Use the SOC proc file to determine the MMIO base offset. */
// Call open to get a file descriptor for the device tree proc file.
LDR R0, =socRangesProcFile
MOV R1, $0
MOV R2, $0
SYSCALL $sys_open
MOV R5, R0 // Copy the result to R5.
// Call lseek to skip past the first word. The relevant word is the second
// one.
// R0 already contains our file descriptor,
// so use that.
MOV R1, $4 // R1, set the offset to 4 bytes (a word =
// 4 bytes so this has the effect of
// skipping the first byte.)
MOV R2, $0x0 // R2, set 'whence'/mode to SEEK_SET - this
// means our offset is relative to the
// start of the file. i.e., we're just
// setting the offset to that point in the
// file.
SYSCALL $sys_lseek
// Now read the contents of the file at that point.
MOV R0, R5 // Re-load the file descriptor back into
// R0, from R5.
LDR R1, =gpioMMIOBase // Set R1 to the word in memory reserved
// for storing the MMIO base.
MOV R2, $4 // Set R2 to the number of bytes we want to
// read. (In this case, it's a word – or 4
// bytes.)
SYSCALL $sys_read
// Call close to clean up the file descriptor, having read the file into
// a memory buffer.
MOV R0, R5 // Re-load the file descriptor back into
// R0, from R5.
SYSCALL $sys_close
// Now, load the value.
LDR R6, =gpioMMIOBase
LDR R0, [R6]
// Check if the value is zero - if it is, we failed to locate the proc file
// which means we should resort to the Pi 1 default value.
CMP R0, $0
BNE 0f
MOV R0, $0x00000020 // Placed in big-endian byte order, so we can do
// REV instead of another comparison/jump as the
// former is guranteed one cycle vs one cycle plus
// 1-3 cycles depending on pipeline status.
0:
// ...reverse the byte-order of the value...
// For some reason (probably just to make our lives difficult) this value
// is stored and retrieved as big-endian - even though we're on a
// little-endian system so we have the fun of needing to REV the value
// (which reverses the byte order) before we can use it.
REV R0, R0
// ...and, add the GPIO base offset.
ADD R0, R0, $0x200000
// We now need to mmap this
MOV R0, $0
MOV R1, $176
MOV R2, $0x3 // Can be read or written.
MOV R3, $0
MOV R4, $0
MOV R5, $0
SYSCALL $sys_mmap
// ...and, finally, store the value.
STR R0, [R6]
BKPT
EPILOGUE
.data
.align 4
socRangesProcFile: .asciz "/proc/device-tree/soc/ranges"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment