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:
Yann Gautier 2018-07-05 16:48:16 +02:00
parent e58a53fb72
commit 278c34df06
5 changed files with 391 additions and 0 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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