Commit fce5f750 authored by Soby Mathew's avatar Soby Mathew
Browse files

Introduce asm console functions in TF

This patch replaces the pl011 console family of functions
with their equivalents defined in assembly. The baud rate is
defined by the PL011_BAUDRATE macro and IBRD and FBRD values
for pl011 are computed statically. This patch will enable
us to invoke the console functions without the C Runtime Stack.

Change-Id: Ic3f7b7370ded38bf9020bf746b362081b76642c7
parent 592dd7cb
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <pl011.h>
void pl011_setbaudrate(unsigned long base_addr, unsigned int baudrate)
{
unsigned int divisor;
assert(baudrate);
divisor = (PL011_CLK_IN_HZ * 4) / baudrate;
pl011_write_ibrd(base_addr, divisor >> 6);
pl011_write_fbrd(base_addr, divisor & 0x3F);
}
...@@ -27,72 +27,149 @@ ...@@ -27,72 +27,149 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <arch.h>
#include <assert.h> #include <asm_macros.S>
#include <console.h>
#include <pl011.h> #include <pl011.h>
static unsigned long uart_base; .globl console_init
.globl console_putc
.globl console_core_init
.globl console_core_putc
.globl console_getc
void console_init(unsigned long base_addr) /*
{ * The console base is in the data section and not in .bss
/* TODO: assert() internally calls printf() and will result in * even though it is zero-init. In particular, this allows
* an infinite loop. This needs to be fixed with some kind of * the console functions to start using this variable before
* exception mechanism or early panic support. This also applies * the runtime memory is initialized for images which do not
* to the other assert() calls below. * need to copy the .data section from ROM to RAM.
*/ */
assert(base_addr); .section .data.console_base ; .align 3
console_base: .quad 0x0
/* Initialise internal base address variable */ /* ---------------------------------------------
uart_base = base_addr; * int console_init(unsigned long base_addr)
* Function to initialize the console without a
* C Runtime to print debug information. It saves
* the console base to the data section.
* In: x0 - console base address
* out: return 1 on success.
* Clobber list : x1, x2
* ---------------------------------------------
*/
func console_init
adrp x1, console_base
str x0, [x1, :lo12:console_base]
b console_core_init
/* Baud Rate */ /* ---------------------------------------------
* int console_core_init(unsigned long base_addr)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: x0 - console base address
* Out: return 1 on success
* Clobber list : x1, x2
* ---------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, init_fail
/* Program the baudrate */
#if defined(PL011_INTEGER) && defined(PL011_FRACTIONAL) #if defined(PL011_INTEGER) && defined(PL011_FRACTIONAL)
pl011_write_ibrd(uart_base, PL011_INTEGER); mov w1, #PL011_INTEGER
pl011_write_fbrd(uart_base, PL011_FRACTIONAL); str w1, [x0, #UARTIBRD]
mov w1, #PL011_FRACTIONAL
str w1, [x0, #UARTFBRD]
#else #else
pl011_setbaudrate(uart_base, PL011_BAUDRATE); .set BRD, ((PL011_CLK_IN_HZ << 2) / PL011_BAUDRATE)
/* Write the IBRD */
mov w1, #((BRD >> 6) & 0xffff)
.if BRD>=0x400000
movk w1, #(BRD >> 22), LSL #16
.endif
str w1, [x0, #UARTIBRD]
/* Write the FBRD */
mov w1, #(BRD & 0x3f)
str w1, [x0, #UARTFBRD]
#endif #endif
mov w1, #PL011_LINE_CONTROL
pl011_write_lcr_h(uart_base, PL011_LINE_CONTROL); str w1, [x0, #UARTLCR_H]
/* Clear any pending errors */ /* Clear any pending errors */
pl011_write_ecr(uart_base, 0); str wzr, [x0, #UARTECR]
/* Enable tx, rx, and uart overall */ /* Enable tx, rx, and uart overall */
pl011_write_cr(uart_base, PL011_UARTCR_RXE | PL011_UARTCR_TXE | mov w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
PL011_UARTCR_UARTEN); str w1, [x0, #UARTCR]
mov w0, #1
init_fail:
ret
} /* ---------------------------------------------
* int console_putc(int c)
#define WAIT_UNTIL_UART_FREE(base) \ * Function to output a character over the
while ((pl011_read_fr(base) & PL011_UARTFR_TXFF)) \ * console. It returns the character printed on
continue * success or -1 on error.
* In : x0 - character to be printed
int console_putc(int c) * Out : return -1 on error else return character.
{ * Clobber list : x1, x2
/* If the console has not been initialized then return an error * ---------------------------------------------
* code. Asserting here would result in recursion and stack
* exhaustion
*/ */
if (!uart_base) func console_putc
return -1; adrp x2, console_base
ldr x1, [x2, :lo12:console_base]
if (c == '\n') { b console_core_putc
WAIT_UNTIL_UART_FREE(uart_base);
pl011_write_dr(uart_base, '\r');
}
WAIT_UNTIL_UART_FREE(uart_base); /* --------------------------------------------------------
pl011_write_dr(uart_base, c); * int console_core_putc(int c, unsigned long base_addr)
return c; * Function to output a character over the console. It
} * returns the character printed on success or -1 on error.
* In : x0 - character to be printed
int console_getc(void) * x1 - console base address
{ * Out : return -1 on error else return character.
assert(uart_base); * Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp x0, #0xA
b.ne 2f
1:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UARTFR]
tbnz w2, #PL011_UARTFR_TXFF_BIT, 1b
mov w2, #0xD
str w2, [x1, #UARTDR]
2:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UARTFR]
tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b
str w0, [x1, #UARTDR]
ret
putc_error:
mov w0, #-1
ret
while ((pl011_read_fr(uart_base) & PL011_UARTFR_RXFE) != 0) /* ---------------------------------------------
; * int console_getc(void)
return pl011_read_dr(uart_base); * Function to get a character from the console.
} * It returns the character grabbed on success
* or -1 on error.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_getc
adrp x0, console_base
ldr x1, [x0, :lo12:console_base]
cbz x1, getc_error
1:
/* Check if the receive FIFO is empty */
ldr w0, [x1, #UARTFR]
tbnz w0, #PL011_UARTFR_RXFE_BIT, 1b
ldr w0, [x1, #UARTDR]
ret
getc_error:
mov w0, #-1
ret
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
#ifndef __PL011_H__ #ifndef __PL011_H__
#define __PL011_H__ #define __PL011_H__
#include <mmio.h>
/* PL011 Registers */ /* PL011 Registers */
#define UARTDR 0x000 #define UARTDR 0x000
#define UARTRSR 0x004 #define UARTRSR 0x004
...@@ -68,6 +65,9 @@ ...@@ -68,6 +65,9 @@
#define PL011_UARTFR_DSR (1 << 1) /* Data set ready */ #define PL011_UARTFR_DSR (1 << 1) /* Data set ready */
#define PL011_UARTFR_CTS (1 << 0) /* Clear to send */ #define PL011_UARTFR_CTS (1 << 0) /* Clear to send */
#define PL011_UARTFR_TXFF_BIT 5 /* Transmit FIFO full bit in UARTFR register */
#define PL011_UARTFR_RXFE_BIT 4 /* Receive FIFO empty bit in UARTFR register */
/* Control reg bits */ /* Control reg bits */
#define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */ #define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */
#define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */ #define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */
...@@ -103,58 +103,4 @@ ...@@ -103,58 +103,4 @@
#define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */ #define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */
#define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */ #define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */
/*******************************************************************************
* Pl011 CPU interface accessors for writing registers
******************************************************************************/
static inline void pl011_write_ibrd(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTIBRD, val);
}
static inline void pl011_write_fbrd(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTFBRD, val);
}
static inline void pl011_write_lcr_h(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTLCR_H, val);
}
static inline void pl011_write_ecr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTECR, val);
}
static inline void pl011_write_cr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTCR, val);
}
static inline void pl011_write_dr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTDR, val);
}
/*******************************************************************************
* Pl011 CPU interface accessors for reading registers
******************************************************************************/
static inline unsigned int pl011_read_fr(unsigned long base)
{
return mmio_read_32(base + UARTFR);
}
static inline unsigned int pl011_read_dr(unsigned long base)
{
return mmio_read_32(base + UARTDR);
}
/*******************************************************************************
* Function prototypes
******************************************************************************/
void pl011_setbaudrate(unsigned long base_addr, unsigned int baudrate);
#endif /* __PL011_H__ */ #endif /* __PL011_H__ */
...@@ -45,8 +45,7 @@ $(eval $(call add_define,TSP_RAM_LOCATION_ID)) ...@@ -45,8 +45,7 @@ $(eval $(call add_define,TSP_RAM_LOCATION_ID))
PLAT_INCLUDES := -Iplat/fvp/include/ PLAT_INCLUDES := -Iplat/fvp/include/
PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011.c \ PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011_console.S \
drivers/arm/pl011/pl011_console.c \
drivers/io/io_fip.c \ drivers/io/io_fip.c \
drivers/io/io_memmap.c \ drivers/io/io_memmap.c \
drivers/io/io_semihosting.c \ drivers/io/io_semihosting.c \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment