diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index f7e1755ea1..c6a9c90828 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -84,6 +84,7 @@ ENTRY(_main) /* set up gd here, outside any C code */ mov r9, r0 bl board_init_f_init_reserve + bl board_init_f_init_serial mov r0, #0 bl board_init_f diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S index 9cb70552fe..bac5de4081 100644 --- a/arch/arm/lib/crt0_64.S +++ b/arch/arm/lib/crt0_64.S @@ -83,6 +83,7 @@ ENTRY(_main) /* set up gd here, outside any C code */ mov x18, x0 bl board_init_f_init_reserve + bl board_init_f_init_serial mov x0, #0 bl board_init_f diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 02e0269e94..fe90a710b3 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -519,6 +519,13 @@ config ROCKCHIP_PRELOADER_ATAGS tos, U-Boot, etc. It delivers boot and configure information, shared with pre-loaders and finally ends with U-Boot. +config ROCKCHIP_PRELOADER_SERIAL + bool "Rockchip pre-loader serial" + default y if ROCKCHIP_PRELOADER_ATAGS + help + This enable U-Boot using pre-loader atags serial configure to initialize console. + It denpends on serial aliases to find pre-loader serial number. + config GICV2 bool "ARM GICv2" diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c index 9e3f5cfed5..954e17d8c3 100644 --- a/arch/arm/mach-rockchip/board.c +++ b/arch/arm/mach-rockchip/board.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef CONFIG_DM_CHARGE_DISPLAY #include #endif @@ -274,6 +275,27 @@ void enable_caches(void) dcache_enable(); } +#ifdef CONFIG_ROCKCHIP_PRELOADER_SERIAL +int board_init_f_init_serial(void) +{ + struct tag *t = atags_get_tag(ATAG_SERIAL); + + if (t) { + gd->serial.using_pre_serial = t->u.serial.enable; + gd->serial.addr = t->u.serial.addr; + gd->serial.baudrate = t->u.serial.baudrate; + gd->serial.id = t->u.serial.id; + + debug("%s: enable=%d, addr=0x%lx, baudrate=%d, id=%d\n", + __func__, gd->serial.using_pre_serial, + gd->serial.addr, gd->serial.baudrate, + gd->serial.id); + } + + return 0; +} +#endif + #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG) #include #include diff --git a/common/board_f.c b/common/board_f.c index f76f7da756..8ce40bef74 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -117,7 +117,11 @@ __weak void board_add_ram_info(int use_default) static int init_baud_rate(void) { - gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE); + if (gd && gd->serial.using_pre_serial) + gd->baudrate = env_get_ulong("baudrate", 10, gd->serial.baudrate); + else + gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE); + return 0; } @@ -142,6 +146,16 @@ static int display_text_info(void) return 0; } +#if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) +static int announce_pre_serial(void) +{ + if (gd && gd->serial.using_pre_serial) + printf("PreSerial: %d\n", gd->serial.id); + + return 0; +} +#endif + static int announce_dram_init(void) { puts("DRAM: "); @@ -803,6 +817,9 @@ static const init_fnc_t init_sequence_f[] = { #endif #if defined(CONFIG_HARD_SPI) init_func_spi, +#endif +#if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) + announce_pre_serial, #endif announce_dram_init, dram_init, /* configure available RAM banks */ diff --git a/common/board_r.c b/common/board_r.c index 818543446b..3885fd4c66 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -172,7 +172,22 @@ static int initr_reloc_global_data(void) static int initr_serial(void) { +/* + * 1. Serial has been initialized in board_f.c => serial_init(), there is + * no special reason to init it again; + * + * 2. Pre-serial works depending on aliases to get pre-serial phandle when + * parse dtb. If CONFIG_USING_KERNEL_DTB is enabled, there are both kernel + * dtb and U-Boot dtb aliases added into aliases_lookup, these nodes have + * same names but different phanles(U-Boot nodes has high prior), this may + * lead a wrong aliases node finding if try to get a node after kenrel dtb + * unflattened, i.e. using U-Boot phandle to get kernel dtb node!! + * + * Notice: of_alias_dump() is provided to dump all aliases node. + */ +#ifndef CONFIG_USING_KERNEL_DTB serial_initialize(); +#endif return 0; } diff --git a/common/init/board_init.c b/common/init/board_init.c index 4a391beba9..9269ca858d 100644 --- a/common/init/board_init.c +++ b/common/init/board_init.c @@ -129,6 +129,14 @@ void board_init_f_init_reserve(ulong base) #endif } +/* + * Board-specific Platform code can init serial earlier if needed + */ +__weak int board_init_f_init_serial(void) +{ + return 0; +} + /* * Board-specific Platform code can reimplement show_boot_progress () if needed */ diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index ff7be7b5b5..92443d401c 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -804,5 +804,17 @@ struct device_node *of_alias_dump(void) struct device_node *of_get_stdout(void) { + struct device_node *np; + + if (gd && gd->serial.using_pre_serial) { + np = of_alias_get_dev("serial", gd->serial.id); + if (!np) + printf("Can't find alias serial%d\n", gd->serial.id); + else + debug("Find alias serial: %s\n", np->full_name); + + of_stdout = np; + } + return of_stdout; } diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index ad7a3d77ab..6f2ee6960d 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -254,6 +254,13 @@ static inline void _debug_uart_init(void) */ baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); + + if (gd && gd->serial.using_pre_serial) { + com_port = (struct NS16550 *)gd->serial.addr; + baud_divisor = ns16550_calc_divisor(com_port, + CONFIG_DEBUG_UART_CLOCK, gd->serial.baudrate); + } + serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); serial_dout(&com_port->mcr, UART_MCRVAL); serial_dout(&com_port->fcr, UART_FCR_DEFVAL); @@ -268,6 +275,9 @@ static inline void _debug_uart_putc(int ch) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; + if (gd && gd->serial.using_pre_serial) + com_port = (struct NS16550 *)gd->serial.addr; + while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) ; serial_dout(&com_port->thr, ch); @@ -288,6 +298,13 @@ static inline void _debug_uart_init(void) baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); + + if (gd && gd->serial.using_pre_serial) { + com_port = (struct NS16550 *)gd->serial.addr; + baud_divisor = ns16550_calc_divisor(com_port, + CONFIG_DEBUG_UART_CLOCK, gd->serial.baudrate); + } + serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER); serial_dout(&com_port->mdr1, 0x7); serial_dout(&com_port->mcr, UART_MCRVAL); @@ -304,6 +321,9 @@ static inline void _debug_uart_putc(int ch) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; + if (gd && gd->serial.using_pre_serial) + com_port = (struct NS16550 *)gd->serial.addr; + while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) ; serial_dout(&com_port->thr, ch); @@ -456,6 +476,10 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) #ifdef CONFIG_SYS_NS16550_PORT_MAPPED plat->base = addr; #else + + if (gd && gd->serial.using_pre_serial) + addr = gd->serial.addr; + plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE); #endif diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 2e5116f7ce..0c7a4d7c87 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -54,6 +54,23 @@ static int serial_check_stdout(const void *blob, struct udevice **devp) } if (node < 0) node = fdt_path_offset(blob, "console"); + + if (gd && gd->serial.using_pre_serial) { + const char *serial_path; + char serial[12]; + + snprintf(serial, 12, "serial%d", gd->serial.id); + serial_path = fdt_get_alias(blob, serial); + if (serial_path) { + debug("Find alias %s, path: %s\n", serial, serial_path); + node = fdt_path_offset(blob, serial_path); + if (node < 0) + printf("Can't find %s by path\n", serial); + } else { + printf("Can't find alias %s\n", serial); + } + } + if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, devp)) return 0; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index b46e542500..17103318b8 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -31,6 +31,13 @@ struct pm_ctx { unsigned long suspend_regs[15]; }; +struct pre_serial { + u32 using_pre_serial; + u32 id; + u32 baudrate; + ulong addr; +}; + typedef struct global_data { bd_t *bd; unsigned long flags; @@ -126,7 +133,7 @@ typedef struct global_data { #ifdef CONFIG_BOOTSTAGE_PRINTF_TIMESTAMP int new_line; #endif - + struct pre_serial serial; #ifdef CONFIG_LOG int log_drop_count; /* Number of dropped log messages */ int default_log_level; /* For devices with no filters */ diff --git a/include/common.h b/include/common.h index 7c42b6453d..1c280d86f8 100644 --- a/include/common.h +++ b/include/common.h @@ -144,6 +144,11 @@ ulong board_init_f_alloc_reserve(ulong top); */ void board_init_f_init_reserve(ulong base); +/* + * Board-specific Platform code can init serial earlier if needed + */ +__weak int board_init_f_init_serial(void); + /** * arch_setup_gd() - Set up the global_data pointer *