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