]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/powerpc/boot/mpsc.c
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6.git] / arch / powerpc / boot / mpsc.c
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 extern 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
48 static volatile char *mpsc_base;
49 static volatile char *mpscintr_base;
50 static u32 chr1, chr2;
51
52 static 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
65 static 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
73 static 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
89 static u8 mpsc_tstc(void)
90 {
91         return (u8)((in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE))
92                                 & MPSC_INTR_CAUSE_RCC) != 0);
93 }
94
95 static 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
105 static 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
122 err_out:
123         return NULL;
124 }
125
126 int 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
168 err_out:
169         return -1;
170 }