xref: /netbsd/sys/arch/arm/nvidia/tegra_platform.c (revision 2e4048e4)
1*2e4048e4Sskrll /* $NetBSD: tegra_platform.c,v 1.28 2023/04/07 08:55:30 skrll Exp $ */
2a7aa900aSjmcneill 
3a7aa900aSjmcneill /*-
4a7aa900aSjmcneill  * Copyright (c) 2017 Jared D. McNeill <jmcneill@invisible.ca>
5a7aa900aSjmcneill  * All rights reserved.
6a7aa900aSjmcneill  *
7a7aa900aSjmcneill  * Redistribution and use in source and binary forms, with or without
8a7aa900aSjmcneill  * modification, are permitted provided that the following conditions
9a7aa900aSjmcneill  * are met:
10a7aa900aSjmcneill  * 1. Redistributions of source code must retain the above copyright
11a7aa900aSjmcneill  *    notice, this list of conditions and the following disclaimer.
12a7aa900aSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13a7aa900aSjmcneill  *    notice, this list of conditions and the following disclaimer in the
14a7aa900aSjmcneill  *    documentation and/or other materials provided with the distribution.
15a7aa900aSjmcneill  *
16a7aa900aSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17a7aa900aSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18a7aa900aSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19a7aa900aSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20a7aa900aSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21a7aa900aSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22a7aa900aSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23a7aa900aSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24a7aa900aSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a7aa900aSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a7aa900aSjmcneill  * SUCH DAMAGE.
27a7aa900aSjmcneill  */
28a7aa900aSjmcneill 
29e4a950e6Sskrll #include "opt_arm_debug.h"
3059508e8aSskrll #include "opt_console.h"
31e4a950e6Sskrll #include "opt_multiprocessor.h"
32e4a950e6Sskrll #include "opt_tegra.h"
33a7aa900aSjmcneill 
34a7aa900aSjmcneill #include "ukbd.h"
35a7aa900aSjmcneill 
36a7aa900aSjmcneill #include <sys/cdefs.h>
37*2e4048e4Sskrll __KERNEL_RCSID(0, "$NetBSD: tegra_platform.c,v 1.28 2023/04/07 08:55:30 skrll Exp $");
38a7aa900aSjmcneill 
39a7aa900aSjmcneill #include <sys/param.h>
40a7aa900aSjmcneill #include <sys/bus.h>
41a7aa900aSjmcneill #include <sys/cpu.h>
42a7aa900aSjmcneill #include <sys/device.h>
43a7aa900aSjmcneill #include <sys/termios.h>
44a7aa900aSjmcneill 
45a7aa900aSjmcneill #include <dev/fdt/fdtvar.h>
46a7aa900aSjmcneill 
47a7aa900aSjmcneill #include <uvm/uvm_extern.h>
48a7aa900aSjmcneill 
49a7aa900aSjmcneill #include <machine/bootconfig.h>
50a7aa900aSjmcneill #include <arm/cpufunc.h>
51a7aa900aSjmcneill 
52a7aa900aSjmcneill #include <arm/nvidia/tegra_reg.h>
53a7aa900aSjmcneill #include <arm/nvidia/tegra_var.h>
548694f07cSryo #include <arm/nvidia/tegra_platform.h>
55a7aa900aSjmcneill 
5679b9098aSjmcneill #include <arm/fdt/arm_fdtvar.h>
57a7aa900aSjmcneill 
5856ba9c3dSjmcneill #include <arm/arm/psci.h>
590102a965Sryo #include <arm/fdt/psci_fdtvar.h>
6056ba9c3dSjmcneill 
61a7aa900aSjmcneill #if NUKBD > 0
62a7aa900aSjmcneill #include <dev/usb/ukbdvar.h>
63a7aa900aSjmcneill #endif
64a7aa900aSjmcneill 
6513d8fe7bSjmcneill #include <dev/ic/ns16550reg.h>
6613d8fe7bSjmcneill #include <dev/ic/comreg.h>
6713d8fe7bSjmcneill 
6845b0a61fSjmcneill #define	PLLP_OUT0_FREQ	408000000
6945b0a61fSjmcneill 
708694f07cSryo void tegra_platform_early_putchar(char);
718694f07cSryo 
72078bd70bSskrll void __noasan
tegra_platform_early_putchar(char c)73763b86b6Sskrll tegra_platform_early_putchar(char c)
74763b86b6Sskrll {
75763b86b6Sskrll #ifdef CONSADDR
76763b86b6Sskrll #define CONSADDR_VA	(CONSADDR - TEGRA_APB_BASE + TEGRA_APB_VBASE)
77763b86b6Sskrll 
78763b86b6Sskrll 	volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
79763b86b6Sskrll 	    (volatile uint32_t *)CONSADDR_VA :
80763b86b6Sskrll 	    (volatile uint32_t *)CONSADDR;
81763b86b6Sskrll 
82763b86b6Sskrll 	while ((uartaddr[com_lsr] & LSR_TXRDY) == 0)
83763b86b6Sskrll 		;
84763b86b6Sskrll 
85763b86b6Sskrll 	uartaddr[com_data] = c;
86763b86b6Sskrll #endif
87763b86b6Sskrll }
88763b86b6Sskrll 
899eb7dc8eSuwe #if defined(SOC_TEGRA124) || defined(SOC_TEGRA210)
90a7aa900aSjmcneill static const struct pmap_devmap *
tegra_platform_devmap(void)91a7aa900aSjmcneill tegra_platform_devmap(void)
92a7aa900aSjmcneill {
93a7aa900aSjmcneill 	static const struct pmap_devmap devmap[] = {
94a7aa900aSjmcneill 		DEVMAP_ENTRY(TEGRA_HOST1X_VBASE,
95a7aa900aSjmcneill 			     TEGRA_HOST1X_BASE,
96a7aa900aSjmcneill 			     TEGRA_HOST1X_SIZE),
97a7aa900aSjmcneill 		DEVMAP_ENTRY(TEGRA_PPSB_VBASE,
98a7aa900aSjmcneill 			     TEGRA_PPSB_BASE,
99a7aa900aSjmcneill 			     TEGRA_PPSB_SIZE),
100a7aa900aSjmcneill 		DEVMAP_ENTRY(TEGRA_APB_VBASE,
101a7aa900aSjmcneill 			     TEGRA_APB_BASE,
102a7aa900aSjmcneill 			     TEGRA_APB_SIZE),
103a7aa900aSjmcneill 		DEVMAP_ENTRY(TEGRA_AHB_A2_VBASE,
104a7aa900aSjmcneill 			     TEGRA_AHB_A2_BASE,
105a7aa900aSjmcneill 			     TEGRA_AHB_A2_SIZE),
106a7aa900aSjmcneill 		DEVMAP_ENTRY_END
107a7aa900aSjmcneill 	};
108a7aa900aSjmcneill 
109a7aa900aSjmcneill 	return devmap;
110a7aa900aSjmcneill }
1119eb7dc8eSuwe #endif	/* SOC_TEGRA124 || SOC_TEGRA210 */
112a7aa900aSjmcneill 
113e4a950e6Sskrll #if defined(SOC_TEGRA124)
114a7aa900aSjmcneill static void
tegra124_platform_bootstrap(void)1152f0a559aSjmcneill tegra124_platform_bootstrap(void)
116a7aa900aSjmcneill {
1178694f07cSryo #ifdef MULTIPROCESSOR
118e4a950e6Sskrll 	arm_cpu_max = 1 + __SHIFTOUT(armreg_l2ctrl_read(), L2CTRL_NUMCPU);
1198694f07cSryo #endif
120e4a950e6Sskrll 
121e4a950e6Sskrll 	tegra_bootstrap();
1222f0a559aSjmcneill }
12356ba9c3dSjmcneill #endif
1242f0a559aSjmcneill 
125e4a950e6Sskrll #if defined(SOC_TEGRA210)
1262f0a559aSjmcneill static void
tegra210_platform_bootstrap(void)1272f0a559aSjmcneill tegra210_platform_bootstrap(void)
1282f0a559aSjmcneill {
129e4a950e6Sskrll 
1302f0a559aSjmcneill 	tegra_bootstrap();
1316ae27e98Sjmcneill 
1326ae27e98Sjmcneill #if defined(MULTIPROCESSOR) && defined(__aarch64__)
1336ae27e98Sjmcneill 	arm_fdt_cpu_bootstrap();
1346ae27e98Sjmcneill #endif
135e4a950e6Sskrll }
13656ba9c3dSjmcneill #endif
137a7aa900aSjmcneill 
1389eb7dc8eSuwe #if defined(SOC_TEGRA124) || defined(SOC_TEGRA210)
139a7aa900aSjmcneill static void
tegra_platform_init_attach_args(struct fdt_attach_args * faa)1405c283536Sjmcneill tegra_platform_init_attach_args(struct fdt_attach_args *faa)
1415c283536Sjmcneill {
1428694f07cSryo 	extern struct bus_space arm_generic_bs_tag;
1432e1981a2Sryo 	extern struct arm32_bus_dma_tag arm_generic_dma_tag;
1445c283536Sjmcneill 
1458694f07cSryo 	faa->faa_bst = &arm_generic_bs_tag;
1462e1981a2Sryo 	faa->faa_dmat = &arm_generic_dma_tag;
1475c283536Sjmcneill }
1485c283536Sjmcneill 
149a7aa900aSjmcneill static void
tegra_platform_device_register(device_t self,void * aux)150a7aa900aSjmcneill tegra_platform_device_register(device_t self, void *aux)
151a7aa900aSjmcneill {
152a7aa900aSjmcneill 	prop_dictionary_t dict = device_properties(self);
153a7aa900aSjmcneill 
154a7aa900aSjmcneill 	if (device_is_a(self, "tegrafb") &&
155a7aa900aSjmcneill 	    match_bootconf_option(boot_args, "console", "fb")) {
156a7aa900aSjmcneill 		prop_dictionary_set_bool(dict, "is_console", true);
157a7aa900aSjmcneill #if NUKBD > 0
158a7aa900aSjmcneill 		ukbd_cnattach();
159a7aa900aSjmcneill #endif
160a7aa900aSjmcneill 	}
161a7aa900aSjmcneill 
162a7aa900aSjmcneill 	if (device_is_a(self, "tegradrm")) {
163a7aa900aSjmcneill 		const char *video = get_bootconf_string(boot_args, "video");
164a7aa900aSjmcneill 		if (video)
165280931ccSskrll 			prop_dictionary_set_string(dict, "HDMI-A-1", video);
166a7aa900aSjmcneill 		if (match_bootconf_option(boot_args, "hdmi.forcemode", "dvi"))
167a7aa900aSjmcneill 			prop_dictionary_set_bool(dict, "force-dvi", true);
168a7aa900aSjmcneill 	}
169a7aa900aSjmcneill 
170a7aa900aSjmcneill 	if (device_is_a(self, "tegracec"))
171280931ccSskrll 		prop_dictionary_set_string(dict, "hdmi-device", "tegradrm0");
172a7aa900aSjmcneill 
173a7aa900aSjmcneill 	if (device_is_a(self, "nouveau")) {
174a7aa900aSjmcneill 		const char *config = get_bootconf_string(boot_args,
175a7aa900aSjmcneill 		    "nouveau.config");
176a7aa900aSjmcneill 		if (config)
177280931ccSskrll 			prop_dictionary_set_string(dict, "config", config);
178a7aa900aSjmcneill 		const char *debug = get_bootconf_string(boot_args,
179a7aa900aSjmcneill 		    "nouveau.debug");
180a7aa900aSjmcneill 		if (debug)
181280931ccSskrll 			prop_dictionary_set_string(dict, "debug", debug);
182a7aa900aSjmcneill 	}
183a7aa900aSjmcneill 
184a7aa900aSjmcneill 	if (device_is_a(self, "tegrapcie")) {
1858e90f9edSthorpej 		static const struct device_compatible_entry jetsontk1[] = {
1868e90f9edSthorpej 			{ .compat = "nvidia,jetson-tk1" },
1878e90f9edSthorpej 			DEVICE_COMPAT_EOL
188a7aa900aSjmcneill 		};
189a7aa900aSjmcneill 		const int phandle = OF_peer(0);
1908e90f9edSthorpej 		if (of_compatible_match(phandle, jetsontk1)) {
191a7aa900aSjmcneill 			/* rfkill GPIO at GPIO X7 */
192a7aa900aSjmcneill 			struct tegra_gpio_pin *pin =
193a7aa900aSjmcneill 			    tegra_gpio_acquire("X7", GPIO_PIN_OUTPUT);
194a7aa900aSjmcneill 			if (pin)
195a7aa900aSjmcneill 				tegra_gpio_write(pin, 1);
196a7aa900aSjmcneill 		}
197a7aa900aSjmcneill 	}
198a7aa900aSjmcneill }
199a7aa900aSjmcneill 
200a7aa900aSjmcneill static void
tegra_platform_reset(void)201a7aa900aSjmcneill tegra_platform_reset(void)
202a7aa900aSjmcneill {
203a7aa900aSjmcneill 	tegra_pmc_reset();
204a7aa900aSjmcneill }
205a7aa900aSjmcneill 
2068702feb1Sjmcneill static void
tegra_platform_delay(u_int us)2078702feb1Sjmcneill tegra_platform_delay(u_int us)
2088702feb1Sjmcneill {
2098702feb1Sjmcneill 	tegra_timer_delay(us);
2108702feb1Sjmcneill }
2118702feb1Sjmcneill 
21245b0a61fSjmcneill static u_int
tegra_platform_uart_freq(void)21345b0a61fSjmcneill tegra_platform_uart_freq(void)
21445b0a61fSjmcneill {
21545b0a61fSjmcneill 	return PLLP_OUT0_FREQ;
21645b0a61fSjmcneill }
2179eb7dc8eSuwe #endif	/* SOC_TEGRA124 || SOC_TEGRA210 */
21845b0a61fSjmcneill 
219e4a950e6Sskrll #if defined(SOC_TEGRA124)
220*2e4048e4Sskrll static const struct fdt_platform tegra124_platform = {
221*2e4048e4Sskrll 	.fp_devmap = tegra_platform_devmap,
222*2e4048e4Sskrll 	.fp_bootstrap = tegra124_platform_bootstrap,
223*2e4048e4Sskrll 	.fp_init_attach_args = tegra_platform_init_attach_args,
224*2e4048e4Sskrll 	.fp_device_register = tegra_platform_device_register,
225*2e4048e4Sskrll 	.fp_reset = tegra_platform_reset,
226*2e4048e4Sskrll 	.fp_delay = tegra_platform_delay,
227*2e4048e4Sskrll 	.fp_uart_freq = tegra_platform_uart_freq,
228*2e4048e4Sskrll 	.fp_mpstart = tegra124_mpstart,
229a7aa900aSjmcneill };
230a7aa900aSjmcneill 
231*2e4048e4Sskrll FDT_PLATFORM(tegra124, "nvidia,tegra124", &tegra124_platform);
23256ba9c3dSjmcneill #endif
2332f0a559aSjmcneill 
234e4a950e6Sskrll #if defined(SOC_TEGRA210)
235*2e4048e4Sskrll static const struct fdt_platform tegra210_platform = {
236*2e4048e4Sskrll 	.fp_devmap = tegra_platform_devmap,
237*2e4048e4Sskrll 	.fp_bootstrap = tegra210_platform_bootstrap,
238*2e4048e4Sskrll 	.fp_init_attach_args = tegra_platform_init_attach_args,
239*2e4048e4Sskrll 	.fp_device_register = tegra_platform_device_register,
240*2e4048e4Sskrll 	.fp_reset = tegra_platform_reset,
241*2e4048e4Sskrll 	.fp_delay = tegra_platform_delay,
242*2e4048e4Sskrll 	.fp_uart_freq = tegra_platform_uart_freq,
243*2e4048e4Sskrll 	.fp_mpstart = arm_fdt_cpu_mpstart,
2442f0a559aSjmcneill };
2452f0a559aSjmcneill 
246*2e4048e4Sskrll FDT_PLATFORM(tegra210, "nvidia,tegra210", &tegra210_platform);
24756ba9c3dSjmcneill #endif
248