Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/sysdev/mv64x60_udbg.c
10817 views
1
/*
2
* udbg serial input/output routines for the Marvell MV64x60 (Discovery).
3
*
4
* Author: Dale Farnsworth <[email protected]>
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 <asm/io.h>
13
#include <asm/prom.h>
14
#include <asm/udbg.h>
15
16
#include <sysdev/mv64x60.h>
17
18
#define MPSC_0_CR1_OFFSET 0x000c
19
20
#define MPSC_0_CR2_OFFSET 0x0010
21
#define MPSC_CHR_2_TCS (1 << 9)
22
23
#define MPSC_0_CHR_10_OFFSET 0x0030
24
25
#define MPSC_INTR_CAUSE_OFF_0 0x0004
26
#define MPSC_INTR_CAUSE_OFF_1 0x000c
27
#define MPSC_INTR_CAUSE_RCC (1<<6)
28
29
static void __iomem *mpsc_base;
30
static void __iomem *mpsc_intr_cause;
31
32
static void mv64x60_udbg_putc(char c)
33
{
34
if (c == '\n')
35
mv64x60_udbg_putc('\r');
36
37
while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
38
;
39
out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
40
out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
41
}
42
43
static int mv64x60_udbg_testc(void)
44
{
45
return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
46
}
47
48
static int mv64x60_udbg_getc(void)
49
{
50
int cause = 0;
51
int c;
52
53
while (!mv64x60_udbg_testc())
54
;
55
56
c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
57
out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
58
out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
59
return c;
60
}
61
62
static int mv64x60_udbg_getc_poll(void)
63
{
64
if (!mv64x60_udbg_testc())
65
return -1;
66
67
return mv64x60_udbg_getc();
68
}
69
70
static void mv64x60_udbg_init(void)
71
{
72
struct device_node *np, *mpscintr, *stdout = NULL;
73
const char *path;
74
const phandle *ph;
75
struct resource r[2];
76
const int *block_index;
77
int intr_cause_offset;
78
int err;
79
80
path = of_get_property(of_chosen, "linux,stdout-path", NULL);
81
if (!path)
82
return;
83
84
stdout = of_find_node_by_path(path);
85
if (!stdout)
86
return;
87
88
for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") {
89
if (np == stdout)
90
break;
91
}
92
93
of_node_put(stdout);
94
if (!np)
95
return;
96
97
block_index = of_get_property(np, "cell-index", NULL);
98
if (!block_index)
99
goto error;
100
101
switch (*block_index) {
102
case 0:
103
intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
104
break;
105
case 1:
106
intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
107
break;
108
default:
109
goto error;
110
}
111
112
err = of_address_to_resource(np, 0, &r[0]);
113
if (err)
114
goto error;
115
116
ph = of_get_property(np, "mpscintr", NULL);
117
mpscintr = of_find_node_by_phandle(*ph);
118
if (!mpscintr)
119
goto error;
120
121
err = of_address_to_resource(mpscintr, 0, &r[1]);
122
of_node_put(mpscintr);
123
if (err)
124
goto error;
125
126
of_node_put(np);
127
128
mpsc_base = ioremap(r[0].start, r[0].end - r[0].start + 1);
129
if (!mpsc_base)
130
return;
131
132
mpsc_intr_cause = ioremap(r[1].start, r[1].end - r[1].start + 1);
133
if (!mpsc_intr_cause) {
134
iounmap(mpsc_base);
135
return;
136
}
137
mpsc_intr_cause += intr_cause_offset;
138
139
udbg_putc = mv64x60_udbg_putc;
140
udbg_getc = mv64x60_udbg_getc;
141
udbg_getc_poll = mv64x60_udbg_getc_poll;
142
143
return;
144
145
error:
146
of_node_put(np);
147
}
148
149
void mv64x60_init_early(void)
150
{
151
mv64x60_udbg_init();
152
}
153
154