linux/arch/powerpc/boot/mpsc.c
<<
>>
Prefs
   1/*
   2 * MPSC/UART driver for the Marvell mv64360, mv64460, ...
   3 *
   4 * Author: Mark A. Greer <mgreer@mvista.com>
   5 *
   6 * 2007 (c) MontaVista Software, Inc. This file is licensed under
   7 * the terms of the GNU General Public License version 2. This program
   8 * is licensed "as is" without any warranty of any kind, whether express
   9 * or implied.
  10 */
  11
  12#include <stdarg.h>
  13#include <stddef.h>
  14#include "types.h"
  15#include "string.h"
  16#include "stdio.h"
  17#include "io.h"
  18#include "ops.h"
  19
  20
  21#define MPSC_CHR_1              0x000c
  22
  23#define MPSC_CHR_2              0x0010
  24#define MPSC_CHR_2_TA           (1<<7)
  25#define MPSC_CHR_2_TCS          (1<<9)
  26#define MPSC_CHR_2_RA           (1<<23)
  27#define MPSC_CHR_2_CRD          (1<<25)
  28#define MPSC_CHR_2_EH           (1<<31)
  29
  30#define MPSC_CHR_4              0x0018
  31#define MPSC_CHR_4_Z            (1<<29)
  32
  33#define MPSC_CHR_5              0x001c
  34#define MPSC_CHR_5_CTL1_INTR    (1<<12)
  35#define MPSC_CHR_5_CTL1_VALID   (1<<15)
  36
  37#define MPSC_CHR_10             0x0030
  38
  39#define MPSC_INTR_CAUSE         0x0000
  40#define MPSC_INTR_CAUSE_RCC     (1<<6)
  41#define MPSC_INTR_MASK          0x0080
  42
  43#define SDMA_SDCM               0x0008
  44#define SDMA_SDCM_AR            (1<<15)
  45#define SDMA_SDCM_AT            (1<<31)
  46
  47static volatile char *mpsc_base;
  48static volatile char *mpscintr_base;
  49static u32 chr1, chr2;
  50
  51static int mpsc_open(void)
  52{
  53        chr1 = in_le32((u32 *)(mpsc_base + MPSC_CHR_1)) & 0x00ff0000;
  54        chr2 = in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & ~(MPSC_CHR_2_TA
  55                        | MPSC_CHR_2_TCS | MPSC_CHR_2_RA | MPSC_CHR_2_CRD
  56                        | MPSC_CHR_2_EH);
  57        out_le32((u32 *)(mpsc_base + MPSC_CHR_4), MPSC_CHR_4_Z);
  58        out_le32((u32 *)(mpsc_base + MPSC_CHR_5),
  59                        MPSC_CHR_5_CTL1_INTR | MPSC_CHR_5_CTL1_VALID);
  60        out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_EH);
  61        return 0;
  62}
  63
  64static void mpsc_putc(unsigned char c)
  65{
  66        while (in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & MPSC_CHR_2_TCS);
  67
  68        out_le32((u32 *)(mpsc_base + MPSC_CHR_1), chr1 | c);
  69        out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_TCS);
  70}
  71
  72static unsigned char mpsc_getc(void)
  73{
  74        u32 cause = 0;
  75        unsigned char c;
  76
  77        while (!(cause & MPSC_INTR_CAUSE_RCC))
  78                cause = in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE));
  79
  80        c = in_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2));
  81        out_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2), c);
  82        out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE),
  83                        cause & ~MPSC_INTR_CAUSE_RCC);
  84
  85        return c;
  86}
  87
  88static u8 mpsc_tstc(void)
  89{
  90        return (u8)((in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE))
  91                                & MPSC_INTR_CAUSE_RCC) != 0);
  92}
  93
  94static void mpsc_stop_dma(volatile char *sdma_base)
  95{
  96        out_le32((u32 *)(mpsc_base + MPSC_CHR_2),MPSC_CHR_2_TA | MPSC_CHR_2_RA);
  97        out_le32((u32 *)(sdma_base + SDMA_SDCM), SDMA_SDCM_AR | SDMA_SDCM_AT);
  98
  99        while ((in_le32((u32 *)(sdma_base + SDMA_SDCM))
 100                                & (SDMA_SDCM_AR | SDMA_SDCM_AT)) != 0)
 101                udelay(100);
 102}
 103
 104static volatile char *mpsc_get_virtreg_of_phandle(void *devp, char *prop)
 105{
 106        void *v;
 107        int n;
 108
 109        n = getprop(devp, prop, &v, sizeof(v));
 110        if (n != sizeof(v))
 111                goto err_out;
 112
 113        devp = find_node_by_linuxphandle((u32)v);
 114        if (devp == NULL)
 115                goto err_out;
 116
 117        n = getprop(devp, "virtual-reg", &v, sizeof(v));
 118        if (n == sizeof(v))
 119                return v;
 120
 121err_out:
 122        return NULL;
 123}
 124
 125int mpsc_console_init(void *devp, struct serial_console_data *scdp)
 126{
 127        void *v;
 128        int n, reg_set;
 129        volatile char *sdma_base;
 130
 131        n = getprop(devp, "virtual-reg", &v, sizeof(v));
 132        if (n != sizeof(v))
 133                goto err_out;
 134        mpsc_base = v;
 135
 136        sdma_base = mpsc_get_virtreg_of_phandle(devp, "sdma");
 137        if (sdma_base == NULL)
 138                goto err_out;
 139
 140        mpscintr_base = mpsc_get_virtreg_of_phandle(devp, "mpscintr");
 141        if (mpscintr_base == NULL)
 142                goto err_out;
 143
 144        n = getprop(devp, "cell-index", &v, sizeof(v));
 145        if (n != sizeof(v))
 146                goto err_out;
 147        reg_set = (int)v;
 148
 149        mpscintr_base += (reg_set == 0) ? 0x4 : 0xc;
 150
 151        /* Make sure the mpsc ctlrs are shutdown */
 152        out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0);
 153        out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0);
 154        out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0);
 155        out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0);
 156
 157        mpsc_stop_dma(sdma_base);
 158
 159        scdp->open = mpsc_open;
 160        scdp->putc = mpsc_putc;
 161        scdp->getc = mpsc_getc;
 162        scdp->tstc = mpsc_tstc;
 163        scdp->close = NULL;
 164
 165        return 0;
 166
 167err_out:
 168        return -1;
 169}
 170