Last active
October 10, 2022 11:18
-
-
Save SamJakob/0102e81c5bb4403ef124acddad821060 to your computer and use it in GitHub Desktop.
Raspberry Pi ARM32 GPIO using Device Tree
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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