Logo Search packages:      
Sourcecode: linux version File versions  Download package

mpc52xx_tty.c

/*
 * Minimal serial functions needed to send messages out a MPC52xx
 * Programmable Serial Controller (PSC).
 *
 * Author: Dale Farnsworth <dfarnsworth@mvista.com>
 *
 * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under the
 * terms of the GNU General Public License version 2.  This program is licensed
 * "as is" without any warranty of any kind, whether express or implied.
 */

#include <linux/types.h>
#include <asm/uaccess.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#include <asm/serial.h>
#include <asm/io.h>
#include <asm/time.h>


#ifdef MPC52xx_PF_CONSOLE_PORT
#define MPC52xx_CONSOLE MPC52xx_PSCx_OFFSET(MPC52xx_PF_CONSOLE_PORT)
#define MPC52xx_PSC_CONFIG_SHIFT ((MPC52xx_PF_CONSOLE_PORT-1)<<2)
#else
#error "MPC52xx_PF_CONSOLE_PORT not defined"
#endif

static struct mpc52xx_psc __iomem *psc =
      (struct mpc52xx_psc __iomem *) MPC52xx_PA(MPC52xx_CONSOLE);

/* The decrementer counts at the system bus clock frequency
 * divided by four.  The most accurate time base is connected to the
 * rtc.  We read the decrementer change during one rtc tick
 * and multiply by 4 to get the system bus clock frequency. Since a
 * rtc tick is one seconds, and that's pretty long, we change the rtc
 * dividers temporarily to set them 64x faster ;)
 */
static int
mpc52xx_ipbfreq(void)
{
      struct mpc52xx_rtc __iomem *rtc =
            (struct mpc52xx_rtc __iomem *) MPC52xx_PA(MPC52xx_RTC_OFFSET);
      struct mpc52xx_cdm __iomem *cdm =
            (struct mpc52xx_cdm __iomem *) MPC52xx_PA(MPC52xx_CDM_OFFSET);
      int current_time, previous_time;
      int tbl_start, tbl_end;
      int xlbfreq, ipbfreq;

      out_be32(&rtc->dividers, 0x8f1f0000);     /* Set RTC 64x faster */
      previous_time = in_be32(&rtc->time);
      while ((current_time = in_be32(&rtc->time)) == previous_time) ;
      tbl_start = get_tbl();
      previous_time = current_time;
      while ((current_time = in_be32(&rtc->time)) == previous_time) ;
      tbl_end = get_tbl();
      out_be32(&rtc->dividers, 0xffff0000);   /* Restore RTC */

      xlbfreq = (tbl_end - tbl_start) << 8;
      ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? xlbfreq / 2 : xlbfreq;

      return ipbfreq;
}

unsigned long
serial_init(int ignored, void *ignored2)
{
      struct mpc52xx_gpio __iomem *gpio =
            (struct mpc52xx_gpio __iomem *) MPC52xx_PA(MPC52xx_GPIO_OFFSET);
      int divisor;
      int mode1;
      int mode2;
      u32 val32;

      static int been_here = 0;

      if (been_here)
            return 0;

      been_here = 1;

      val32 = in_be32(&gpio->port_config);
      val32 &= ~(0x7 << MPC52xx_PSC_CONFIG_SHIFT);
      val32 |= MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD
                        << MPC52xx_PSC_CONFIG_SHIFT;
      out_be32(&gpio->port_config, val32);

      out_8(&psc->command, MPC52xx_PSC_RST_TX
                  | MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_ENABLE);
      out_8(&psc->command, MPC52xx_PSC_RST_RX);

      out_be32(&psc->sicr, 0x0);
      out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
      out_be16(&psc->tfalarm, 0xf8);

      out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1
                  | MPC52xx_PSC_RX_ENABLE
                  | MPC52xx_PSC_TX_ENABLE);

      divisor = ((mpc52xx_ipbfreq()
                  / (CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD * 16)) + 1) >> 1;

      mode1 = MPC52xx_PSC_MODE_8_BITS | MPC52xx_PSC_MODE_PARNONE
                  | MPC52xx_PSC_MODE_ERR;
      mode2 = MPC52xx_PSC_MODE_ONE_STOP;

      out_8(&psc->ctur, divisor>>8);
      out_8(&psc->ctlr, divisor);
      out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
      out_8(&psc->mode, mode1);
      out_8(&psc->mode, mode2);

      return 0;   /* ignored */
}

void
serial_putc(void *ignored, const char c)
{
      serial_init(0, NULL);

      while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
      out_8(&psc->mpc52xx_psc_buffer_8, c);
      while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
}

char
serial_getc(void *ignored)
{
      while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY)) ;

      return in_8(&psc->mpc52xx_psc_buffer_8);
}

int
serial_tstc(void *ignored)
{
      return (in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY) != 0;
}

Generated by  Doxygen 1.6.0   Back to index