• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/powerpc/sysdev/
1/*
2 * udbg serial input/output routines for the Marvell MV64x60 (Discovery).
3 *
4 * Author: Dale Farnsworth <dale@farnsworth.org>
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
29static void __iomem *mpsc_base;
30static void __iomem *mpsc_intr_cause;
31
32static 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
43static int mv64x60_udbg_testc(void)
44{
45	return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
46}
47
48static 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
62static int mv64x60_udbg_getc_poll(void)
63{
64	if (!mv64x60_udbg_testc())
65		return -1;
66
67	return mv64x60_udbg_getc();
68}
69
70static 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
145error:
146	of_node_put(np);
147}
148
149void mv64x60_init_early(void)
150{
151	mv64x60_udbg_init();
152}
153