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 
47 static volatile char *mpsc_base;
48 static volatile char *mpscintr_base;
49 static u32 chr1, chr2;
50 
mpsc_open(void)51 static 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 
mpsc_putc(unsigned char c)64 static 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 
mpsc_getc(void)72 static 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 
mpsc_tstc(void)88 static u8 mpsc_tstc(void)
89 {
90 	return (u8)((in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE))
91 				& MPSC_INTR_CAUSE_RCC) != 0);
92 }
93 
mpsc_stop_dma(volatile char * sdma_base)94 static 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 
mpsc_get_virtreg_of_phandle(void * devp,char * prop)104 static 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 
121 err_out:
122 	return NULL;
123 }
124 
mpsc_console_init(void * devp,struct serial_console_data * scdp)125 int 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 
167 err_out:
168 	return -1;
169 }
170