am335x UART1输入u-boot 调试信息代码修改

时间:2023-03-08 15:40:49
am335x UART1输入u-boot 调试信息代码修改

AM335x 调试信息UART1输出代码修改
1. 关于pin_mux  的配置
代码修改位置:
/board/forlinx/ok335x/mux.c

 void enable_uart0_pin_mux(void)
{
configure_module_pin_mux(uart0_pin_mux_spl);
configure_module_pin_mux(uart1_pin_mux);
}

将这行代码打开。

代码跟踪流程:
arch/arm/cpu/armv7/start.S :
开头的_start 函数:

 .globl _start
_start: b reset

从reset 函数跳入cpu_init_crit 函数,还是在本文件内:

 reset:
bl save_boot_params
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
//......
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
//......

从cpu_init_crit 函数进入lowlevel_init 函数。

这个函数在arch/arm/cpu/armv7/ti81xx/lowlevel_init.S 文件内。

 /*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************/
cpu_init_crit:
/*
* Invalidate L1 I/D
*/
mov r0, # @ set up for MCR
mcr p15, , r0, c8, c7, @ invalidate TLBs
mcr p15, , r0, c7, c5, @ invalidate icache
mcr p15, , r0, c7, c5, @ invalidate BP array
mcr p15, , r0, c7, c10, @ DSB
mcr p15, , r0, c7, c5, @ ISB
//......
bl lowlevel_init @ go setup pll,mux,memory
//......

从lowlevel_init 函数进入s_init_start 函数。

 /*****************************************************************************
* lowlevel_init: - Platform low level init.
* Corrupted Register : r0, r1, r2, r3, r4, r5, r6
****************************************************************************/
.globl lowlevel_init
lowlevel_init: /* The link register is saved in ip by start.S */
mov r6, ip
/* check if we are already running from RAM */
ldr r2, _lowlevel_init
ldr r3, _TEXT_BASE
sub r4, r2, r3
sub r0, pc, r4
//......
ands r0, r0, #0xC0000000 /* MSB 2 bits <> 0 then we are in ocmc or DDR */
cmp r0, #0x80000000
bne s_init_start
mov r10, #0x01
b s_init_start //......

从s_init_start 函数进入s_init 函数。

 s_init_start:
mov r0, r10 /* passing in_ddr in r0 */
bl s_init
/* back to arch calling code */
mov pc, r6
/* the literal pools origin */
.ltorg
 /*
* early system init of muxing and clocks.
*/
void s_init(void)
{
/* Can be removed as A8 comes up with L2 enabled */
l2_cache_enable(); /* WDT1 is already running when the bootloader gets control
* Disable it to avoid "random" resets
*/
__raw_writel(0xAAAA, WDT_WSPR);
while(__raw_readl(WDT_WWPS) != 0x0);
__raw_writel(0x5555, WDT_WSPR);
while(__raw_readl(WDT_WWPS) != 0x0); //......
pll_init();
//......
enable_uart0_pin_mux(); //......

这个函数的实现在board/forlinx/ok335x/evm.c 文件内.

从这里进入enable_uart0_pin_mux() ;

 void enable_uart0_pin_mux(void)
{
configure_module_pin_mux(uart0_pin_mux_spl);
configure_module_pin_mux(uart1_pin_mux);
}

这函数的实现在board/forlinx/ok335x/mux.c 文件内。

把这个uart1_pin_mux 的功能打开。

2. 关于uart1 时钟的配置
代码添加位置:
board/forlinx/ok335x/pll.c
per_clocks_enable 函数内,添加对uart1 始终的配置。

change by chen 2016/9/30 的即是我修改的。

 static void per_clocks_enable(void)
{
/* Enable the module clock */
__raw_writel(PRCM_MOD_EN, CM_PER_TIMER2_CLKCTRL);
while (__raw_readl(CM_PER_TIMER2_CLKCTRL) != PRCM_MOD_EN); /* Select the Master osc 24 MHZ as Timer2 clock source */
__raw_writel(0x1, CLKSEL_TIMER2_CLK); /* UART0 */
__raw_writel(PRCM_MOD_EN, CM_WKUP_UART0_CLKCTRL);
while (__raw_readl(CM_WKUP_UART0_CLKCTRL) != PRCM_MOD_EN); /* change by chen 2016/9/30 */
__raw_writel(PRCM_MOD_EN, CM_PER_UART1_CLKCTRL);
while (__raw_readl(CM_PER_UART1_CLKCTRL) != PRCM_MOD_EN); /* UART3 */
__raw_writel(PRCM_MOD_EN, CM_PER_UART3_CLKCTRL);
while (__raw_readl(CM_PER_UART3_CLKCTRL) != PRCM_MOD_EN); /* GPMC */
__raw_writel(PRCM_MOD_EN, CM_PER_GPMC_CLKCTRL);
while (__raw_readl(CM_PER_GPMC_CLKCTRL) != PRCM_MOD_EN);
//.....
}

CM_PER_UART1_CLKCTR的宏定义设置在arch/arm/include/asm/arch-ti81xx/cpu.h文件内。

添加这一条宏定义。

 #define CM_PER_UART1_CLKCTRL        (CM_PER + 0x6C) /* UART1 */
#define CM_PER_UART3_CLKCTRL (CM_PER + 0x74) /* UART3 */

代码修改跟踪流程:

在上面已经跟踪的s_init 函数里面。

再进入pll_init () 函数。

 /*
* Configure the PLL/PRCM for necessary peripherals
*/
void pll_init()
{ // mpu_pll_config(MPUPLL_M_500);
mpu_pll_config(MPUPLL_M_720);
core_pll_config();
per_pll_config();
ddr_pll_config();
/* Enable the required interconnect clocks */
interface_clocks_enable();
/* Enable power domain transition */
power_domain_transition_enable();
/* Enable the required peripherals */
per_clocks_enable();
}

这个函数的实现在:board/forlinx/ok335x/pll.c

再进入per_clocks_enable()函数内,这个函数在本文件内实现。

 /*
* Enable the module clock and the power domain for required peripherals
*/
static void per_clocks_enable(void)
{
/* Enable the module clock */
__raw_writel(PRCM_MOD_EN, CM_PER_TIMER2_CLKCTRL);
while (__raw_readl(CM_PER_TIMER2_CLKCTRL) != PRCM_MOD_EN); /* Select the Master osc 24 MHZ as Timer2 clock source */
__raw_writel(0x1, CLKSEL_TIMER2_CLK); /* UART0 */
__raw_writel(PRCM_MOD_EN, CM_WKUP_UART0_CLKCTRL);
while (__raw_readl(CM_WKUP_UART0_CLKCTRL) != PRCM_MOD_EN); /* change by chen 2016/9/30 */
__raw_writel(PRCM_MOD_EN, CM_PER_UART1_CLKCTRL);
while (__raw_readl(CM_PER_UART1_CLKCTRL) != PRCM_MOD_EN);
// ..................................
}

3. 关于include/configs/ok335x.h配置
代码修改位置:

 #define CONFIG_SYS_NS16550_COM2     0x48022000   /* UART1 sbc-7109 */

 #define CONFIG_SERIAL2          1
#define CONFIG_CONS_INDEX 2

如上所示,添加这三个宏定义。
CONFIG_CONS_INDEX 这个为修改,原来uart0 输出调试信息的时候是为1。

代码跟踪流程:
arch/arm/cpu/armv7/start.S :从_start 进入reset 函数。

 /* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, # /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f

再进入board_init_f 函数。

这个函数的实现在:
arch/arm/lib/board.c 文件内。

 void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp; /* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory"); memset((void *)gd, , sizeof(gd_t)); gd->mon_len = _bss_end_ofs; for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != ) {
hang ();
}
}
//......
}

在这个函数内有for循环运行一系列的初始化。

这个数组有如下定义:

 init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
//.......
}

再进入serial_init 串行通信初始化。

这个函数的实现在:drivers/serial/serial.c 文件后内。

 #if !defined(CONFIG_SERIAL_MULTI)
int serial_init (void)
{ int clock_divisor; #ifdef CONFIG_NS87308
initialise_ns87308();
#endif #ifdef CONFIG_SYS_NS16550_COM1
clock_divisor = calc_divisor(serial_ports[]);
NS16550_init(serial_ports[], clock_divisor);
#endif
#ifdef CONFIG_SYS_NS16550_COM2
clock_divisor = calc_divisor(serial_ports[]);
NS16550_init(serial_ports[], clock_divisor);
#endif
#ifdef CONFIG_SYS_NS16550_COM3
clock_divisor = calc_divisor(serial_ports[]);
NS16550_init(serial_ports[], clock_divisor);
#endif
//......
}

第一个CONFIG_SYS_NS16550_COM1为UART0的串口初始化。

第二个CONFIG_SYS_NS16550_COM2要自己定义,在include/configs/ok335x.h 内添加。

 #define CONFIG_SYS_NS16550_COM2     0x48022000   /* UART1 sbc-7109 */           

这里的话只是完成了初始化,但是还要指定调试信息输出的端口。

回到arch/arm/lib/board.c
进入display_banner 函数,这个函数的实现在本文件内实现。

 static int display_banner(void)
{
printf("\n\n%s\n\n", version_string);
printf("chen goto it ....\n") ;
debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
_TEXT_BASE,
_bss_start_ofs + _TEXT_BASE, _bss_end_ofs + _TEXT_BASE);
#ifdef CONFIG_MODEM_SUPPORT
debug("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif return ();
}

进入printf 函数,这个函数在/common/console.c 文件内实现。

 int printf(const char *fmt, ...)
{
va_list args;
uint i;
char printbuffer[CONFIG_SYS_PBSIZE]; va_start(args, fmt); /* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf(printbuffer, fmt, args);
va_end(args); /* Print the string */
puts(printbuffer);
return i;
}

还是在本文件内,进入puts 函数:

 void puts(const char *s)
{
#ifdef CONFIG_SILENT_CONSOLE
if (gd->flags & GD_FLG_SILENT)
return;
#endif #ifdef CONFIG_DISABLE_CONSOLE
if (gd->flags & GD_FLG_DISABLE_CONSOLE)
return;
#endif if (gd->flags & GD_FLG_DEVINIT) {
/* Send to the standard output */
fputs(stdout, s);
} else {
/* Send directly to the handler */
serial_puts(s);
}
}


再进入serial_puts 函数,这个函数的实现在drivers/serial/serial.c文件内实现。

 void
serial_puts(const char *s)
{
_serial_puts(s,CONFIG_CONS_INDEX);
}


这里指定了输出的端口,这个宏定义也是在include/configs/ok335x.h 里面定义:

 #define CONFIG_CONS_INDEX       2        

到此,在u-boot 阶段串口输出的调试信息即可以在UART1输出。

4. 关于kernel 调试信息的打印配置
在u-boot 文件夹内
include/configs/ok335x.h
将console=ttyO1 这样的话kernel 的调试信息也将在UART1输出。

 #ifdef CONFIG_ANDROID
#define CON \
"console=ttyO0,115200n8 earlyprintk androidboot.console=ttyO0\0" \
"optargs=init=/init\0" \
"mmcroot=/dev/mmcblk0p2 rw\0" \
"mmcrootfstype=ext4 rootwait\0" \
"nandroot=ubi0:rootfs rw ubi.mtd=7,2048\0" \
"nandrootfstype=ubifs rootwait=1\0"
#else
#define CON \
"console=ttyO1,115200n8\0" \
"optargs=\0" \
"mmcroot=/dev/mmcblk0p2 ro\0" \
"mmcrootfstype=ext3 rootwait\0" \
"nandroot=ubi0:rootfs rw ubi.mtd=7,2048\0" \
"nandrootfstype=ubifs rootwait=1\0"
#endif

5. 关于文件系统调试信息的配置
在文件系统目录。
etc/inittab

46行位UART1 输出,45行为UART0输出。

  #::respawn:/sbin/getty  ttyO0
::respawn:/sbin/getty ttyO1