mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
stm32mp1: Add console support
Signed-off-by: Yann Gautier <yann.gautier@st.com> Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com> Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
This commit is contained in:
parent
e58a53fb72
commit
278c34df06
5 changed files with 391 additions and 0 deletions
|
@ -5,6 +5,25 @@
|
|||
*/
|
||||
#include <asm_macros.S>
|
||||
|
||||
#define USART_TIMEOUT 0x1000
|
||||
|
||||
#define USART_CR1 0x00
|
||||
#define USART_CR1_UE 0x00000001
|
||||
#define USART_CR1_TE 0x00000008
|
||||
#define USART_CR1_FIFOEN 0x20000000
|
||||
|
||||
#define USART_CR2 0x04
|
||||
#define USART_CR2_STOP 0x00003000
|
||||
|
||||
#define USART_BRR 0x0C
|
||||
|
||||
#define USART_ISR 0x1C
|
||||
#define USART_ISR_TC 0x00000040
|
||||
#define USART_ISR_TXE 0x00000080
|
||||
#define USART_ISR_TEACK 0x00200000
|
||||
|
||||
#define USART_TDR 0x28
|
||||
|
||||
.globl console_core_init
|
||||
.globl console_core_putc
|
||||
.globl console_core_getc
|
||||
|
@ -27,6 +46,47 @@
|
|||
* -----------------------------------------------------------------
|
||||
*/
|
||||
func console_core_init
|
||||
/* Check the input base address */
|
||||
cmp r0, #0
|
||||
beq core_init_fail
|
||||
#if defined(IMAGE_BL2)
|
||||
/* Check baud rate and uart clock for sanity */
|
||||
cmp r1, #0
|
||||
beq core_init_fail
|
||||
cmp r2, #0
|
||||
beq core_init_fail
|
||||
/* Disable UART */
|
||||
ldr r3, [r0, #USART_CR1]
|
||||
bic r3, r3, #USART_CR1_UE
|
||||
str r3, [r0, #USART_CR1]
|
||||
/* Configure UART */
|
||||
orr r3, r3, #(USART_CR1_TE | USART_CR1_FIFOEN)
|
||||
str r3, [r0, #USART_CR1]
|
||||
ldr r3, [r0, #USART_CR2]
|
||||
bic r3, r3, #USART_CR2_STOP
|
||||
str r3, [r0, #USART_CR2]
|
||||
/* Divisor = (Uart clock + (baudrate / 2)) / baudrate */
|
||||
lsl r3, r2, #1
|
||||
add r3, r1, r3
|
||||
udiv r3, r3, r2
|
||||
str r3, [r0, #USART_BRR]
|
||||
/* Enable UART */
|
||||
ldr r3, [r0, #USART_CR1]
|
||||
orr r3, r3, #USART_CR1_UE
|
||||
str r3, [r0, #USART_CR1]
|
||||
/* Check TEACK bit */
|
||||
mov r2, #USART_TIMEOUT
|
||||
teack_loop:
|
||||
subs r2, r2, #1
|
||||
beq core_init_fail
|
||||
ldr r3, [r0, #USART_ISR]
|
||||
tst r3, #USART_ISR_TEACK
|
||||
beq teack_loop
|
||||
#endif /* IMAGE_BL2 */
|
||||
mov r0, #1
|
||||
bx lr
|
||||
core_init_fail:
|
||||
mov r0, #0
|
||||
bx lr
|
||||
endfunc console_core_init
|
||||
|
||||
|
@ -43,6 +103,40 @@ endfunc console_core_init
|
|||
* ---------------------------------------------------------------
|
||||
*/
|
||||
func console_core_putc
|
||||
/* Check the input parameter */
|
||||
cmp r1, #0
|
||||
beq putc_error
|
||||
/* Prepend '\r' to '\n' */
|
||||
cmp r0, #0xA
|
||||
bne 2f
|
||||
1:
|
||||
/* Check Transmit Data Register Empty */
|
||||
txe_loop_1:
|
||||
ldr r2, [r1, #USART_ISR]
|
||||
tst r2, #USART_ISR_TXE
|
||||
beq txe_loop_1
|
||||
mov r2, #0xD
|
||||
str r2, [r1, #USART_TDR]
|
||||
/* Check transmit complete flag */
|
||||
tc_loop_1:
|
||||
ldr r2, [r1, #USART_ISR]
|
||||
tst r2, #USART_ISR_TC
|
||||
beq tc_loop_1
|
||||
2:
|
||||
/* Check Transmit Data Register Empty */
|
||||
txe_loop_2:
|
||||
ldr r2, [r1, #USART_ISR]
|
||||
tst r2, #USART_ISR_TXE
|
||||
beq txe_loop_2
|
||||
str r0, [r1, #USART_TDR]
|
||||
/* Check transmit complete flag */
|
||||
tc_loop_2:
|
||||
ldr r2, [r1, #USART_ISR]
|
||||
tst r2, #USART_ISR_TC
|
||||
beq tc_loop_2
|
||||
bx lr
|
||||
putc_error:
|
||||
mov r0, #-1
|
||||
bx lr
|
||||
endfunc console_core_putc
|
||||
|
||||
|
@ -75,5 +169,16 @@ endfunc console_core_getc
|
|||
* ---------------------------------------------------------------
|
||||
*/
|
||||
func console_core_flush
|
||||
cmp r0, #0
|
||||
beq flush_error
|
||||
/* Check Transmit Data Register Empty */
|
||||
txe_loop_3:
|
||||
ldr r1, [r0, #USART_ISR]
|
||||
tst r1, #USART_ISR_TXE
|
||||
beq txe_loop_3
|
||||
mov r0, #0
|
||||
bx lr
|
||||
flush_error:
|
||||
mov r0, #-1
|
||||
bx lr
|
||||
endfunc console_core_flush
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <stm32mp1_context.h>
|
||||
#include <stm32mp1_pwr.h>
|
||||
#include <stm32mp1_rcc.h>
|
||||
#include <stm32mp1_reset.h>
|
||||
#include <string.h>
|
||||
#include <xlat_tables_v2.h>
|
||||
|
||||
|
@ -38,8 +39,12 @@ void bl2_platform_setup(void)
|
|||
|
||||
void bl2_el3_plat_arch_setup(void)
|
||||
{
|
||||
int32_t result;
|
||||
struct dt_node_info dt_dev_info;
|
||||
const char *board_model;
|
||||
boot_api_context_t *boot_context =
|
||||
(boot_api_context_t *)stm32mp1_get_boot_ctx_address();
|
||||
uint32_t clk_rate;
|
||||
|
||||
/*
|
||||
* Disable the backup domain write protection.
|
||||
|
@ -94,6 +99,42 @@ void bl2_el3_plat_arch_setup(void)
|
|||
panic();
|
||||
}
|
||||
|
||||
result = dt_get_stdout_uart_info(&dt_dev_info);
|
||||
|
||||
if ((result <= 0) ||
|
||||
(dt_dev_info.status == 0U) ||
|
||||
(dt_dev_info.clock < 0) ||
|
||||
(dt_dev_info.reset < 0)) {
|
||||
goto skip_console_init;
|
||||
}
|
||||
|
||||
if (dt_set_stdout_pinctrl() != 0) {
|
||||
goto skip_console_init;
|
||||
}
|
||||
|
||||
if (stm32mp1_clk_enable((unsigned long)dt_dev_info.clock) != 0) {
|
||||
goto skip_console_init;
|
||||
}
|
||||
|
||||
stm32mp1_reset_assert((uint32_t)dt_dev_info.reset);
|
||||
udelay(2);
|
||||
stm32mp1_reset_deassert((uint32_t)dt_dev_info.reset);
|
||||
mdelay(1);
|
||||
|
||||
clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_dev_info.clock);
|
||||
|
||||
if (console_init(dt_dev_info.base, clk_rate,
|
||||
STM32MP1_UART_BAUDRATE) == 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
board_model = dt_get_board_model();
|
||||
if (board_model != NULL) {
|
||||
NOTICE("%s\n", board_model);
|
||||
}
|
||||
|
||||
skip_console_init:
|
||||
|
||||
if (stm32_save_boot_interface(boot_context->boot_interface_selected,
|
||||
boot_context->boot_interface_instance) !=
|
||||
0) {
|
||||
|
|
|
@ -9,6 +9,14 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct dt_node_info {
|
||||
uint32_t base;
|
||||
int32_t clock;
|
||||
int32_t reset;
|
||||
bool status;
|
||||
bool sec_status;
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Function and variable prototypes
|
||||
******************************************************************************/
|
||||
|
@ -22,5 +30,11 @@ uint32_t fdt_read_uint32_default(int node, const char *prop_name,
|
|||
int fdt_read_uint32_array(int node, const char *prop_name,
|
||||
uint32_t *array, uint32_t count);
|
||||
int dt_set_pinctrl_config(int node);
|
||||
int dt_set_stdout_pinctrl(void);
|
||||
void dt_fill_device_info(struct dt_node_info *info, int node);
|
||||
int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
|
||||
int dt_get_stdout_uart_info(struct dt_node_info *info);
|
||||
int dt_get_stdout_node_offset(void);
|
||||
const char *dt_get_board_model(void);
|
||||
|
||||
#endif /* __STM32MP1_DT_H__ */
|
||||
|
|
|
@ -309,3 +309,148 @@ int dt_set_pinctrl_config(int node)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function gets the stdout pin configuration information from the DT.
|
||||
* And then calls the sub-function to treat it and set GPIO registers.
|
||||
* Returns 0 if success, and a negative value else.
|
||||
******************************************************************************/
|
||||
int dt_set_stdout_pinctrl(void)
|
||||
{
|
||||
int node;
|
||||
|
||||
node = dt_get_stdout_node_offset();
|
||||
if (node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
return dt_set_pinctrl_config(node);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function fills the generic information from a given node.
|
||||
******************************************************************************/
|
||||
void dt_fill_device_info(struct dt_node_info *info, int node)
|
||||
{
|
||||
const fdt32_t *cuint;
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "reg", NULL);
|
||||
if (cuint != NULL) {
|
||||
info->base = fdt32_to_cpu(*cuint);
|
||||
} else {
|
||||
info->base = 0;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
||||
if (cuint != NULL) {
|
||||
cuint++;
|
||||
info->clock = (int)fdt32_to_cpu(*cuint);
|
||||
} else {
|
||||
info->clock = -1;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "resets", NULL);
|
||||
if (cuint != NULL) {
|
||||
cuint++;
|
||||
info->reset = (int)fdt32_to_cpu(*cuint);
|
||||
} else {
|
||||
info->reset = -1;
|
||||
}
|
||||
|
||||
info->status = fdt_check_status(node);
|
||||
info->sec_status = fdt_check_secure_status(node);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function retrieve the generic information from DT.
|
||||
* Returns node if success, and a negative value else.
|
||||
******************************************************************************/
|
||||
int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
|
||||
{
|
||||
int node;
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, offset, compat);
|
||||
if (node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
dt_fill_device_info(info, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function gets the UART instance info of stdout from the DT.
|
||||
* Returns node if success, and a negative value else.
|
||||
******************************************************************************/
|
||||
int dt_get_stdout_uart_info(struct dt_node_info *info)
|
||||
{
|
||||
int node;
|
||||
|
||||
node = dt_get_stdout_node_offset();
|
||||
if (node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
dt_fill_device_info(info, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function gets the stdout path node.
|
||||
* It reads the value indicated inside the device tree.
|
||||
* Returns node if success, and a negative value else.
|
||||
******************************************************************************/
|
||||
int dt_get_stdout_node_offset(void)
|
||||
{
|
||||
int node;
|
||||
const char *cchar;
|
||||
|
||||
node = fdt_path_offset(fdt, "/chosen");
|
||||
if (node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
|
||||
if (cchar == NULL) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
node = -FDT_ERR_NOTFOUND;
|
||||
if (strchr(cchar, (int)':') != NULL) {
|
||||
const char *name;
|
||||
char *str = (char *)cchar;
|
||||
int len = 0;
|
||||
|
||||
while (strncmp(":", str, 1)) {
|
||||
len++;
|
||||
str++;
|
||||
}
|
||||
|
||||
name = fdt_get_alias_namelen(fdt, cchar, len);
|
||||
|
||||
if (name != NULL) {
|
||||
node = fdt_path_offset(fdt, name);
|
||||
}
|
||||
} else {
|
||||
node = fdt_path_offset(fdt, cchar);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function retrieves board model from DT
|
||||
* Returns string taken from model node, NULL otherwise
|
||||
******************************************************************************/
|
||||
const char *dt_get_board_model(void)
|
||||
{
|
||||
int node = fdt_path_offset(fdt, "/");
|
||||
|
||||
if (node < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (const char *)fdt_getprop(fdt, node, "model", NULL);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,14 @@
|
|||
#include <asm_macros.S>
|
||||
#include <bl_common.h>
|
||||
#include <platform_def.h>
|
||||
#include <stm32_gpio.h>
|
||||
#include <stm32mp1_rcc.h>
|
||||
|
||||
#define GPIO_BANK_G_ADDRESS 0x50008000
|
||||
#define GPIO_TX_PORT 11
|
||||
#define GPIO_TX_SHIFT (GPIO_TX_PORT << 1)
|
||||
#define GPIO_TX_ALT_SHIFT ((GPIO_TX_PORT - GPIO_ALT_LOWER_LIMIT) << 2)
|
||||
#define STM32MP1_HSI_CLK 64000000
|
||||
|
||||
.globl platform_mem_init
|
||||
.globl plat_report_exception
|
||||
|
@ -16,6 +24,9 @@
|
|||
.globl plat_reset_handler
|
||||
.globl plat_is_my_cpu_primary
|
||||
.globl plat_my_core_pos
|
||||
.globl plat_crash_console_init
|
||||
.globl plat_crash_console_flush
|
||||
.globl plat_crash_console_putc
|
||||
.globl plat_panic_handler
|
||||
|
||||
func platform_mem_init
|
||||
|
@ -92,3 +103,78 @@ func plat_my_core_pos
|
|||
ldcopr r0, MPIDR
|
||||
b plat_stm32mp1_get_core_pos
|
||||
endfunc plat_my_core_pos
|
||||
|
||||
/* ---------------------------------------------
|
||||
* int plat_crash_console_init(void)
|
||||
*
|
||||
* Initialize the crash console without a C Runtime stack.
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_init
|
||||
/* Enable GPIOs for UART4 TX */
|
||||
ldr r1, =(RCC_BASE + RCC_MP_AHB4ENSETR)
|
||||
ldr r2, [r1]
|
||||
/* Configure GPIO G11 */
|
||||
orr r2, r2, #RCC_MP_AHB4ENSETR_GPIOGEN
|
||||
str r2, [r1]
|
||||
ldr r1, =GPIO_BANK_G_ADDRESS
|
||||
/* Set GPIO mode alternate */
|
||||
ldr r2, [r1, #GPIO_MODE_OFFSET]
|
||||
bic r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT)
|
||||
orr r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT)
|
||||
str r2, [r1, #GPIO_MODE_OFFSET]
|
||||
/* Set GPIO speed low */
|
||||
ldr r2, [r1, #GPIO_SPEED_OFFSET]
|
||||
bic r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT)
|
||||
str r2, [r1, #GPIO_SPEED_OFFSET]
|
||||
/* Set no-pull */
|
||||
ldr r2, [r1, #GPIO_PUPD_OFFSET]
|
||||
bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT)
|
||||
str r2, [r1, #GPIO_PUPD_OFFSET]
|
||||
/* Set alternate AF6 */
|
||||
ldr r2, [r1, #GPIO_AFRH_OFFSET]
|
||||
bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT)
|
||||
orr r2, r2, #(GPIO_ALTERNATE_6 << GPIO_TX_ALT_SHIFT)
|
||||
str r2, [r1, #GPIO_AFRH_OFFSET]
|
||||
|
||||
/* Enable UART clock, with HSI source */
|
||||
ldr r1, =(RCC_BASE + RCC_UART24CKSELR)
|
||||
mov r2, #RCC_UART24CKSELR_HSI
|
||||
str r2, [r1]
|
||||
ldr r1, =(RCC_BASE + RCC_MP_APB1ENSETR)
|
||||
ldr r2, [r1]
|
||||
orr r2, r2, #RCC_MP_APB1ENSETR_UART4EN
|
||||
str r2, [r1]
|
||||
|
||||
ldr r0, =STM32MP1_DEBUG_USART_BASE
|
||||
ldr r1, =STM32MP1_HSI_CLK
|
||||
ldr r2, =STM32MP1_UART_BAUDRATE
|
||||
b console_core_init
|
||||
endfunc plat_crash_console_init
|
||||
|
||||
/* ---------------------------------------------
|
||||
* int plat_crash_console_flush(void)
|
||||
*
|
||||
* Flush the crash console without a C Runtime stack.
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_flush
|
||||
ldr r1, =STM32MP1_DEBUG_USART_BASE
|
||||
b console_core_flush
|
||||
endfunc plat_crash_console_flush
|
||||
|
||||
/* ---------------------------------------------
|
||||
* int plat_crash_console_putc(int c)
|
||||
*
|
||||
* Print a character on the crash console without a C Runtime stack.
|
||||
* Clobber list : r1 - r3
|
||||
*
|
||||
* In case of bootloading through uart, we keep console crash as this.
|
||||
* Characters could be sent to the programmer, but will be ignored.
|
||||
* No specific code in that case.
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_putc
|
||||
ldr r1, =STM32MP1_DEBUG_USART_BASE
|
||||
b console_core_putc
|
||||
endfunc plat_crash_console_putc
|
||||
|
|
Loading…
Add table
Reference in a new issue