linux/arch/powerpc/sysdev/mv64x60_udbg.c
<<
>>
Prefs
   1/*
   2 * udbg serial input/output routines for the Marvell MV64x60 (Discovery).
   3 *
   4 * Author: Dale Farnsworth <dale@farnsworth.org>
   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 <asm/io.h>
  13#include <asm/prom.h>
  14#include <asm/udbg.h>
  15
  16#include <sysdev/mv64x60.h>
  17
  18#define MPSC_0_CR1_OFFSET       0x000c
  19
  20#define MPSC_0_CR2_OFFSET       0x0010
  21#define MPSC_CHR_2_TCS          (1 << 9)
  22
  23#define MPSC_0_CHR_10_OFFSET    0x0030
  24
  25#define MPSC_INTR_CAUSE_OFF_0   0x0004
  26#define MPSC_INTR_CAUSE_OFF_1   0x000c
  27#define MPSC_INTR_CAUSE_RCC     (1<<6)
  28
  29static void __iomem *mpsc_base;
  30static void __iomem *mpsc_intr_cause;
  31
  32static void mv64x60_udbg_putc(char c)
  33{
  34        if (c == '\n')
  35                mv64x60_udbg_putc('\r');
  36
  37        while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
  38                ;
  39        out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
  40        out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
  41}
  42
  43static int mv64x60_udbg_testc(void)
  44{
  45        return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
  46}
  47
  48static int mv64x60_udbg_getc(void)
  49{
  50        int cause = 0;
  51        int c;
  52
  53        while (!mv64x60_udbg_testc())
  54                ;
  55
  56        c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
  57        out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
  58        out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
  59        return c;
  60}
  61
  62static int mv64x60_udbg_getc_poll(void)
  63{
  64        if (!mv64x60_udbg_testc())
  65                return -1;
  66
  67        return mv64x60_udbg_getc();
  68}
  69
  70static void mv64x60_udbg_init(void)
  71{
  72        struct device_node *np, *mpscintr, *stdout = NULL;
  73        const char *path;
  74        const phandle *ph;
  75        struct resource r[2];
  76        const int *block_index;
  77        int intr_cause_offset;
  78        int err;
  79
  80        path = of_get_property(of_chosen, "linux,stdout-path", NULL);
  81        if (!path)
  82                return;
  83
  84        stdout = of_find_node_by_path(path);
  85        if (!stdout)
  86                return;
  87
  88        for_each_compatible_node(np, NULL, "marvell,mv64360-mpsc") {
  89                if (np == stdout)
  90                        break;
  91        }
  92
  93        of_node_put(stdout);
  94        if (!np)
  95                return;
  96
  97        block_index = of_get_property(np, "cell-index", NULL);
  98        if (!block_index)
  99                goto error;
 100
 101        switch (*block_index) {
 102        case 0:
 103                intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
 104                break;
 105        case 1:
 106                intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
 107                break;
 108        default:
 109                goto error;
 110        }
 111
 112        err = of_address_to_resource(np, 0, &r[0]);
 113        if (err)
 114                goto error;
 115
 116        ph = of_get_property(np, "mpscintr", NULL);
 117        mpscintr = of_find_node_by_phandle(*ph);
 118        if (!mpscintr)
 119                goto error;
 120
 121        err = of_address_to_resource(mpscintr, 0, &r[1]);
 122        of_node_put(mpscintr);
 123        if (err)
 124                goto error;
 125
 126        of_node_put(np);
 127
 128        mpsc_base = ioremap(r[0].start, resource_size(&r[0]));
 129        if (!mpsc_base)
 130                return;
 131
 132        mpsc_intr_cause = ioremap(r[1].start, resource_size(&r[1]));
 133        if (!mpsc_intr_cause) {
 134                iounmap(mpsc_base);
 135                return;
 136        }
 137        mpsc_intr_cause += intr_cause_offset;
 138
 139        udbg_putc = mv64x60_udbg_putc;
 140        udbg_getc = mv64x60_udbg_getc;
 141        udbg_getc_poll = mv64x60_udbg_getc_poll;
 142
 143        return;
 144
 145error:
 146        of_node_put(np);
 147}
 148
 149void mv64x60_init_early(void)
 150{
 151        mv64x60_udbg_init();
 152}
 153