1
2
3
4
5
6
7
8
9
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
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