Browse Source
The old driver is now in deprecated_console.S, in a similar way to the AArch64 driver. Change-Id: Ib57209c322576c451d466d7406a94adbf01ab8fd Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>pull/1583/head
Daniel Boulby
6 years ago
4 changed files with 435 additions and 106 deletions
@ -0,0 +1,112 @@ |
|||
/* |
|||
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. |
|||
* |
|||
* SPDX-License-Identifier: BSD-3-Clause |
|||
*/ |
|||
#include <asm_macros.S> |
|||
|
|||
/* |
|||
* This is the common console core code for the deprecated single-console API. |
|||
* New platforms should set MULTI_CONSOLE_API=1 and not use this file. |
|||
*/ |
|||
#warning "Using deprecated console implementation. Please migrate to MULTI_CONSOLE_API" |
|||
|
|||
.globl console_init |
|||
.globl console_uninit |
|||
.globl console_putc |
|||
.globl console_getc |
|||
.globl console_flush |
|||
|
|||
/* |
|||
* The console base is in the data section and not in .bss |
|||
* even though it is zero-init. In particular, this allows |
|||
* the console functions to start using this variable before |
|||
* the runtime memory is initialized for images which do not |
|||
* need to copy the .data section from ROM to RAM. |
|||
*/ |
|||
.section .data.console_base ; .align 2 |
|||
console_base: .word 0x0 |
|||
|
|||
/* ----------------------------------------------- |
|||
* int console_init(uintptr_t base_addr, |
|||
* unsigned int uart_clk, unsigned int baud_rate) |
|||
* Function to initialize the console without a |
|||
* C Runtime to print debug information. It saves |
|||
* the console base to the data section. |
|||
* In: r0 - console base address |
|||
* r1 - Uart clock in Hz |
|||
* r2 - Baud rate |
|||
* out: return 1 on success else 0 on error |
|||
* Clobber list : r1 - r3 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_init |
|||
/* Check the input base address */ |
|||
cmp r0, #0 |
|||
beq init_fail |
|||
ldr r3, =console_base |
|||
str r0, [r3] |
|||
b console_core_init |
|||
init_fail: |
|||
bx lr |
|||
endfunc console_init |
|||
|
|||
/* ----------------------------------------------- |
|||
* void console_uninit(void) |
|||
* Function to finish the use of console driver. |
|||
* It sets the console_base as NULL so that any |
|||
* further invocation of `console_putc` or |
|||
* `console_getc` APIs would return error. |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_uninit |
|||
mov r0, #0 |
|||
ldr r3, =console_base |
|||
str r0, [r3] |
|||
bx lr |
|||
endfunc console_uninit |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_putc(int c) |
|||
* Function to output a character over the |
|||
* console. It returns the character printed on |
|||
* success or -1 on error. |
|||
* In : r0 - character to be printed |
|||
* Out : return -1 on error else return character. |
|||
* Clobber list : r1, r2 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_putc |
|||
ldr r2, =console_base |
|||
ldr r1, [r2] |
|||
b console_core_putc |
|||
endfunc console_putc |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_getc(void) |
|||
* Function to get a character from the console. |
|||
* It returns the character grabbed on success |
|||
* or -1 on error. |
|||
* Clobber list : r0, r1 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_getc |
|||
ldr r1, =console_base |
|||
ldr r0, [r1] |
|||
b console_core_getc |
|||
endfunc console_getc |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_flush(void) |
|||
* Function to force a write of all buffered |
|||
* data that hasn't been output. It returns 0 |
|||
* upon successful completion, otherwise it |
|||
* returns -1. |
|||
* Clobber list : r0, r1 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_flush |
|||
ldr r1, =console_base |
|||
ldr r0, [r1] |
|||
b console_core_flush |
|||
endfunc console_flush |
@ -0,0 +1,318 @@ |
|||
/* |
|||
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. |
|||
* |
|||
* SPDX-License-Identifier: BSD-3-Clause |
|||
*/ |
|||
|
|||
#include <asm_macros.S> |
|||
#include <assert_macros.S> |
|||
#include <console.h> |
|||
|
|||
.globl console_register |
|||
.globl console_unregister |
|||
.globl console_is_registered |
|||
.globl console_set_scope |
|||
.globl console_switch_state |
|||
.globl console_putc |
|||
.globl console_getc |
|||
.globl console_flush |
|||
|
|||
/* |
|||
* The console list pointer is in the data section and not in |
|||
* .bss even though it is zero-init. In particular, this allows |
|||
* the console functions to start using this variable before |
|||
* the runtime memory is initialized for images which do not |
|||
* need to copy the .data section from ROM to RAM. |
|||
*/ |
|||
.section .data.console_list ; .align 2 |
|||
console_list: .word 0x0 |
|||
.section .data.console_state ; .align 0 |
|||
console_state: .byte CONSOLE_FLAG_BOOT |
|||
|
|||
/* ----------------------------------------------- |
|||
* int console_register(console_t *console) |
|||
* Function to insert a new console structure into |
|||
* the console list. Should usually be called by |
|||
* console_<driver>_register implementations. The |
|||
* data structure passed will be taken over by the |
|||
* console framework and *MUST* be allocated in |
|||
* persistent memory (e.g. the data section). |
|||
* In : r0 - address of console_t structure |
|||
* Out: r0 - Always 1 (for easier tail calling) |
|||
* Clobber list: r0, r1 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_register |
|||
push {r6, lr} |
|||
#if ENABLE_ASSERTIONS |
|||
/* Assert that r0 isn't a NULL pointer */ |
|||
cmp r0, #0 |
|||
ASM_ASSERT(ne) |
|||
/* Assert that the struct isn't in the stack */ |
|||
ldr r1, =__STACKS_START__ |
|||
cmp r0, r1 |
|||
blo not_on_stack |
|||
ldr r1, =__STACKS_END__ |
|||
cmp r0, r1 |
|||
ASM_ASSERT(hs) |
|||
not_on_stack: |
|||
/* Assert that this struct isn't in the list */ |
|||
mov r1, r0 /* Preserve r0 and lr */ |
|||
bl console_is_registered |
|||
cmp r0, #0 |
|||
ASM_ASSERT(eq) |
|||
mov r0, r1 |
|||
#endif /* ENABLE_ASSERTIONS */ |
|||
ldr r6, =console_list |
|||
ldr r1, [r6] /* R1 = first struct in list */ |
|||
str r0, [r6] /* list head = new console */ |
|||
str r1, [r0, #CONSOLE_T_NEXT] /* new console next ptr = R1 */ |
|||
mov r0, #1 |
|||
pop {r6, pc} |
|||
endfunc console_register |
|||
|
|||
/* ----------------------------------------------- |
|||
* int console_unregister(console_t *console) |
|||
* Function to find a specific console in the list |
|||
* of currently active consoles and remove it. |
|||
* In: r0 - address of console_t struct to remove |
|||
* Out: r0 - removed address, or NULL if not found |
|||
* Clobber list: r0, r1 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_unregister |
|||
#if ENABLE_ASSERTIONS |
|||
/* Assert that r0 isn't a NULL pointer */ |
|||
cmp r0, #0 |
|||
ASM_ASSERT(ne) |
|||
#endif /* ENABLE_ASSERTIONS */ |
|||
push {r6} |
|||
ldr r6, =console_list /* R6 = ptr to first struct */ |
|||
ldr r1, [r6] /* R1 = first struct */ |
|||
|
|||
unregister_loop: |
|||
cmp r1, #0 |
|||
beq unregister_not_found |
|||
cmp r0, r1 |
|||
beq unregister_found |
|||
ldr r6, [r6] /* R6 = next ptr of struct */ |
|||
ldr r1, [r6] /* R1 = next struct */ |
|||
b unregister_loop |
|||
|
|||
unregister_found: |
|||
ldr r1, [r1] /* R1 = next struct */ |
|||
str r1, [r6] /* prev->next = cur->next */ |
|||
pop {r6} |
|||
bx lr |
|||
|
|||
unregister_not_found: |
|||
mov r0, #0 /* return NULL if not found */ |
|||
pop {r6} |
|||
bx lr |
|||
endfunc console_unregister |
|||
|
|||
/* ----------------------------------------------- |
|||
* int console_is_registered(console_t *console) |
|||
* Function to detect if a specific console is |
|||
* registered or not. |
|||
* In: r0 - address of console_t struct to remove |
|||
* Out: r0 - 1 if it is registered, 0 if not. |
|||
* Clobber list: r0 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_is_registered |
|||
#if ENABLE_ASSERTIONS |
|||
/* Assert that r0 isn't a NULL pointer */ |
|||
cmp r0, #0 |
|||
ASM_ASSERT(ne) |
|||
#endif /* ENABLE_ASSERTIONS */ |
|||
push {r6} |
|||
ldr r6, =console_list |
|||
ldr r6, [r6] /* R6 = first console struct */ |
|||
check_registered_loop: |
|||
cmp r6, #0 /* Check if end of list */ |
|||
beq console_not_registered |
|||
cmp r0, r6 /* Check if the pointers are different */ |
|||
beq console_registered |
|||
ldr r6, [r6, #CONSOLE_T_NEXT] /* Get pointer to next struct */ |
|||
b check_registered_loop |
|||
console_not_registered: |
|||
mov r0, #0 |
|||
pop {r6} |
|||
bx lr |
|||
console_registered: |
|||
mov r0, #1 |
|||
pop {r6} |
|||
bx lr |
|||
endfunc console_is_registered |
|||
|
|||
/* ----------------------------------------------- |
|||
* void console_switch_state(unsigned int new_state) |
|||
* Function to switch the current console state. |
|||
* The console state determines which of the |
|||
* registered consoles are actually used at a time. |
|||
* In : r0 - global console state to move to |
|||
* Clobber list: r0, r1 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_switch_state |
|||
ldr r1, =console_state |
|||
strb r0, [r1] |
|||
bx lr |
|||
endfunc console_switch_state |
|||
|
|||
/* ----------------------------------------------- |
|||
* void console_set_scope(console_t *console, |
|||
* unsigned int scope) |
|||
* Function to update the states that a given console |
|||
* may be active in. |
|||
* In : r0 - pointer to console_t struct |
|||
* : r1 - new active state mask |
|||
* Clobber list: r0, r1, r2 |
|||
* ----------------------------------------------- |
|||
*/ |
|||
func console_set_scope |
|||
#if ENABLE_ASSERTIONS |
|||
ands r2, r1, #~CONSOLE_FLAG_SCOPE_MASK |
|||
ASM_ASSERT(eq) |
|||
#endif /* ENABLE_ASSERTIONS */ |
|||
ldr r2, [r0, #CONSOLE_T_FLAGS] |
|||
and r2, r2, #~CONSOLE_FLAG_SCOPE_MASK |
|||
orr r2, r2, r1 |
|||
str r2, [r0, #CONSOLE_T_FLAGS] |
|||
bx lr |
|||
endfunc console_set_scope |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_putc(int c) |
|||
* Function to output a character. Calls all |
|||
* active console's putc() handlers in succession. |
|||
* In : r0 - character to be printed |
|||
* Out: r0 - printed character on success, or < 0 |
|||
if at least one console had an error |
|||
* Clobber list : r0, r1, r2 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_putc |
|||
push {r4-r6, lr} |
|||
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ |
|||
mov r4, r0 /* R4 = character to print */ |
|||
ldr r6, =console_list |
|||
ldr r6, [r6] /* R6 = first console struct */ |
|||
|
|||
putc_loop: |
|||
cmp r6, #0 |
|||
beq putc_done |
|||
ldr r1, =console_state |
|||
ldrb r1, [r1] |
|||
ldr r2, [r6, #CONSOLE_T_FLAGS] |
|||
tst r1, r2 |
|||
beq putc_continue |
|||
ldr r2, [r6, #CONSOLE_T_PUTC] |
|||
cmp r2, #0 |
|||
beq putc_continue |
|||
mov r0, r4 |
|||
mov r1, r6 |
|||
blx r2 |
|||
cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */ |
|||
cmpne r0, #0 /* else update it if R0 < 0 */ |
|||
movlt r5, r0 |
|||
putc_continue: |
|||
ldr r6, [r6] /* R6 = next struct */ |
|||
b putc_loop |
|||
|
|||
putc_done: |
|||
mov r0, r5 |
|||
pop {r4-r6, pc} |
|||
endfunc console_putc |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_getc(void) |
|||
* Function to get a character from any console. |
|||
* Keeps looping through all consoles' getc() |
|||
* handlers until one of them returns a |
|||
* character, then stops iterating and returns |
|||
* that character to the caller. Will stop looping |
|||
* if all active consoles report real errors |
|||
* (other than just not having a char available). |
|||
* Out : r0 - read character, or < 0 on error |
|||
* Clobber list : r0, r1 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_getc |
|||
push {r5-r6, lr} |
|||
getc_try_again: |
|||
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ |
|||
ldr r6, =console_list |
|||
ldr r6, [r6] /* R6 = first console struct */ |
|||
cmp r6, #0 |
|||
bne getc_loop |
|||
mov r0, r5 /* If no consoles registered */ |
|||
pop {r5-r6, pc} /* return immediately. */ |
|||
|
|||
getc_loop: |
|||
ldr r0, =console_state |
|||
ldrb r0, [r0] |
|||
ldr r1, [r6, #CONSOLE_T_FLAGS] |
|||
tst r0, r1 |
|||
beq getc_continue |
|||
ldr r1, [r6, #CONSOLE_T_GETC] |
|||
cmp r1, #0 |
|||
beq getc_continue |
|||
mov r0, r6 |
|||
blx r1 |
|||
cmp r0, #0 /* if R0 >= 0: return */ |
|||
bge getc_found |
|||
cmp r5, #ERROR_NO_PENDING_CHAR /* may update R5 (NOCHAR has */ |
|||
movne r5, r0 /* precedence vs real errors) */ |
|||
getc_continue: |
|||
ldr r6, [r6] /* R6 = next struct */ |
|||
cmp r6, #0 |
|||
bne getc_loop |
|||
cmp r5, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */ |
|||
beq getc_try_again /* one console returns NOCHAR */ |
|||
mov r0, r5 |
|||
|
|||
getc_found: |
|||
pop {r5-r6, pc} |
|||
endfunc console_getc |
|||
|
|||
/* --------------------------------------------- |
|||
* int console_flush(void) |
|||
* Function to force a write of all buffered |
|||
* data that hasn't been output. Calls all |
|||
* console's flush() handlers in succession. |
|||
* Out: r0 - 0 on success, < 0 if at least one error |
|||
* Clobber list : r0, r1, r2 |
|||
* --------------------------------------------- |
|||
*/ |
|||
func console_flush |
|||
push {r5-r6, lr} |
|||
mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ |
|||
ldr r6, =console_list |
|||
ldr r6, [r6] /* R6 = first console struct */ |
|||
|
|||
flush_loop: |
|||
cmp r6, #0 |
|||
beq flush_done |
|||
ldr r1, =console_state |
|||
ldrb r1, [r1] |
|||
ldr r2, [r6, #CONSOLE_T_FLAGS] |
|||
tst r1, r2 |
|||
beq flush_continue |
|||
ldr r1, [r6, #CONSOLE_T_FLUSH] |
|||
cmp r1, #0 |
|||
beq flush_continue |
|||
mov r0, r6 |
|||
blx r1 |
|||
cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */ |
|||
cmpne r0, #0 /* else update it if R0 < 0 */ |
|||
movlt r5, r0 |
|||
flush_continue: |
|||
ldr r6, [r6] /* R6 = next struct */ |
|||
b flush_loop |
|||
|
|||
flush_done: |
|||
mov r0, r5 |
|||
pop {r5-r6, pc} |
|||
endfunc console_flush |
Loading…
Reference in new issue