xref: /netbsd-src/sys/arch/arm/nvidia/tegra_com.c (revision 6e54367a22fbc89a1139d033e95bec0c0cf0975b)
1*6e54367aSthorpej /* $NetBSD: tegra_com.c,v 1.15 2021/01/27 03:10:19 thorpej Exp $ */
2d4fd1143Sjmcneill 
3d4fd1143Sjmcneill /*-
4d4fd1143Sjmcneill  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5d4fd1143Sjmcneill  * All rights reserved.
6d4fd1143Sjmcneill  *
7d4fd1143Sjmcneill  * This code is derived from software contributed to The NetBSD Foundation
8d4fd1143Sjmcneill  * by Matt Thomas of 3am Software Foundry.
9d4fd1143Sjmcneill  *
10d4fd1143Sjmcneill  * Redistribution and use in source and binary forms, with or without
11d4fd1143Sjmcneill  * modification, are permitted provided that the following conditions
12d4fd1143Sjmcneill  * are met:
13d4fd1143Sjmcneill  * 1. Redistributions of source code must retain the above copyright
14d4fd1143Sjmcneill  *    notice, this list of conditions and the following disclaimer.
15d4fd1143Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
16d4fd1143Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
17d4fd1143Sjmcneill  *    documentation and/or other materials provided with the distribution.
18d4fd1143Sjmcneill  *
19d4fd1143Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d4fd1143Sjmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d4fd1143Sjmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d4fd1143Sjmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d4fd1143Sjmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d4fd1143Sjmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d4fd1143Sjmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d4fd1143Sjmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d4fd1143Sjmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d4fd1143Sjmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d4fd1143Sjmcneill  * POSSIBILITY OF SUCH DAMAGE.
30d4fd1143Sjmcneill  */
31d4fd1143Sjmcneill 
32d4fd1143Sjmcneill #include <sys/cdefs.h>
33d4fd1143Sjmcneill 
34*6e54367aSthorpej __KERNEL_RCSID(1, "$NetBSD: tegra_com.c,v 1.15 2021/01/27 03:10:19 thorpej Exp $");
35d4fd1143Sjmcneill 
36d4fd1143Sjmcneill #include <sys/param.h>
37d4fd1143Sjmcneill #include <sys/bus.h>
38d4fd1143Sjmcneill #include <sys/device.h>
39d4fd1143Sjmcneill #include <sys/intr.h>
40d4fd1143Sjmcneill #include <sys/systm.h>
41d4fd1143Sjmcneill #include <sys/time.h>
42d4fd1143Sjmcneill #include <sys/termios.h>
43d4fd1143Sjmcneill 
44d4fd1143Sjmcneill #include <arm/nvidia/tegra_reg.h>
45d4fd1143Sjmcneill #include <arm/nvidia/tegra_var.h>
46d4fd1143Sjmcneill 
47d4fd1143Sjmcneill #include <dev/ic/comvar.h>
48d4fd1143Sjmcneill 
49d59db8d0Sjmcneill #include <dev/fdt/fdtvar.h>
50d59db8d0Sjmcneill 
51d4fd1143Sjmcneill static int tegra_com_match(device_t, cfdata_t, void *);
52d4fd1143Sjmcneill static void tegra_com_attach(device_t, device_t, void *);
53d4fd1143Sjmcneill 
54*6e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
55*6e54367aSthorpej 	{ .compat = "nvidia,tegra210-uart" },
56*6e54367aSthorpej 	{ .compat = "nvidia,tegra124-uart" },
57*6e54367aSthorpej 	{ .compat = "nvidia,tegra20-uart" },
58*6e54367aSthorpej 	DEVICE_COMPAT_EOL
5973b64c76Sjmcneill };
6073b64c76Sjmcneill 
61d4fd1143Sjmcneill struct tegra_com_softc {
62d4fd1143Sjmcneill 	struct com_softc tsc_sc;
63d4fd1143Sjmcneill 	void *tsc_ih;
6493e0bfebSjmcneill 
6593e0bfebSjmcneill 	struct clk *tsc_clk;
6693e0bfebSjmcneill 	struct fdtbus_reset *tsc_rst;
67d4fd1143Sjmcneill };
68d4fd1143Sjmcneill 
69d4fd1143Sjmcneill CFATTACH_DECL_NEW(tegra_com, sizeof(struct tegra_com_softc),
70d4fd1143Sjmcneill 	tegra_com_match, tegra_com_attach, NULL, NULL);
71d4fd1143Sjmcneill 
72d4fd1143Sjmcneill static int
tegra_com_match(device_t parent,cfdata_t cf,void * aux)73d4fd1143Sjmcneill tegra_com_match(device_t parent, cfdata_t cf, void *aux)
74d4fd1143Sjmcneill {
75d59db8d0Sjmcneill 	struct fdt_attach_args * const faa = aux;
76d4fd1143Sjmcneill 
77*6e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
78d4fd1143Sjmcneill }
79d4fd1143Sjmcneill 
80d4fd1143Sjmcneill static void
tegra_com_attach(device_t parent,device_t self,void * aux)81d4fd1143Sjmcneill tegra_com_attach(device_t parent, device_t self, void *aux)
82d4fd1143Sjmcneill {
83d4fd1143Sjmcneill 	struct tegra_com_softc * const tsc = device_private(self);
84d4fd1143Sjmcneill 	struct com_softc * const sc = &tsc->tsc_sc;
85d59db8d0Sjmcneill 	struct fdt_attach_args * const faa = aux;
86c30892caSjmcneill 	bus_space_tag_t bst = faa->faa_bst;
87d4fd1143Sjmcneill 	bus_space_handle_t bsh;
88d59db8d0Sjmcneill 	char intrstr[128];
89d59db8d0Sjmcneill 	bus_addr_t addr;
90d59db8d0Sjmcneill 	bus_size_t size;
91d59db8d0Sjmcneill 	u_int reg_shift;
924e8cdc22Sjmcneill 	int error;
93d59db8d0Sjmcneill 
94d59db8d0Sjmcneill 	if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
95d59db8d0Sjmcneill 		aprint_error(": couldn't get registers\n");
96d59db8d0Sjmcneill 		return;
97d59db8d0Sjmcneill 	}
98d59db8d0Sjmcneill 
994e8cdc22Sjmcneill 	if (of_getprop_uint32(faa->faa_phandle, "reg-shift", &reg_shift)) {
1004e8cdc22Sjmcneill 		/* missing or bad reg-shift property, assume 2 */
101c30892caSjmcneill 		reg_shift = 2;
102d59db8d0Sjmcneill 	}
103d4fd1143Sjmcneill 
104d4fd1143Sjmcneill 	sc->sc_dev = self;
105d59db8d0Sjmcneill 
10693e0bfebSjmcneill 	tsc->tsc_clk = fdtbus_clock_get_index(faa->faa_phandle, 0);
10793e0bfebSjmcneill 	tsc->tsc_rst = fdtbus_reset_get(faa->faa_phandle, "serial");
10893e0bfebSjmcneill 
10993e0bfebSjmcneill 	if (tsc->tsc_clk == NULL) {
11093e0bfebSjmcneill 		aprint_error(": couldn't get frequency\n");
11193e0bfebSjmcneill 		return;
112d59db8d0Sjmcneill 	}
11393e0bfebSjmcneill 
11493e0bfebSjmcneill 	sc->sc_frequency = clk_get_rate(tsc->tsc_clk);
115ec484ab4Sjmcneill 	sc->sc_type = COM_TYPE_TEGRA;
116d4fd1143Sjmcneill 
117d59db8d0Sjmcneill 	error = bus_space_map(bst, addr, size, 0, &bsh);
118d59db8d0Sjmcneill 	if (error) {
1192e65b46dSskrll 		aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, error);
120d59db8d0Sjmcneill 		return;
121d4fd1143Sjmcneill 	}
122d59db8d0Sjmcneill 
123c30892caSjmcneill 	com_init_regs_stride(&sc->sc_regs, bst, bsh, addr, reg_shift);
124d4fd1143Sjmcneill 
125d4fd1143Sjmcneill 	com_attach_subr(sc);
126d4fd1143Sjmcneill 	aprint_naive("\n");
127d4fd1143Sjmcneill 
128d59db8d0Sjmcneill 	if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) {
129d59db8d0Sjmcneill 		aprint_error_dev(self, "failed to decode interrupt\n");
130d59db8d0Sjmcneill 		return;
131d59db8d0Sjmcneill 	}
132d59db8d0Sjmcneill 
1333f513eddSjmcneill 	tsc->tsc_ih = fdtbus_intr_establish_xname(faa->faa_phandle, 0,
1343f513eddSjmcneill 	    IPL_SERIAL, FDT_INTR_MPSAFE, comintr, sc, device_xname(self));
135d59db8d0Sjmcneill 	if (tsc->tsc_ih == NULL) {
136d59db8d0Sjmcneill 		aprint_error_dev(self, "failed to establish interrupt on %s\n",
137d59db8d0Sjmcneill 		    intrstr);
138d59db8d0Sjmcneill 	}
139d59db8d0Sjmcneill 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
140d4fd1143Sjmcneill }
14173b64c76Sjmcneill 
14273b64c76Sjmcneill /*
14373b64c76Sjmcneill  * Console support
14473b64c76Sjmcneill  */
14573b64c76Sjmcneill 
14673b64c76Sjmcneill static int
tegra_com_console_match(int phandle)14773b64c76Sjmcneill tegra_com_console_match(int phandle)
14873b64c76Sjmcneill {
149*6e54367aSthorpej 	return of_compatible_match(phandle, compat_data);
15073b64c76Sjmcneill }
15173b64c76Sjmcneill 
15273b64c76Sjmcneill static void
tegra_com_console_consinit(struct fdt_attach_args * faa,u_int uart_freq)153faf8273eSjmcneill tegra_com_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
15473b64c76Sjmcneill {
15573b64c76Sjmcneill 	const int phandle = faa->faa_phandle;
156c30892caSjmcneill 	bus_space_tag_t bst = faa->faa_bst;
157c30892caSjmcneill 	bus_space_handle_t dummy_bsh;
158c30892caSjmcneill 	struct com_regs regs;
15973b64c76Sjmcneill 	bus_addr_t addr;
16073b64c76Sjmcneill 	tcflag_t flags;
161c30892caSjmcneill 	u_int reg_shift;
16273b64c76Sjmcneill 	int speed;
16373b64c76Sjmcneill 
16473b64c76Sjmcneill 	fdtbus_get_reg(phandle, 0, &addr, NULL);
16573b64c76Sjmcneill 	speed = fdtbus_get_stdout_speed();
16673b64c76Sjmcneill 	if (speed < 0)
16773b64c76Sjmcneill 		speed = 115200;	/* default */
16873b64c76Sjmcneill 	flags = fdtbus_get_stdout_flags();
16973b64c76Sjmcneill 
170c30892caSjmcneill 	if (of_getprop_uint32(faa->faa_phandle, "reg-shift", &reg_shift)) {
171c30892caSjmcneill 		/* missing or bad reg-shift property, assume 2 */
172c30892caSjmcneill 		reg_shift = 2;
173c30892caSjmcneill 	}
174c30892caSjmcneill 
175c30892caSjmcneill 	memset(&dummy_bsh, 0, sizeof(dummy_bsh));
176c30892caSjmcneill 	com_init_regs_stride(&regs, bst, dummy_bsh, addr, reg_shift);
177c30892caSjmcneill 
178c30892caSjmcneill 	if (comcnattach1(&regs, speed, uart_freq, COM_TYPE_TEGRA, flags))
17973b64c76Sjmcneill 		panic("Cannot initialize tegra com console");
18073b64c76Sjmcneill }
18173b64c76Sjmcneill 
18273b64c76Sjmcneill static const struct fdt_console tegra_com_console = {
18373b64c76Sjmcneill 	.match = tegra_com_console_match,
18473b64c76Sjmcneill 	.consinit = tegra_com_console_consinit,
18573b64c76Sjmcneill };
18673b64c76Sjmcneill 
18773b64c76Sjmcneill FDT_CONSOLE(tegra_com, &tegra_com_console);
188