|  | /* | 
|  | * (C) Copyright 2000 - 2007 | 
|  | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | * | 
|  | * Based ont the MPC5200 PSC driver. | 
|  | * Adapted for MPC512x by Jan Wrobel <wrr@semihalf.com> | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Minimal serial functions needed to use one of the PSC ports | 
|  | * as serial console interface. | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  |  | 
|  | DECLARE_GLOBAL_DATA_PTR; | 
|  |  | 
|  | #if defined(CONFIG_PSC_CONSOLE) | 
|  |  | 
|  | static void fifo_init (volatile psc512x_t *psc) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  |  | 
|  | /* reset Rx & Tx fifo slice */ | 
|  | psc->rfcmd = PSC_FIFO_RESET_SLICE; | 
|  | psc->tfcmd = PSC_FIFO_RESET_SLICE; | 
|  |  | 
|  | /* disable Tx & Rx FIFO interrupts */ | 
|  | psc->rfintmask = 0; | 
|  | psc->tfintmask = 0; | 
|  |  | 
|  | psc->tfsize = CONSOLE_FIFO_TX_SIZE | (CONSOLE_FIFO_TX_ADDR << 16); | 
|  | psc->rfsize = CONSOLE_FIFO_RX_SIZE | (CONSOLE_FIFO_RX_ADDR << 16); | 
|  |  | 
|  | /* enable Tx & Rx FIFO slice */ | 
|  | psc->rfcmd = PSC_FIFO_ENABLE_SLICE; | 
|  | psc->tfcmd = PSC_FIFO_ENABLE_SLICE; | 
|  |  | 
|  | im->fifoc.fifoc_cmd = FIFOC_DISABLE_CLOCK_GATE; | 
|  | __asm__ volatile ("sync"); | 
|  | } | 
|  |  | 
|  | int serial_init(void) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  | unsigned long baseclk; | 
|  | int div; | 
|  |  | 
|  | fifo_init (psc); | 
|  |  | 
|  | /* set MR register to point to MR1 */ | 
|  | psc->command = PSC_SEL_MODE_REG_1; | 
|  |  | 
|  | /* disable Tx/Rx */ | 
|  | psc->command = PSC_TX_DISABLE | PSC_RX_DISABLE; | 
|  |  | 
|  | /* choose the prescaler	by 16 for the Tx/Rx clock generation */ | 
|  | psc->psc_clock_select =  0xdd00; | 
|  |  | 
|  | /* switch to UART mode */ | 
|  | psc->sicr = 0; | 
|  |  | 
|  | /* mode register points to mr1 */ | 
|  | /* configure parity, bit length and so on in mode register 1*/ | 
|  | psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE; | 
|  | /* now, mode register points to mr2 */ | 
|  | psc->mode = PSC_MODE_1_STOPBIT; | 
|  |  | 
|  | /* calculate dividor for setting PSC CTUR and CTLR registers */ | 
|  | baseclk = (gd->ips_clk + 8) / 16; | 
|  | div = (baseclk + (gd->baudrate / 2)) / gd->baudrate; | 
|  |  | 
|  | psc->ctur = (div >> 8) & 0xff; | 
|  | /* set baudrate */ | 
|  | psc->ctlr = div & 0xff; | 
|  |  | 
|  | /* disable all interrupts */ | 
|  | psc->psc_imr = 0; | 
|  |  | 
|  | /* reset and enable Rx/Tx */ | 
|  | psc->command = PSC_RST_RX; | 
|  | psc->command = PSC_RST_TX; | 
|  | psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void serial_putc (const char c) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *)CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | if (c == '\n') | 
|  | serial_putc ('\r'); | 
|  |  | 
|  | /* Wait for last character to go. */ | 
|  | while (!(psc->psc_status & PSC_SR_TXEMP)) | 
|  | ; | 
|  |  | 
|  | psc->tfdata_8 = c; | 
|  | } | 
|  |  | 
|  | void serial_putc_raw (const char c) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | /* Wait for last character to go. */ | 
|  | while (!(psc->psc_status & PSC_SR_TXEMP)) | 
|  | ; | 
|  |  | 
|  | psc->tfdata_8 = c; | 
|  | } | 
|  |  | 
|  |  | 
|  | void serial_puts (const char *s) | 
|  | { | 
|  | while (*s) { | 
|  | serial_putc (*s++); | 
|  | } | 
|  | } | 
|  |  | 
|  | int serial_getc (void) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | /* Wait for a character to arrive. */ | 
|  | while (psc->rfstat & PSC_FIFO_EMPTY) | 
|  | ; | 
|  |  | 
|  | return psc->rfdata_8; | 
|  | } | 
|  |  | 
|  | int serial_tstc (void) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | return !(psc->rfstat & PSC_FIFO_EMPTY); | 
|  | } | 
|  |  | 
|  | void serial_setbrg (void) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  | unsigned long baseclk, div; | 
|  |  | 
|  | baseclk = (gd->csb_clk + 8) / 16; | 
|  | div = (baseclk + (gd->baudrate / 2)) / gd->baudrate; | 
|  |  | 
|  | psc->ctur = (div >> 8) & 0xFF; | 
|  | psc->ctlr =  div & 0xff; /* set baudrate */ | 
|  | } | 
|  |  | 
|  | void serial_setrts(int s) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | if (s) { | 
|  | /* Assert RTS (become LOW) */ | 
|  | psc->op1 = 0x1; | 
|  | } | 
|  | else { | 
|  | /* Negate RTS (become HIGH) */ | 
|  | psc->op0 = 0x1; | 
|  | } | 
|  | } | 
|  |  | 
|  | int serial_getcts(void) | 
|  | { | 
|  | volatile immap_t *im = (immap_t *) CFG_IMMR; | 
|  | volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; | 
|  |  | 
|  | return (psc->ip & 0x1) ? 0 : 1; | 
|  | } | 
|  | #endif /* CONFIG_PSC_CONSOLE */ |