uart_cpu_fdt.c revision 257144
1/*-
2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Semihalf under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/uart/uart_cpu_fdt.c 257144 2013-10-26 03:22:57Z nwhitehorn $");
32
33#include <sys/param.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37
38#include <vm/vm.h>
39#include <vm/pmap.h>
40#include <machine/pmap.h>
41
42#include <machine/bus.h>
43#include <machine/fdt.h>
44
45#include <dev/fdt/fdt_common.h>
46#include <dev/ofw/ofw_bus.h>
47#include <dev/ofw/ofw_bus_subr.h>
48#include <dev/uart/uart.h>
49#include <dev/uart/uart_bus.h>
50#include <dev/uart/uart_cpu.h>
51
52/*
53 * UART console routines.
54 */
55bus_space_tag_t uart_bus_space_io;
56bus_space_tag_t uart_bus_space_mem;
57
58static int
59uart_fdt_get_clock(phandle_t node, pcell_t *cell)
60{
61	pcell_t clock;
62
63	if ((OF_getprop(node, "clock-frequency", &clock,
64	    sizeof(clock))) <= 0)
65		return (ENXIO);
66
67	if (clock == 0)
68		/* Try to retrieve parent 'bus-frequency' */
69		/* XXX this should go to simple-bus fixup or so */
70		if ((OF_getprop(OF_parent(node), "bus-frequency", &clock,
71		    sizeof(clock))) <= 0)
72			clock = 0;
73
74	*cell = fdt32_to_cpu(clock);
75	return (0);
76}
77
78static int
79uart_fdt_get_shift(phandle_t node, pcell_t *cell)
80{
81	pcell_t shift;
82
83	if ((OF_getprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
84		shift = 0;
85	*cell = fdt32_to_cpu(shift);
86	return (0);
87}
88
89int
90uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
91{
92
93	if (b1->bst != b2->bst)
94		return (0);
95	if (pmap_kextract(b1->bsh) == 0)
96		return (0);
97	if (pmap_kextract(b2->bsh) == 0)
98		return (0);
99	return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0);
100}
101
102int
103uart_cpu_getdev(int devtype, struct uart_devinfo *di)
104{
105	char buf[64];
106	struct uart_class *class;
107	phandle_t node, chosen;
108	pcell_t shift, br, rclk;
109	u_long start, size, pbase, psize;
110	int err;
111
112	uart_bus_space_mem = fdtbus_bs_tag;
113	uart_bus_space_io = NULL;
114
115	/* Allow overriding the FDT uning the environment. */
116	class = &uart_ns8250_class;
117	err = uart_getenv(devtype, di, class);
118	if (!err)
119		return (0);
120
121	if (devtype != UART_DEV_CONSOLE)
122		return (ENXIO);
123
124	/*
125	 * Retrieve /chosen/std{in,out}.
126	 */
127	if ((chosen = OF_finddevice("/chosen")) == -1)
128		return (ENXIO);
129	if (OF_getprop(chosen, "stdin", buf, sizeof(buf)) <= 0)
130		return (ENXIO);
131	if ((node = OF_finddevice(buf)) == -1)
132		return (ENXIO);
133	if (OF_getprop(chosen, "stdout", buf, sizeof(buf)) <= 0)
134		return (ENXIO);
135	if (OF_finddevice(buf) != node)
136		/* Only stdin == stdout is supported. */
137		return (ENXIO);
138	/*
139	 * Retrieve serial attributes.
140	 */
141	uart_fdt_get_shift(node, &shift);
142
143	if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0)
144		br = 0;
145	br = fdt32_to_cpu(br);
146
147	if ((err = uart_fdt_get_clock(node, &rclk)) != 0)
148		return (err);
149	/*
150	 * Finalize configuration.
151	 */
152	if (fdt_is_compatible(node, "fsl,imx-uart"))
153		class = &uart_imx_class;
154	else if (fdt_is_compatible(node, "quicc"))
155		class = &uart_quicc_class;
156	else if (fdt_is_compatible(node, "lpc"))
157		class = &uart_lpc_class;
158	else if (fdt_is_compatible(node, "arm,pl011"))
159		class = &uart_pl011_class;
160	else if (fdt_is_compatible(node, "exynos"))
161		class = &uart_s3c2410_class;
162	else if (fdt_is_compatible(node, "cadence,uart"))
163		class = &uart_cdnc_class;
164	else if (fdt_is_compatible(node, "ti,ns16550"))
165		class = &uart_ti8250_class;
166	else if (fdt_is_compatible(node, "ns16550"))
167		class = &uart_ns8250_class;
168
169	di->bas.chan = 0;
170	di->bas.regshft = (u_int)shift;
171	di->baudrate = br;
172	di->bas.rclk = (u_int)rclk;
173	di->ops = uart_getops(class);
174	di->databits = 8;
175	di->stopbits = 1;
176	di->parity = UART_PARITY_NONE;
177	di->bas.bst = uart_bus_space_mem;
178
179	err = fdt_regsize(node, &start, &size);
180	if (err)
181		return (ENXIO);
182	err = fdt_get_range(OF_parent(node), 0, &pbase, &psize);
183	if (err)
184		pbase = 0;
185
186	start += pbase;
187
188	return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh));
189}
190