console_init() question

Povolotsky, Alexander Alexander.Povolotsky at marconi.com
Fri Jan 28 13:56:21 EST 2005


-----Original Message-----
>From: Dan Malek [mailto:dan at embeddededge.com]
>Sent: Thursday, January 27, 2005 9:38 PM
>To: Povolotsky, Alexander
>Cc: 'linuxppc-dev at lists.linuxppc.org'; 'linuxppc-embedded at ozlabs.org'
>Subject: Re: console_init() question 

>Do you boot over a network?  Does your boot loader shut down
>the network controller and interrupts before jumping to the kernel?

No - also, please note that the serial works during the "simple bootloader
time" (see my "add on" question below)

>Everything looks OK until the CPM and serial port are reconfigured
>by Linux, so something is amiss with that.  Could be many reasons
>such as location of BDs and buffers, some part of the CPM still
>running a peripheral from the boot loader that Linux doesn't know
>about, and so on.

That why I asked (OK ..., may be I did not ask that ...)
 for some "CPM diagnostic" software, that could
be run upon kernel booting
 - (something what PPCbug might have already - not sure, though, just
guessing ...)

	-- Dan

Alternatively (or addionally) to my original questin - why not (optionally)
to
 allow for the kernel to use the simple serial console mechanism
(putc( ), puts( ), puthex( )) which is used (and, by the way, works in my
case - as one could 
see from the quotted below booting output) in the "simple" bootloader (the
'middle-man' between the primary 
bootloader and the kernel ) - may be by making it available to the kernel as
a library  ?

-----Original Message-----
>From: Andrew Williams [mailto:awilliam at nortelnetworks.com]
>Sent: Thursday, January 27, 2005 9:33 PM
>To: Povolotsky, Alexander; 'linuxppc-dev at lists.linuxppc.org';
'linuxppc-embedded at ozlabs.org'
>Subject: RE: console_init() question 

>Here's a reference doc, that I found extremely usefull/interesting 
>when working on board bring up. 
>  <http://www.tldp.org/LDP/cpg/Custom-Porting-Guide.pdf> 
>Andrew 
Thanks - I have already look at that - those lucky guys had simple serial
UART (without CPM complexity) 


>  -----Original Message-----
> From: 	Povolotsky, Alexander  
> Sent:	Thursday, January 27, 2005 9:07 PM
> To:	'linuxppc-dev at lists.linuxppc.org'; 'linuxppc-embedded at ozlabs.org'
> Subject:	console_init() question 
> 
> 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 via 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
> 



More information about the Linuxppc-embedded mailing list