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 20extern void udelay(long delay); 21 22#define MPSC_CHR_1 0x000c 23 24#define MPSC_CHR_2 0x0010 25#define MPSC_CHR_2_TA (1<<7) 26#define MPSC_CHR_2_TCS (1<<9) 27#define MPSC_CHR_2_RA (1<<23) 28#define MPSC_CHR_2_CRD (1<<25) 29#define MPSC_CHR_2_EH (1<<31) 30 31#define MPSC_CHR_4 0x0018 32#define MPSC_CHR_4_Z (1<<29) 33 34#define MPSC_CHR_5 0x001c 35#define MPSC_CHR_5_CTL1_INTR (1<<12) 36#define MPSC_CHR_5_CTL1_VALID (1<<15) 37 38#define MPSC_CHR_10 0x0030 39 40#define MPSC_INTR_CAUSE 0x0000 41#define MPSC_INTR_CAUSE_RCC (1<<6) 42#define MPSC_INTR_MASK 0x0080 43 44#define SDMA_SDCM 0x0008 45#define SDMA_SDCM_AR (1<<15) 46#define SDMA_SDCM_AT (1<<31) 47 48static volatile char *mpsc_base; 49static volatile char *mpscintr_base; 50static u32 chr1, chr2; 51 52static int mpsc_open(void) 53{ 54 chr1 = in_le32((u32 *)(mpsc_base + MPSC_CHR_1)) & 0x00ff0000; 55 chr2 = in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & ~(MPSC_CHR_2_TA 56 | MPSC_CHR_2_TCS | MPSC_CHR_2_RA | MPSC_CHR_2_CRD 57 | MPSC_CHR_2_EH); 58 out_le32((u32 *)(mpsc_base + MPSC_CHR_4), MPSC_CHR_4_Z); 59 out_le32((u32 *)(mpsc_base + MPSC_CHR_5), 60 MPSC_CHR_5_CTL1_INTR | MPSC_CHR_5_CTL1_VALID); 61 out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_EH); 62 return 0; 63} 64 65static void mpsc_putc(unsigned char c) 66{ 67 while (in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & MPSC_CHR_2_TCS); 68 69 out_le32((u32 *)(mpsc_base + MPSC_CHR_1), chr1 | c); 70 out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_TCS); 71} 72 73static unsigned char mpsc_getc(void) 74{ 75 u32 cause = 0; 76 unsigned char c; 77 78 while (!(cause & MPSC_INTR_CAUSE_RCC)) 79 cause = in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE)); 80 81 c = in_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2)); 82 out_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2), c); 83 out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 84 cause & ~MPSC_INTR_CAUSE_RCC); 85 86 return c; 87} 88 89static u8 mpsc_tstc(void) 90{ 91 return (u8)((in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE)) 92 & MPSC_INTR_CAUSE_RCC) != 0); 93} 94 95static void mpsc_stop_dma(volatile char *sdma_base) 96{ 97 out_le32((u32 *)(mpsc_base + MPSC_CHR_2),MPSC_CHR_2_TA | MPSC_CHR_2_RA); 98 out_le32((u32 *)(sdma_base + SDMA_SDCM), SDMA_SDCM_AR | SDMA_SDCM_AT); 99 100 while ((in_le32((u32 *)(sdma_base + SDMA_SDCM)) 101 & (SDMA_SDCM_AR | SDMA_SDCM_AT)) != 0) 102 udelay(100); 103} 104 105static volatile char *mpsc_get_virtreg_of_phandle(void *devp, char *prop) 106{ 107 void *v; 108 int n; 109 110 n = getprop(devp, prop, &v, sizeof(v)); 111 if (n != sizeof(v)) 112 goto err_out; 113 114 devp = find_node_by_linuxphandle((u32)v); 115 if (devp == NULL) 116 goto err_out; 117 118 n = getprop(devp, "virtual-reg", &v, sizeof(v)); 119 if (n == sizeof(v)) 120 return v; 121 122err_out: 123 return NULL; 124} 125 126int mpsc_console_init(void *devp, struct serial_console_data *scdp) 127{ 128 void *v; 129 int n, reg_set; 130 volatile char *sdma_base; 131 132 n = getprop(devp, "virtual-reg", &v, sizeof(v)); 133 if (n != sizeof(v)) 134 goto err_out; 135 mpsc_base = v; 136 137 sdma_base = mpsc_get_virtreg_of_phandle(devp, "sdma"); 138 if (sdma_base == NULL) 139 goto err_out; 140 141 mpscintr_base = mpsc_get_virtreg_of_phandle(devp, "mpscintr"); 142 if (mpscintr_base == NULL) 143 goto err_out; 144 145 n = getprop(devp, "block-index", &v, sizeof(v)); 146 if (n != sizeof(v)) 147 goto err_out; 148 reg_set = (int)v; 149 150 mpscintr_base += (reg_set == 0) ? 0x4 : 0xc; 151 152 /* Make sure the mpsc ctlrs are shutdown */ 153 out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0); 154 out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0); 155 out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0); 156 out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0); 157 158 mpsc_stop_dma(sdma_base); 159 160 scdp->open = mpsc_open; 161 scdp->putc = mpsc_putc; 162 scdp->getc = mpsc_getc; 163 scdp->tstc = mpsc_tstc; 164 scdp->close = NULL; 165 166 return 0; 167 168err_out: 169 return -1; 170} 171