Rodrigo Arias Mallo
806023778b
Unless the UART is properly initialized, the console won't display any message until a next stage intializes it (OpenSBI) and then we will start to see messages after uploading the next bootroms. Follows the OpenSBI initialization for the UART setting the baud rate to 115200 and assuming a clock of 50 MHz.
190 lines
4.2 KiB
ArmAsm
190 lines
4.2 KiB
ArmAsm
/*
|
|
* Copyright (c) 2024, Barcelona Supercomputing Center (BSC)
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* RBOOTROM v1.0
|
|
* Modified by Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
|
|
*
|
|
* This is a custom bootrom that prints some information to the UART when
|
|
* starting, as well as when it hangs. It assumes the UART is at UART_BASE and
|
|
* it will jump to DRAM_BASE to continue the boot.
|
|
*/
|
|
|
|
#define DRAM_BASE 0x80000000
|
|
#define UART_BASE 0x40001000
|
|
#define UART_BAUDRATE 115200
|
|
#define UART_CLOCK 50000000
|
|
|
|
#define UART_BDIV ((UART_CLOCK + 8 * UART_BAUDRATE) / (16 * UART_BAUDRATE))
|
|
#define UART_SHIFT 2
|
|
|
|
#define UART_RBR_OFFSET (0<<UART_SHIFT) /* In: Recieve Buffer Register */
|
|
#define UART_THR_OFFSET (0<<UART_SHIFT) /* Out: Transmitter Holding Register */
|
|
#define UART_DLL_OFFSET (0<<UART_SHIFT) /* Out: Divisor Latch Low */
|
|
#define UART_IER_OFFSET (1<<UART_SHIFT) /* I/O: Interrupt Enable Register */
|
|
#define UART_DLM_OFFSET (1<<UART_SHIFT) /* Out: Divisor Latch High */
|
|
#define UART_FCR_OFFSET (2<<UART_SHIFT) /* Out: FIFO Control Register */
|
|
#define UART_IIR_OFFSET (2<<UART_SHIFT) /* I/O: Interrupt Identification Register */
|
|
#define UART_LCR_OFFSET (3<<UART_SHIFT) /* Out: Line Control Register */
|
|
#define UART_MCR_OFFSET (4<<UART_SHIFT) /* Out: Modem Control Register */
|
|
#define UART_LSR_OFFSET (5<<UART_SHIFT) /* In: Line Status Register */
|
|
#define UART_MSR_OFFSET (6<<UART_SHIFT) /* In: Modem Status Register */
|
|
#define UART_SCR_OFFSET (7<<UART_SHIFT) /* I/O: Scratch Register */
|
|
#define UART_MDR1_OFFSET (8<<UART_SHIFT) /* I/O: Mode Register */
|
|
|
|
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
|
#define UART_LSR_DR 0x01 /* Receiver data ready */
|
|
|
|
.macro PUTC, ch
|
|
li a0, \ch
|
|
jal putchar
|
|
.endm
|
|
|
|
.section .text.start, "ax", @progbits
|
|
.globl _start
|
|
_start:
|
|
jal uart_init // Initialize console
|
|
jal print_hello // Print initial message on HART 0 only
|
|
|
|
la t0, _hang
|
|
csrw mtvec, t0 // Set the machine trap vector
|
|
|
|
csrr a0, mhartid // Load HART ID into a0
|
|
li s0, DRAM_BASE // Load next address into s0
|
|
jr s0 // Jump to s0
|
|
|
|
.section .text.hang, "ax", @progbits
|
|
.globl _hang
|
|
_hang:
|
|
|
|
PUTC '\n'
|
|
PUTC '\r'
|
|
PUTC 'R'
|
|
PUTC 'B'
|
|
PUTC 'O'
|
|
PUTC 'O'
|
|
PUTC 'T'
|
|
PUTC 'R'
|
|
PUTC 'O'
|
|
PUTC 'M'
|
|
PUTC ' '
|
|
PUTC 'H'
|
|
PUTC 'A'
|
|
PUTC 'N'
|
|
PUTC 'G'
|
|
PUTC '\n'
|
|
PUTC '\r'
|
|
|
|
/* Hang */
|
|
csrr a0, mhartid
|
|
1:
|
|
wfi
|
|
j 1b
|
|
|
|
.section .text, "ax", @progbits
|
|
|
|
putchar:
|
|
/* Wait until ready to transmit */
|
|
|
|
la t0, UART_BASE // Load UART base address
|
|
1:
|
|
lb t1, UART_LSR_OFFSET(t0) // Read Line Status Register
|
|
andi t1, t1, UART_LSR_THRE // Transmitter Holding Register Empty
|
|
beqz t1, 1b // Repeat if zero (not empty)
|
|
|
|
/* Write the character now */
|
|
sb a0, UART_THR_OFFSET(t0) // Transmit character
|
|
ret
|
|
|
|
uart_init:
|
|
/* Assume reg_shift = 2 and reg_width = 2 */
|
|
|
|
la t0, UART_BASE // Load UART base address
|
|
|
|
/* From OpenSBI v1.5 lib/utils/serial/uart8250.c */
|
|
|
|
la t1, 0x00 // Disable all interrupts
|
|
sb t1, UART_IER_OFFSET(t0)
|
|
la t1, 0x80 // Enable DLAB
|
|
sb t1, UART_LCR_OFFSET(t0)
|
|
|
|
la t1, UART_BDIV & 0xff // Set divisor low byte
|
|
sb t1, UART_DLL_OFFSET(t0)
|
|
la t1, (UART_BDIV >> 8) & 0xff // Set divisor high byte
|
|
sb t1, UART_DLM_OFFSET(t0)
|
|
|
|
la t1, 0x03 // 8 bits, no parity, one stop bit
|
|
sb t1, UART_LCR_OFFSET(t0)
|
|
la t1, 0x01 // Enable FIFO
|
|
sb t1, UART_FCR_OFFSET(t0)
|
|
la t1, 0x00 // No modem control DTR RTS
|
|
sb t1, UART_MCR_OFFSET(t0)
|
|
|
|
/* TODO: Clear line status */
|
|
/* TODO: Read receive buffer */
|
|
|
|
la t1, 0x00 // Set scratchpad to 0
|
|
sb t1, UART_SCR_OFFSET(t0)
|
|
|
|
ret
|
|
|
|
print_hello:
|
|
csrr t0, mhartid // Load HART ID into a0
|
|
beq t0, zero, 1f // Print message on HART 0 only
|
|
ret
|
|
1:
|
|
mv s0, ra // Save return address
|
|
PUTC '\n' // Identify bootroom
|
|
PUTC '\r'
|
|
PUTC 'R'
|
|
PUTC 'B'
|
|
PUTC 'O'
|
|
PUTC 'O'
|
|
PUTC 'T'
|
|
PUTC 'R'
|
|
PUTC 'O'
|
|
PUTC 'M'
|
|
PUTC ' '
|
|
PUTC 'v'
|
|
PUTC '1'
|
|
PUTC '.'
|
|
PUTC '0'
|
|
PUTC ' '
|
|
PUTC ':'
|
|
PUTC '^'
|
|
PUTC ')'
|
|
PUTC '\n'
|
|
PUTC '\r'
|
|
|
|
// Print jumping address
|
|
PUTC 'J'
|
|
PUTC 'u'
|
|
PUTC 'm'
|
|
PUTC 'p'
|
|
PUTC 'i'
|
|
PUTC 'n'
|
|
PUTC 'g'
|
|
PUTC ' '
|
|
PUTC 't'
|
|
PUTC 'o'
|
|
PUTC ' '
|
|
PUTC '0' // TODO: Compute from DRAM_BASE
|
|
PUTC 'x'
|
|
PUTC '8'
|
|
PUTC '0'
|
|
PUTC '0'
|
|
PUTC '0'
|
|
PUTC '_'
|
|
PUTC '0'
|
|
PUTC '0'
|
|
PUTC '0'
|
|
PUTC '0'
|
|
PUTC '.'
|
|
PUTC '.'
|
|
PUTC '.'
|
|
PUTC '\n'
|
|
PUTC '\r'
|
|
|
|
mv ra, s0 // Restore return address
|
|
ret
|