Raspberry Pi 4 bare metal GPIO set/clear issue

There are a few potential problems here. First and most importantly, when writing to GPIO registers, you should use str instead of ldr for the final GPIO_SET0 operation. You’re currently trying to read from the SET0 register rather than write to it. Here’s the corrected line:

str x1, [x0, #GPIO_SET0]  // Use str to write to the register

The base address 0xFE200000 is correct for the Raspberry Pi 4’s peripheral base when using the ARM64 architecture, so that’s not the issue.

Your setup code for configuring GPIO 21 as an output looks correct, using GPIO_SEL2 register (GPFSEL2) and setting bits 3-5 for GPIO 21.

When running bare metal code, you need to ensure proper initialization. Here’s a more complete version of your code that might help:

.section ".text.boot"
.global _start

.equ GPIO_BASE, 0xFE200000
.equ GPIO_SET_21_OUT, 1 << 3
.equ GPIO_SEL2, 0x08
.equ GPIO_SET0, 0x1C
.equ GPIO_21, 1 << 21

_start:
    // Ensure we're in EL1
    mrs x0, currentel
    lsr x0, x0, #2
    cmp x0, #1
    bne .

    // Disable all interrupts
    msr daifset, #0xf
    
    // Initialize stack pointer
    ldr x0, =_start
    mov sp, x0

    // GPIO initialization
    ldr x0, =GPIO_BASE
    ldr x1, =GPIO_SET_21_OUT
    str x1, [x0, #GPIO_SEL2]
    ldr x1, =GPIO_21
    str x1, [x0, #GPIO_SET0]  // Changed to str

loop: 
    nop 
    b   loop

For your compilation, make sure you’re using the correct flags. Here’s a suggested compilation process:

aarch64-none-elf-as -c source.s -o source.o
aarch64-none-elf-ld -T linker.ld source.o -o kernel8.elf
aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img

And here’s a basic linker script (linker.ld):

SECTIONS
{
    . = 0x80000;
    .text : { *(.text.boot) *(.text*) }
    .rodata : { *(.rodata*) }
    .data : { *(.data*) }
    .bss : { *(.bss*) }
}

The inconsistency in 32-bit mode might be related to the initialization state of the hardware. The Raspberry Pi’s boot process can leave the hardware in different states, which is why proper initialization is important.

Read more here: Source link