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