linux/arch/ppc/boot/simple/mv64x60_tty.c
<<
>>
Prefs
   1/*
   2 * Bootloader version of the embedded MPSC/UART driver for the Marvell 64x60.
   3 * Note: Due to a GT64260A erratum, DMA will be used for UART input (via SDMA).
   4 *
   5 * Author: Mark A. Greer <mgreer@mvista.com>
   6 *
   7 * 2001 (c) MontaVista Software, Inc. This file is licensed under
   8 * the terms of the GNU General Public License version 2. This program
   9 * is licensed "as is" without any warranty of any kind, whether express
  10 * or implied.
  11 */
  12
  13/* This code assumes that the data cache has been disabled (L1, L2, L3). */
  14
  15#include <linux/types.h>
  16#include <linux/serial_reg.h>
  17#include <asm/serial.h>
  18#include <asm/io.h>
  19#include <asm/mv64x60_defs.h>
  20#include <mpsc_defs.h>
  21
  22#ifdef CONFIG_EV64360
  23#include <platforms/ev64360.h>
  24u32     mv64x60_console_baud = EV64360_DEFAULT_BAUD;
  25u32     mv64x60_mpsc_clk_src = EV64360_MPSC_CLK_SRC; /* TCLK */
  26u32     mv64x60_mpsc_clk_freq = EV64360_MPSC_CLK_FREQ;
  27#else
  28u32     mv64x60_console_baud = 9600;
  29u32     mv64x60_mpsc_clk_src = 8; /* TCLK */
  30u32     mv64x60_mpsc_clk_freq = 100000000;
  31#endif
  32
  33extern void udelay(long);
  34static void stop_dma(int chan);
  35
  36static void __iomem *mv64x60_base = (void __iomem *)CONFIG_MV64X60_NEW_BASE;
  37
  38struct sdma_regs {
  39        u32     sdc;
  40        u32     sdcm;
  41        u32     rx_desc;
  42        u32     rx_buf_ptr;
  43        u32     scrdp;
  44        u32     tx_desc;
  45        u32     sctdp;
  46        u32     sftdp;
  47};
  48
  49static struct sdma_regs sdma_regs[2];
  50
  51#define SDMA_REGS_INIT(s, reg_base) {                   \
  52        (s)->sdc        = (reg_base) + SDMA_SDC;        \
  53        (s)->sdcm       = (reg_base) + SDMA_SDCM;       \
  54        (s)->rx_desc    = (reg_base) + SDMA_RX_DESC;    \
  55        (s)->rx_buf_ptr = (reg_base) + SDMA_RX_BUF_PTR; \
  56        (s)->scrdp      = (reg_base) + SDMA_SCRDP;      \
  57        (s)->tx_desc    = (reg_base) + SDMA_TX_DESC;    \
  58        (s)->sctdp      = (reg_base) + SDMA_SCTDP;      \
  59        (s)->sftdp      = (reg_base) + SDMA_SFTDP;      \
  60}
  61
  62static u32      mpsc_base[2] = { MV64x60_MPSC_0_OFFSET, MV64x60_MPSC_1_OFFSET };
  63
  64struct mv64x60_rx_desc {
  65        u16     bufsize;
  66        u16     bytecnt;
  67        u32     cmd_stat;
  68        u32     next_desc_ptr;
  69        u32     buffer;
  70};
  71
  72struct mv64x60_tx_desc {
  73        u16     bytecnt;
  74        u16     shadow;
  75        u32     cmd_stat;
  76        u32     next_desc_ptr;
  77        u32     buffer;
  78};
  79
  80#define MAX_RESET_WAIT  10000
  81#define MAX_TX_WAIT     10000
  82
  83#define RX_NUM_DESC     2
  84#define TX_NUM_DESC     2
  85
  86#define RX_BUF_SIZE     32
  87#define TX_BUF_SIZE     32
  88
  89static struct mv64x60_rx_desc rd[2][RX_NUM_DESC] __attribute__ ((aligned(32)));
  90static struct mv64x60_tx_desc td[2][TX_NUM_DESC] __attribute__ ((aligned(32)));
  91
  92static char rx_buf[2][RX_NUM_DESC * RX_BUF_SIZE] __attribute__ ((aligned(32)));
  93static char tx_buf[2][TX_NUM_DESC * TX_BUF_SIZE] __attribute__ ((aligned(32)));
  94
  95static int cur_rd[2] = { 0, 0 };
  96static int cur_td[2] = { 0, 0 };
  97
  98static char chan_initialized[2] = { 0, 0 };
  99
 100
 101#define RX_INIT_RDP(rdp) {                      \
 102        (rdp)->bufsize = 2;                     \
 103        (rdp)->bytecnt = 0;                     \
 104        (rdp)->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |   \
 105                SDMA_DESC_CMDSTAT_O;    \
 106}
 107
 108#ifdef CONFIG_MV64360
 109static u32 cpu2mem_tab[MV64x60_CPU2MEM_WINDOWS][2] = {
 110                { MV64x60_CPU2MEM_0_BASE, MV64x60_CPU2MEM_0_SIZE },
 111                { MV64x60_CPU2MEM_1_BASE, MV64x60_CPU2MEM_1_SIZE },
 112                { MV64x60_CPU2MEM_2_BASE, MV64x60_CPU2MEM_2_SIZE },
 113                { MV64x60_CPU2MEM_3_BASE, MV64x60_CPU2MEM_3_SIZE }
 114};
 115
 116static u32 com2mem_tab[MV64x60_CPU2MEM_WINDOWS][2] = {
 117                { MV64360_MPSC2MEM_0_BASE, MV64360_MPSC2MEM_0_SIZE },
 118                { MV64360_MPSC2MEM_1_BASE, MV64360_MPSC2MEM_1_SIZE },
 119                { MV64360_MPSC2MEM_2_BASE, MV64360_MPSC2MEM_2_SIZE },
 120                { MV64360_MPSC2MEM_3_BASE, MV64360_MPSC2MEM_3_SIZE }
 121};
 122
 123static u32 dram_selects[MV64x60_CPU2MEM_WINDOWS] = { 0xe, 0xd, 0xb, 0x7 };
 124#endif
 125
 126unsigned long
 127serial_init(int chan, void *ignored)
 128{
 129        u32             mpsc_routing_base, sdma_base, brg_bcr, cdv;
 130        int             i;
 131
 132        chan = (chan == 1); /* default to chan 0 if anything but 1 */
 133
 134        if (chan_initialized[chan])
 135                return chan;
 136
 137        chan_initialized[chan] = 1;
 138
 139        if (chan == 0) {
 140                sdma_base = MV64x60_SDMA_0_OFFSET;
 141                brg_bcr = MV64x60_BRG_0_OFFSET + BRG_BCR;
 142                SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_0_OFFSET);
 143        } else {
 144                sdma_base = MV64x60_SDMA_1_OFFSET;
 145                brg_bcr = MV64x60_BRG_1_OFFSET + BRG_BCR;
 146                SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_1_OFFSET);
 147        }
 148
 149        mpsc_routing_base = MV64x60_MPSC_ROUTING_OFFSET;
 150
 151        stop_dma(chan);
 152
 153        /* Set up ring buffers */
 154        for (i=0; i<RX_NUM_DESC; i++) {
 155                RX_INIT_RDP(&rd[chan][i]);
 156                rd[chan][i].buffer = (u32)&rx_buf[chan][i * RX_BUF_SIZE];
 157                rd[chan][i].next_desc_ptr = (u32)&rd[chan][i+1];
 158        }
 159        rd[chan][RX_NUM_DESC - 1].next_desc_ptr = (u32)&rd[chan][0];
 160
 161        for (i=0; i<TX_NUM_DESC; i++) {
 162                td[chan][i].bytecnt = 0;
 163                td[chan][i].shadow = 0;
 164                td[chan][i].buffer = (u32)&tx_buf[chan][i * TX_BUF_SIZE];
 165                td[chan][i].cmd_stat = SDMA_DESC_CMDSTAT_F|SDMA_DESC_CMDSTAT_L;
 166                td[chan][i].next_desc_ptr = (u32)&td[chan][i+1];
 167        }
 168        td[chan][TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[chan][0];
 169
 170        /* Set MPSC Routing */
 171        out_le32(mv64x60_base + mpsc_routing_base + MPSC_MRR, 0x3ffffe38);
 172
 173#ifdef CONFIG_GT64260
 174        out_le32(mv64x60_base + GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
 175#else /* Must be MV64360 or MV64460 */
 176        {
 177        u32     enables, prot_bits, v;
 178
 179        /* Set up comm unit to memory mapping windows */
 180        /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
 181
 182        enables = in_le32(mv64x60_base + MV64360_CPU_BAR_ENABLE) & 0xf;
 183        prot_bits = 0;
 184
 185        for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
 186                if (!(enables & (1 << i))) {
 187                        v = in_le32(mv64x60_base + cpu2mem_tab[i][0]);
 188                        v = ((v & 0xffff) << 16) | (dram_selects[i] << 8);
 189                        out_le32(mv64x60_base + com2mem_tab[i][0], v);
 190
 191                        v = in_le32(mv64x60_base + cpu2mem_tab[i][1]);
 192                        v = (v & 0xffff) << 16;
 193                        out_le32(mv64x60_base + com2mem_tab[i][1], v);
 194
 195                        prot_bits |= (0x3 << (i << 1)); /* r/w access */
 196                }
 197        }
 198
 199        out_le32(mv64x60_base + MV64360_MPSC_0_REMAP, 0);
 200        out_le32(mv64x60_base + MV64360_MPSC_1_REMAP, 0);
 201        out_le32(mv64x60_base + MV64360_MPSC2MEM_ACC_PROT_0, prot_bits);
 202        out_le32(mv64x60_base + MV64360_MPSC2MEM_ACC_PROT_1, prot_bits);
 203        out_le32(mv64x60_base + MV64360_MPSC2MEM_BAR_ENABLE, enables);
 204        }
 205#endif
 206
 207        /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
 208        out_le32(mv64x60_base + mpsc_routing_base + MPSC_RCRR, 0x00000100);
 209        out_le32(mv64x60_base + mpsc_routing_base + MPSC_TCRR, 0x00000100);
 210
 211        /* clear pending interrupts */
 212        out_le32(mv64x60_base + MV64x60_SDMA_INTR_OFFSET + SDMA_INTR_MASK, 0);
 213
 214        out_le32(mv64x60_base + SDMA_SCRDP + sdma_base, (int)&rd[chan][0]);
 215        out_le32(mv64x60_base + SDMA_SCTDP + sdma_base,
 216                (int)&td[chan][TX_NUM_DESC - 1]);
 217        out_le32(mv64x60_base + SDMA_SFTDP + sdma_base,
 218                (int)&td[chan][TX_NUM_DESC - 1]);
 219
 220        out_le32(mv64x60_base + SDMA_SDC + sdma_base,
 221                SDMA_SDC_RFT | SDMA_SDC_SFM | SDMA_SDC_BLMR | SDMA_SDC_BLMT |
 222                (3 << 12));
 223
 224        cdv = ((mv64x60_mpsc_clk_freq/(32*mv64x60_console_baud))-1);
 225        out_le32(mv64x60_base + brg_bcr,
 226                ((mv64x60_mpsc_clk_src << 18) | (1 << 16) | cdv));
 227
 228        /* Put MPSC into UART mode, no null modem, 16x clock mode */
 229        out_le32(mv64x60_base + MPSC_MMCRL + mpsc_base[chan], 0x000004c4);
 230        out_le32(mv64x60_base + MPSC_MMCRH + mpsc_base[chan], 0x04400400);
 231
 232        out_le32(mv64x60_base + MPSC_CHR_1 + mpsc_base[chan], 0);
 233        out_le32(mv64x60_base + MPSC_CHR_9 + mpsc_base[chan], 0);
 234        out_le32(mv64x60_base + MPSC_CHR_10 + mpsc_base[chan], 0);
 235        out_le32(mv64x60_base + MPSC_CHR_3 + mpsc_base[chan], 4);
 236        out_le32(mv64x60_base + MPSC_CHR_4 + mpsc_base[chan], 0);
 237        out_le32(mv64x60_base + MPSC_CHR_5 + mpsc_base[chan], 0);
 238        out_le32(mv64x60_base + MPSC_CHR_6 + mpsc_base[chan], 0);
 239        out_le32(mv64x60_base + MPSC_CHR_7 + mpsc_base[chan], 0);
 240        out_le32(mv64x60_base + MPSC_CHR_8 + mpsc_base[chan], 0);
 241
 242        /* 8 data bits, 1 stop bit */
 243        out_le32(mv64x60_base + MPSC_MPCR + mpsc_base[chan], (3 << 12));
 244        out_le32(mv64x60_base + SDMA_SDCM + sdma_base, SDMA_SDCM_ERD);
 245        out_le32(mv64x60_base + MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_EH);
 246
 247        udelay(100);
 248
 249        return chan;
 250}
 251
 252static void
 253stop_dma(int chan)
 254{
 255        int     i;
 256
 257        /* Abort MPSC Rx (aborting Tx messes things up) */
 258        out_le32(mv64x60_base + MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_RA);
 259
 260        /* Abort SDMA Rx, Tx */
 261        out_le32(mv64x60_base + sdma_regs[chan].sdcm,
 262                SDMA_SDCM_AR | SDMA_SDCM_STD);
 263
 264        for (i=0; i<MAX_RESET_WAIT; i++) {
 265                if ((in_le32(mv64x60_base + sdma_regs[chan].sdcm) &
 266                                (SDMA_SDCM_AR | SDMA_SDCM_AT)) == 0)
 267                        break;
 268
 269                udelay(100);
 270        }
 271}
 272
 273static int
 274wait_for_ownership(int chan)
 275{
 276        int     i;
 277
 278        for (i=0; i<MAX_TX_WAIT; i++) {
 279                if ((in_le32(mv64x60_base + sdma_regs[chan].sdcm) &
 280                                SDMA_SDCM_TXD) == 0)
 281                        break;
 282
 283                udelay(1000);
 284        }
 285
 286        return (i < MAX_TX_WAIT);
 287}
 288
 289void
 290serial_putc(unsigned long com_port, unsigned char c)
 291{
 292        struct mv64x60_tx_desc  *tdp;
 293
 294        if (wait_for_ownership(com_port) == 0)
 295                return;
 296
 297        tdp = &td[com_port][cur_td[com_port]];
 298        if (++cur_td[com_port] >= TX_NUM_DESC)
 299                cur_td[com_port] = 0;
 300
 301        *(unchar *)(tdp->buffer ^ 7) = c;
 302        tdp->bytecnt = 1;
 303        tdp->shadow = 1;
 304        tdp->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |
 305                SDMA_DESC_CMDSTAT_O;
 306
 307        out_le32(mv64x60_base + sdma_regs[com_port].sctdp, (int)tdp);
 308        out_le32(mv64x60_base + sdma_regs[com_port].sftdp, (int)tdp);
 309        out_le32(mv64x60_base + sdma_regs[com_port].sdcm,
 310                in_le32(mv64x60_base + sdma_regs[com_port].sdcm) |
 311                        SDMA_SDCM_TXD);
 312}
 313
 314unsigned char
 315serial_getc(unsigned long com_port)
 316{
 317        struct mv64x60_rx_desc  *rdp;
 318        unchar                  c = '\0';
 319
 320        rdp = &rd[com_port][cur_rd[com_port]];
 321
 322        if ((rdp->cmd_stat & (SDMA_DESC_CMDSTAT_O|SDMA_DESC_CMDSTAT_ES)) == 0) {
 323                c = *(unchar *)(rdp->buffer ^ 7);
 324                RX_INIT_RDP(rdp);
 325                if (++cur_rd[com_port] >= RX_NUM_DESC)
 326                        cur_rd[com_port] = 0;
 327        }
 328
 329        return c;
 330}
 331
 332int
 333serial_tstc(unsigned long com_port)
 334{
 335        struct mv64x60_rx_desc  *rdp;
 336        int                     loop_count = 0;
 337        int                     rc = 0;
 338
 339        rdp = &rd[com_port][cur_rd[com_port]];
 340
 341        /* Go through rcv descs until empty looking for one with data (no error)*/
 342        while (((rdp->cmd_stat & SDMA_DESC_CMDSTAT_O) == 0) &&
 343                (loop_count++ < RX_NUM_DESC)) {
 344
 345                /* If there was an error, reinit the desc & continue */
 346                if ((rdp->cmd_stat & SDMA_DESC_CMDSTAT_ES) != 0) {
 347                        RX_INIT_RDP(rdp);
 348                        if (++cur_rd[com_port] >= RX_NUM_DESC)
 349                                cur_rd[com_port] = 0;
 350                        rdp = (struct mv64x60_rx_desc *)rdp->next_desc_ptr;
 351                } else {
 352                        rc = 1;
 353                        break;
 354                }
 355        }
 356
 357        return rc;
 358}
 359
 360void
 361serial_close(unsigned long com_port)
 362{
 363        stop_dma(com_port);
 364}
 365