am335x UART1输入u-boot 调试信息代码修改
AM335x 调试信息UART1输出代码修改
1. 关于pin_mux 的配置
代码修改位置:
/board/forlinx/ok335x/mux.c
1 void enable_uart0_pin_mux(void) 2 { 3 configure_module_pin_mux(uart0_pin_mux_spl); 4 configure_module_pin_mux(uart1_pin_mux); 5 } 6
将这行代码打开。
代码跟踪流程:
arch/arm/cpu/armv7/start.S :
开头的_start 函数:
1 .globl _start 2 _start: b reset
从reset 函数跳入cpu_init_crit 函数,还是在本文件内:
1 reset: 2 bl save_boot_params 3 /* 4 * set the cpu to SVC32 mode 5 */ 6 mrs r0, cpsr 7 bic r0, r0, #0x1f 8 orr r0, r0, #0xd3 9 msr cpsr,r0 10 //...... 11 #ifndef CONFIG_SKIP_LOWLEVEL_INIT 12 bl cpu_init_crit 13 #endif 14 //......
从cpu_init_crit 函数进入lowlevel_init 函数。
这个函数在arch/arm/cpu/armv7/ti81xx/lowlevel_init.S 文件内。
1 /************************************************************************* 2 * 3 * CPU_init_critical registers 4 * 5 * setup important registers 6 * setup memory timing 7 * 8 *************************************************************************/ 9 cpu_init_crit: 10 /* 11 * Invalidate L1 I/D 12 */ 13 mov r0, #0 @ set up for MCR 14 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs 15 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 16 mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array 17 mcr p15, 0, r0, c7, c10, 4 @ DSB 18 mcr p15, 0, r0, c7, c5, 4 @ ISB 19 //...... 20 bl lowlevel_init @ go setup pll,mux,memory 21 //......
从lowlevel_init 函数进入s_init_start 函数。
1 /***************************************************************************** 2 * lowlevel_init: - Platform low level init. 3 * Corrupted Register : r0, r1, r2, r3, r4, r5, r6 4 ****************************************************************************/ 5 .globl lowlevel_init 6 lowlevel_init: 7 8 /* The link register is saved in ip by start.S */ 9 mov r6, ip 10 /* check if we are already running from RAM */ 11 ldr r2, _lowlevel_init 12 ldr r3, _TEXT_BASE 13 sub r4, r2, r3 14 sub r0, pc, r4 15 //...... 16 ands r0, r0, #0xC0000000 /* MSB 2 bits <> 0 then we are in ocmc or DDR */ 17 cmp r0, #0x80000000 18 bne s_init_start 19 mov r10, #0x01 20 b s_init_start 21 22 //......
从s_init_start 函数进入s_init 函数。
1 s_init_start: 2 mov r0, r10 /* passing in_ddr in r0 */ 3 bl s_init 4 /* back to arch calling code */ 5 mov pc, r6 6 /* the literal pools origin */ 7 .ltorg 8
1 /* 2 * early system init of muxing and clocks. 3 */ 4 void s_init(void) 5 { 6 /* Can be removed as A8 comes up with L2 enabled */ 7 l2_cache_enable(); 8 9 /* WDT1 is already running when the bootloader gets control 10 * Disable it to avoid "random" resets 11 */ 12 __raw_writel(0xAAAA, WDT_WSPR); 13 while(__raw_readl(WDT_WWPS) != 0x0); 14 __raw_writel(0x5555, WDT_WSPR); 15 while(__raw_readl(WDT_WWPS) != 0x0); 16 17 //...... 18 pll_init(); 19 //...... 20 enable_uart0_pin_mux(); 21 22 //...... 23
这个函数的实现在board/forlinx/ok335x/evm.c 文件内.
从这里进入enable_uart0_pin_mux() ;
1 void enable_uart0_pin_mux(void) 2 { 3 configure_module_pin_mux(uart0_pin_mux_spl); 4 configure_module_pin_mux(uart1_pin_mux); 5 }
这函数的实现在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 的即是我修改的。
1 static void per_clocks_enable(void) 2 { 3 /* Enable the module clock */ 4 __raw_writel(PRCM_MOD_EN, CM_PER_TIMER2_CLKCTRL); 5 while (__raw_readl(CM_PER_TIMER2_CLKCTRL) != PRCM_MOD_EN); 6 7 /* Select the Master osc 24 MHZ as Timer2 clock source */ 8 __raw_writel(0x1, CLKSEL_TIMER2_CLK); 9 10 /* UART0 */ 11 __raw_writel(PRCM_MOD_EN, CM_WKUP_UART0_CLKCTRL); 12 while (__raw_readl(CM_WKUP_UART0_CLKCTRL) != PRCM_MOD_EN); 13 14 /* change by chen 2016/9/30 */ 15 __raw_writel(PRCM_MOD_EN, CM_PER_UART1_CLKCTRL); 16 while (__raw_readl(CM_PER_UART1_CLKCTRL) != PRCM_MOD_EN); 17 18 /* UART3 */ 19 __raw_writel(PRCM_MOD_EN, CM_PER_UART3_CLKCTRL); 20 while (__raw_readl(CM_PER_UART3_CLKCTRL) != PRCM_MOD_EN); 21 22 /* GPMC */ 23 __raw_writel(PRCM_MOD_EN, CM_PER_GPMC_CLKCTRL); 24 while (__raw_readl(CM_PER_GPMC_CLKCTRL) != PRCM_MOD_EN); 25 //..... 26 }
CM_PER_UART1_CLKCTR的宏定义设置在arch/arm/include/asm/arch-ti81xx/cpu.h文件内。
添加这一条宏定义。
1 #define CM_PER_UART1_CLKCTRL (CM_PER + 0x6C) /* UART1 */ 2 #define CM_PER_UART3_CLKCTRL (CM_PER + 0x74) /* UART3 */
代码修改跟踪流程:
在上面已经跟踪的s_init 函数里面。
再进入pll_init () 函数。
1 /* 2 * Configure the PLL/PRCM for necessary peripherals 3 */ 4 void pll_init() 5 { // mpu_pll_config(MPUPLL_M_500); 6 mpu_pll_config(MPUPLL_M_720); 7 core_pll_config(); 8 per_pll_config(); 9 ddr_pll_config(); 10 /* Enable the required interconnect clocks */ 11 interface_clocks_enable(); 12 /* Enable power domain transition */ 13 power_domain_transition_enable(); 14 /* Enable the required peripherals */ 15 per_clocks_enable(); 16 }
这个函数的实现在:board/forlinx/ok335x/pll.c
再进入per_clocks_enable()函数内,这个函数在本文件内实现。
1 /* 2 * Enable the module clock and the power domain for required peripherals 3 */ 4 static void per_clocks_enable(void) 5 { 6 /* Enable the module clock */ 7 __raw_writel(PRCM_MOD_EN, CM_PER_TIMER2_CLKCTRL); 8 while (__raw_readl(CM_PER_TIMER2_CLKCTRL) != PRCM_MOD_EN); 9 10 /* Select the Master osc 24 MHZ as Timer2 clock source */ 11 __raw_writel(0x1, CLKSEL_TIMER2_CLK); 12 13 /* UART0 */ 14 __raw_writel(PRCM_MOD_EN, CM_WKUP_UART0_CLKCTRL); 15 while (__raw_readl(CM_WKUP_UART0_CLKCTRL) != PRCM_MOD_EN); 16 17 /* change by chen 2016/9/30 */ 18 __raw_writel(PRCM_MOD_EN, CM_PER_UART1_CLKCTRL); 19 while (__raw_readl(CM_PER_UART1_CLKCTRL) != PRCM_MOD_EN); 20 // .................................. 21 }
3. 关于include/configs/ok335x.h配置
代码修改位置:
1 #define CONFIG_SYS_NS16550_COM2 0x48022000 /* UART1 sbc-7109 */ 2 3 #define CONFIG_SERIAL2 1 4 #define CONFIG_CONS_INDEX 2
如上所示,添加这三个宏定义。
CONFIG_CONS_INDEX 这个为修改,原来uart0 输出调试信息的时候是为1。
代码跟踪流程:
arch/arm/cpu/armv7/start.S :从_start 进入reset 函数。
1 /* Set stackpointer in internal RAM to call board_init_f */ 2 call_board_init_f: 3 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 4 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 5 ldr r0,=0x00000000 6 bl board_init_f
再进入board_init_f 函数。
这个函数的实现在:
arch/arm/lib/board.c 文件内。
1 void board_init_f(ulong bootflag) 2 { 3 bd_t *bd; 4 init_fnc_t **init_fnc_ptr; 5 gd_t *id; 6 ulong addr, addr_sp; 7 8 9 /* Pointer is writable since we allocated a register for it */ 10 gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07); 11 /* compiler optimization barrier needed for GCC >= 3.4 */ 12 __asm__ __volatile__("": : :"memory"); 13 14 memset((void *)gd, 0, sizeof(gd_t)); 15 16 gd->mon_len = _bss_end_ofs; 17 18 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { 19 if ((*init_fnc_ptr)() != 0) { 20 hang (); 21 } 22 } 23 //...... 24 }
在这个函数内有for循环运行一系列的初始化。
这个数组有如下定义:
1 init_fnc_t *init_sequence[] = { 2 #if defined(CONFIG_ARCH_CPU_INIT) 3 arch_cpu_init, /* basic arch cpu dependent setup */ 4 #endif 5 #if defined(CONFIG_BOARD_EARLY_INIT_F) 6 board_early_init_f, 7 #endif 8 timer_init, /* initialize timer */ 9 #ifdef CONFIG_FSL_ESDHC 10 get_clocks, 11 #endif 12 env_init, /* initialize environment */ 13 init_baudrate, /* initialze baudrate settings */ 14 serial_init, /* serial communications setup */ 15 console_init_f, /* stage 1 init of console */ 16 display_banner, /* say that we are here */ 17 #if defined(CONFIG_DISPLAY_CPUINFO) 18 print_cpuinfo, /* display cpu info (and speed) */ 19 #endif 20 #if defined(CONFIG_DISPLAY_BOARDINFO) 21 checkboard, /* display board info */ 22 //....... 23 }
再进入serial_init 串行通信初始化。
这个函数的实现在:drivers/serial/serial.c 文件后内。
1 #if !defined(CONFIG_SERIAL_MULTI) 2 int serial_init (void) 3 { 4 5 int clock_divisor; 6 7 #ifdef CONFIG_NS87308 8 initialise_ns87308(); 9 #endif 10 11 #ifdef CONFIG_SYS_NS16550_COM1 12 clock_divisor = calc_divisor(serial_ports[0]); 13 NS16550_init(serial_ports[0], clock_divisor); 14 #endif 15 #ifdef CONFIG_SYS_NS16550_COM2 16 clock_divisor = calc_divisor(serial_ports[1]); 17 NS16550_init(serial_ports[1], clock_divisor); 18 #endif 19 #ifdef CONFIG_SYS_NS16550_COM3 20 clock_divisor = calc_divisor(serial_ports[2]); 21 NS16550_init(serial_ports[2], clock_divisor); 22 #endif 23 //...... 24 }
第一个CONFIG_SYS_NS16550_COM1为UART0的串口初始化。
第二个CONFIG_SYS_NS16550_COM2要自己定义,在include/configs/ok335x.h 内添加。
1 #define CONFIG_SYS_NS16550_COM2 0x48022000 /* UART1 sbc-7109 */
这里的话只是完成了初始化,但是还要指定调试信息输出的端口。
回到arch/arm/lib/board.c
进入display_banner 函数,这个函数的实现在本文件内实现。
1 static int display_banner(void) 2 { 3 printf("\n\n%s\n\n", version_string); 4 printf("chen goto it ....\n") ; 5 debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", 6 _TEXT_BASE, 7 _bss_start_ofs + _TEXT_BASE, _bss_end_ofs + _TEXT_BASE); 8 #ifdef CONFIG_MODEM_SUPPORT 9 debug("Modem Support enabled\n"); 10 #endif 11 #ifdef CONFIG_USE_IRQ 12 debug("IRQ Stack: %08lx\n", IRQ_STACK_START); 13 debug("FIQ Stack: %08lx\n", FIQ_STACK_START); 14 #endif 15 16 return (0); 17 }
进入printf 函数,这个函数在/common/console.c 文件内实现。
1 int printf(const char *fmt, ...) 2 { 3 va_list args; 4 uint i; 5 char printbuffer[CONFIG_SYS_PBSIZE]; 6 7 va_start(args, fmt); 8 9 /* For this to work, printbuffer must be larger than 10 * anything we ever want to print. 11 */ 12 i = vsprintf(printbuffer, fmt, args); 13 va_end(args); 14 15 /* Print the string */ 16 puts(printbuffer); 17 return i; 18 }
还是在本文件内,进入puts 函数:
1 void puts(const char *s) 2 { 3 #ifdef CONFIG_SILENT_CONSOLE 4 if (gd->flags & GD_FLG_SILENT) 5 return; 6 #endif 7 8 #ifdef CONFIG_DISABLE_CONSOLE 9 if (gd->flags & GD_FLG_DISABLE_CONSOLE) 10 return; 11 #endif 12 13 if (gd->flags & GD_FLG_DEVINIT) { 14 /* Send to the standard output */ 15 fputs(stdout, s); 16 } else { 17 /* Send directly to the handler */ 18 serial_puts(s); 19 } 20 }
再进入serial_puts 函数,这个函数的实现在drivers/serial/serial.c文件内实现。
1 void 2 serial_puts(const char *s) 3 { 4 _serial_puts(s,CONFIG_CONS_INDEX); 5 }
这里指定了输出的端口,这个宏定义也是在include/configs/ok335x.h 里面定义:
1 #define CONFIG_CONS_INDEX 2
到此,在u-boot 阶段串口输出的调试信息即可以在UART1输出。
4. 关于kernel 调试信息的打印配置
在u-boot 文件夹内
include/configs/ok335x.h
将console=ttyO1 这样的话kernel 的调试信息也将在UART1输出。
1 #ifdef CONFIG_ANDROID 2 #define CON \ 3 "console=ttyO0,115200n8 earlyprintk androidboot.console=ttyO0\0" \ 4 "optargs=init=/init\0" \ 5 "mmcroot=/dev/mmcblk0p2 rw\0" \ 6 "mmcrootfstype=ext4 rootwait\0" \ 7 "nandroot=ubi0:rootfs rw ubi.mtd=7,2048\0" \ 8 "nandrootfstype=ubifs rootwait=1\0" 9 #else 10 #define CON \ 11 "console=ttyO1,115200n8\0" \ 12 "optargs=\0" \ 13 "mmcroot=/dev/mmcblk0p2 ro\0" \ 14 "mmcrootfstype=ext3 rootwait\0" \ 15 "nandroot=ubi0:rootfs rw ubi.mtd=7,2048\0" \ 16 "nandrootfstype=ubifs rootwait=1\0" 17 #endif
5. 关于文件系统调试信息的配置
在文件系统目录。
etc/inittab
46行位UART1 输出,45行为UART0输出。
45 #0:2345:respawn:/sbin/getty 115200 ttyO0 46 1:2345:respawn:/sbin/getty 115200 ttyO1