|  | /*********************************************************************** | 
|  | * | 
|  | * Copyright (C) 2004 by FS Forth-Systeme GmbH. | 
|  | * All rights reserved. | 
|  | * | 
|  | * $Id: ns9750_serial.c,v 1.1 2004/02/16 10:37:20 mpietrek Exp $ | 
|  | * @Author: Markus Pietrek | 
|  | * @Descr: Serial driver for the NS9750. Only one UART is supported yet. | 
|  | * @References: [1] NS9750 Hardware Reference/December 2003 | 
|  | * @TODO: Implement Character GAP Timer when chip is fixed for PLL bypass | 
|  | * | 
|  | * 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 | 
|  | * | 
|  | ***********************************************************************/ | 
|  |  | 
|  | #include <common.h> | 
|  |  | 
|  | #include "ns9750_bbus.h"	/* for GPIOs */ | 
|  | #include "ns9750_ser.h"		/* for serial configuration */ | 
|  |  | 
|  | DECLARE_GLOBAL_DATA_PTR; | 
|  |  | 
|  | #if !defined(CONFIG_CONS_INDEX) | 
|  | #error "No console index specified." | 
|  | #endif | 
|  |  | 
|  | #define CONSOLE CONFIG_CONS_INDEX | 
|  |  | 
|  | static unsigned int calcBitrateRegister( void ); | 
|  | static unsigned int calcRxCharGapRegister( void ); | 
|  |  | 
|  | static char cCharsAvailable; /* Numbers of chars in unCharCache */ | 
|  | static unsigned int unCharCache; /* unCharCache is only valid if | 
|  | * cCharsAvailable > 0 */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: serial_init | 
|  | * @Return: 0 | 
|  | * @Descr: configures GPIOs and UART. Requires BBUS Master Reset turned off | 
|  | ***********************************************************************/ | 
|  |  | 
|  | int serial_init( void ) | 
|  | { | 
|  | unsigned int aunGPIOTxD[] = { 0, 8, 40, 44 }; | 
|  | unsigned int aunGPIORxD[] = { 1, 9, 41, 45 }; | 
|  |  | 
|  | cCharsAvailable = 0; | 
|  |  | 
|  | /* configure TxD and RxD pins for their special function */ | 
|  | set_gpio_cfg_reg_val( aunGPIOTxD[ CONSOLE ], | 
|  | NS9750_GPIO_CFG_FUNC_0 | NS9750_GPIO_CFG_OUTPUT ); | 
|  | set_gpio_cfg_reg_val( aunGPIORxD[ CONSOLE ], | 
|  | NS9750_GPIO_CFG_FUNC_0 | NS9750_GPIO_CFG_INPUT ); | 
|  |  | 
|  | /* configure serial engine */ | 
|  | *get_ser_reg_addr_channel( NS9750_SER_CTRL_A, CONSOLE ) = | 
|  | NS9750_SER_CTRL_A_CE | | 
|  | NS9750_SER_CTRL_A_STOP | | 
|  | NS9750_SER_CTRL_A_WLS_8; | 
|  |  | 
|  | serial_setbrg(); | 
|  |  | 
|  | *get_ser_reg_addr_channel( NS9750_SER_CTRL_B, CONSOLE ) = | 
|  | NS9750_SER_CTRL_B_RCGT; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: serial_putc | 
|  | * @Return: n/a | 
|  | * @Descr: writes one character to the FIFO. Blocks until FIFO is not full | 
|  | ***********************************************************************/ | 
|  |  | 
|  | void serial_putc( const char c ) | 
|  | { | 
|  | if (c == '\n') | 
|  | serial_putc( '\r' ); | 
|  |  | 
|  | while (!(*get_ser_reg_addr_channel( NS9750_SER_STAT_A, CONSOLE) & | 
|  | NS9750_SER_STAT_A_TRDY ) ) { | 
|  | /* do nothing, wait for characters in FIFO sent */ | 
|  | } | 
|  |  | 
|  | *(volatile char*) get_ser_reg_addr_channel( NS9750_SER_FIFO, | 
|  | CONSOLE) = c; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: serial_puts | 
|  | * @Return: n/a | 
|  | * @Descr: writes non-zero string to the FIFO. | 
|  | ***********************************************************************/ | 
|  |  | 
|  | void serial_puts( const char *s ) | 
|  | { | 
|  | while (*s) { | 
|  | serial_putc( *s++ ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: serial_getc | 
|  | * @Return: the character read | 
|  | * @Descr: performs only 8bit accesses to the FIFO. No error handling | 
|  | ***********************************************************************/ | 
|  |  | 
|  | int serial_getc( void ) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | while (!serial_tstc() ) { | 
|  | /* do nothing, wait for incoming characters */ | 
|  | } | 
|  |  | 
|  | /*  at least one character in unCharCache */ | 
|  | i = (int) (unCharCache & 0xff); | 
|  |  | 
|  | unCharCache >>= 8; | 
|  | cCharsAvailable--; | 
|  |  | 
|  | return i; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: serial_tstc | 
|  | * @Return: 0 if no input available, otherwise != 0 | 
|  | * @Descr: checks for incoming FIFO not empty. Stores the incoming chars in | 
|  | *	   unCharCache and the numbers of characters in cCharsAvailable | 
|  | ***********************************************************************/ | 
|  |  | 
|  | int serial_tstc( void ) | 
|  | { | 
|  | unsigned int unRegCache; | 
|  |  | 
|  | if ( cCharsAvailable ) | 
|  | return 1; | 
|  |  | 
|  | unRegCache = *get_ser_reg_addr_channel( NS9750_SER_STAT_A,CONSOLE ); | 
|  | if( unRegCache & NS9750_SER_STAT_A_RBC ) { | 
|  | *get_ser_reg_addr_channel( NS9750_SER_STAT_A, CONSOLE ) = | 
|  | NS9750_SER_STAT_A_RBC; | 
|  | unRegCache = *get_ser_reg_addr_channel( NS9750_SER_STAT_A, | 
|  | CONSOLE ); | 
|  | } | 
|  |  | 
|  | if ( unRegCache & NS9750_SER_STAT_A_RRDY ) { | 
|  | cCharsAvailable = (unRegCache & NS9750_SER_STAT_A_RXFDB_MA)>>20; | 
|  | if ( !cCharsAvailable ) | 
|  | cCharsAvailable = 4; | 
|  |  | 
|  | unCharCache = *get_ser_reg_addr_channel( NS9750_SER_FIFO, | 
|  | CONSOLE ); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* no chars available */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void serial_setbrg( void ) | 
|  | { | 
|  | *get_ser_reg_addr_channel( NS9750_SER_BITRATE, CONSOLE ) = | 
|  | calcBitrateRegister(); | 
|  | *get_ser_reg_addr_channel( NS9750_SER_RX_CHAR_TIMER, CONSOLE ) = | 
|  | calcRxCharGapRegister(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: calcBitrateRegister | 
|  | * @Return: value for the serial bitrate register | 
|  | * @Descr: register value depends on clock frequency and baudrate | 
|  | ***********************************************************************/ | 
|  |  | 
|  | static unsigned int calcBitrateRegister( void ) | 
|  | { | 
|  | return ( NS9750_SER_BITRATE_EBIT | | 
|  | NS9750_SER_BITRATE_CLKMUX_BCLK | | 
|  | NS9750_SER_BITRATE_TMODE | | 
|  | NS9750_SER_BITRATE_TCDR_16 | | 
|  | NS9750_SER_BITRATE_RCDR_16 | | 
|  | ( ( ( ( CONFIG_SYS_CLK_FREQ / 8 ) / /* BBUS clock,[1] Fig. 38 */ | 
|  | ( gd->baudrate * 16 ) ) - 1 ) & | 
|  | NS9750_SER_BITRATE_N_MA ) ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * @Function: calcRxCharGapRegister | 
|  | * @Return: value for the character gap timer register | 
|  | * @Descr: register value depends on clock frequency and baudrate. Currently 0 | 
|  | *	   is used as there is a bug with the gap timer in PLL bypass mode. | 
|  | ***********************************************************************/ | 
|  |  | 
|  | static unsigned int calcRxCharGapRegister( void ) | 
|  | { | 
|  | return NS9750_SER_RX_CHAR_TIMER_TRUN; | 
|  | } |