> Hi, > I am struggling with bringing up the MPC 880 board on Linux 2.6-10.rc3 ... I could see that only 3 characters (see below) from the linux_banner are printed in __init start_kernel() (init/main.c) upon booting. Then a lot of garbage is outputted and eventually kernel hangs ... ... after gunzip done. Now booting the kernel Lin??????????????????8??????????X??????????x??????????~????????????????????? ???? <more garbage> <hangs> ... ...
Very laborious debugging (without BDM and soft reset button - but with great help) shows that the hang is caused by the console serial driver at about (or just soon after) console_drivers = console; statement in register_console(struct console * console) function (in kernel/printk.c ) I can not find (so far ) any specific error in values supplied vi bd_info from the ("custom" modified pSOS bootloader) causing above problem. > The debug output showing my serial settings was saved into log buffer and read at "bootloader time" after "software stimulated" "soft reboot" - it is listed here. Could someone kindly spare 5 min examining supplied debug output from both cpm_uart_set_termios() > (in drivers/serial/cpm_uart/cpm_uart_core.c) and cpm_setbrg() (in > arch/ppc/8xx_io/commproc.c) and tell me what is wrong there ? > The output is supplied at the end of my e-mail after the listings of > functions (with my print statements) > > Thanks, > Alex > PS - I noticed (with help and via "trial and error" way) that console_init() code is written to work only with "boot" (unmapped) memory and therefore only could work if executed prior to mem_init(). Suppose I would disable (comment out in main.c ) the console_init() call and suppose (I do not know yet since did not tried that) the kernel booting will continue without any additional problems and will sucessfully finish (just without the console ;-) ) - is there any existant "non-standard" "debugging" "experimental" code, which I could integrate and execute with the aim to "late" launch my serial console at that point ? > ***************** drivers/serial/cpm_uart/cpm_uart_core.c > ****************** > .... > #define DEBUG > .... > static void cpm_uart_set_termios(struct uart_port *port, > struct termios *termios, struct termios > *old) > { > int baud; > unsigned long flags; > u16 cval, scval, prev_mode; > int bits, sbits; > struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; > volatile smc_t *smcp = pinfo->smcp; > volatile scc_t *sccp = pinfo->sccp; > #ifdef DEBUG > pr_debug("CPM uart[%d]:set_termios\n", port->line); > #endif > > baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / > 16); > > #ifdef DEBUG > pr_debug("CPM uart baud=%d\n", baud); > #endif > /* Character length programmed into the mode register is the > * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, > * 1 or 2 stop bits, minus 1. > * The value 'bits' counts this for us. > */ > cval = 0; > scval = 0; > > /* byte size */ > switch (termios->c_cflag & CSIZE) { > case CS5: > bits = 5; > break; > case CS6: > bits = 6; > break; > case CS7: > bits = 7; > break; > case CS8: > bits = 8; > break; > /* Never happens, but GCC is too dumb to figure it out */ > default: > bits = 8; > break; > } > sbits = bits - 5; > #ifdef DEBUG > pr_debug("CPM uart bits=%d\n", bits); > pr_debug("CPM uart sbits=%d\n", sbits); > #endif > > if (termios->c_cflag & CSTOPB) { > cval |= SMCMR_SL; /* Two stops */ > scval |= SCU_PSMR_SL; > bits++; > } > > if (termios->c_cflag & PARENB) { > cval |= SMCMR_PEN; > scval |= SCU_PSMR_PEN; > bits++; > if (!(termios->c_cflag & PARODD)) { > cval |= SMCMR_PM_EVEN; > scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); > } > } > #ifdef DEBUG > pr_debug("CPM uart bits=%d\n", bits); > pr_debug("CPM uart cval=%d\n", cval); > pr_debug("CPM uart scval=%d\n", scval); > #endif > > /* > * Set up parity check flag > */ > #define RELEVANT_IFLAG(iflag) (iflag & > (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) > > port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); > if (termios->c_iflag & INPCK) > port->read_status_mask |= BD_SC_FR | BD_SC_PR; > if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK)) > port->read_status_mask |= BD_SC_BR; > > /* > * Characters to ignore > */ > port->ignore_status_mask = 0; > if (termios->c_iflag & IGNPAR) > port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; > if (termios->c_iflag & IGNBRK) { > port->ignore_status_mask |= BD_SC_BR; > /* > * If we're ignore parity and break indicators, ignore > * overruns too. (For real raw support). > */ > if (termios->c_iflag & IGNPAR) > port->ignore_status_mask |= BD_SC_OV; > ifdef DEBUG > if (termios->c_iflag & IGNPAR) > pr_debug("CPM uart real raw support"); > endif > } > /* > * !!! ignore all characters if CREAD is not set > */ > if ((termios->c_cflag & CREAD) == 0) > port->read_status_mask &= ~BD_SC_EMPTY; > ifdef DEBUG > if ((termios->c_cflag & CREAD) == 0) > pr_debug("CPM uart CREAD is not set"); > endif > > spin_lock_irqsave(&port->lock, flags); > > /* Start bit has not been added (so don't, because we would just > * subtract it later), and we need to add one for the number of > * stops bits (there is always at least one). > */ > bits++; > ifdef DEBUG > pr_debug("CPM uart bits=%d\n", bits); > endif > if (IS_SMC(pinfo)) { > /* Set the mode register. We want to keep a copy of the > * enables, because we want to put them back if they were > * present. > */ > prev_mode = smcp->smc_smcmr; > smcp->smc_smcmr = smcr_mk_clen(bits) | cval | > SMCMR_SM_UART; > smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); > ifdef DEBUG > pr_debug("CPM uart IS_SMCpinfo > 0 \n"); > endif > } else { > sccp->scc_psmr = (sbits << 12) | scval; > } > > cpm_set_brg(pinfo->brg - 1, baud); > ifdef DEBUG > pr_debug(" returned from cpm_set_brg"); > endif > spin_unlock_irqrestore(&port->lock, flags); > ifdef DEBUG > pr_debug("after spin_unlock_irqrestore"); > #endif > *(int*)0 = 0xdeadbeef; <==== I have inserted here to force > crash and soft reboot - it works ! > #ifdef DEBUG > pr_debug("after deadbeef"); <<========== I have inserted here > for double check - never reached ... > #endif > > } > > ***************************** arch/ppc/8xx_io/commproc.c > *********************************** > > #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq) > #define BRG_UART_CLK (BRG_INT_CLK/16) > #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) > > void > cpm_setbrg(uint brg, uint rate) > { > volatile uint *bp; > unsigned long brgUrtClkDiv16 = BRG_UART_CLK_DIV16; > > /* This is good enough to get SMCs running..... > */ > bp = (uint *)&cpmp->cp_brgc1; > > printk("cpm_setbrg: BRG_UART_CLK_DIV16 %lu",brgUrtClkDiv16); > printk("cpm_setbrg: *bp came as %u",*bp); > printk("cpm_setbrg: rate came as %u",rate); > bp += brg; > > printk("cpm_setbrg: *bp is now %u",*bp); > /* The BRG has a 12-bit counter. For really slow baud rates (or > * really fast processors), we may have to further divide by 16. > */ > if (((BRG_UART_CLK / rate) - 1) < 4096) > *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN; > else > *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | > CPM_BRG_EN | > CPM_BRG_DIV16; > > > printk("cpm_setbrg: *bp is set to %u",*bp); > > } > > **************************** > Now the output in the log buffer from both cpm_uart_set_termios() and > cpm_setbrg() ) : > ********************************************* > > < 7>CPM uart[0]:set_termios. > <7>CPM uart baud =115200. > <7>CPM uart bits=8. > .<7>CPM uart cval=0. > .<7>CPM uart bits=9. > .<4>cpm_setbrg: BRG_UART_CLK_DIV16 195312 > cpm_setbrg: *bp came as 65588 > cpm_setbrg: rate came as 115200 > cpm_setbrg: *bp is now 65588 > cpm_setbrg: *bp is set to 65588 > <7>returned from cpm_set_brg > <7>after spin_unlock_irqrestore >