*/
#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
* -----------------------------------------------------------------
*/
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
* ---------------------------------------------------------------
*/
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
* ---------------------------------------------------------------
*/
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
#include <stm32mp1_context.h>
#include <stm32mp1_pwr.h>
#include <stm32mp1_rcc.h>
+#include <stm32mp1_reset.h>
#include <string.h>
#include <xlat_tables_v2.h>
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.
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) {
#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
******************************************************************************/
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__ */
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);
+}
#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
.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
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