Module Name: src Committed By: jmcneill Date: Sun May 28 23:39:30 UTC 2017
Modified Files: src/sys/arch/arm/fdt: armv7_fdt.c src/sys/arch/arm/nvidia: files.tegra src/sys/arch/evbarm/tegra: platform.h tegra_machdep.c Added Files: src/sys/arch/arm/fdt: armv7_fdtvar.h src/sys/arch/arm/nvidia: tegra_platform.c Log Message: Add a facility for platform-specific callbacks and use it to remove most of the Tegra-specific code from tegra_machdep.c. Platform code matches on the compatible property of the root ("/") DT node and allows for chip-specific implementations of the following: - devmap: Return a 0-terminated list of static device map entries. - bootstrap: Early initialization of platform-specific facilities. - early_putchar: Provides an implementation of putchar for use in early debug messages. - device_register: Platform-specific device register callback. - reset: Platform-specific CPU reset implementation. - consinit: Platform-specific console init implementation. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/fdt/armv7_fdt.c cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/fdt/armv7_fdtvar.h cvs rdiff -u -r1.37 -r1.38 src/sys/arch/arm/nvidia/files.tegra cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/nvidia/tegra_platform.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/evbarm/tegra/platform.h cvs rdiff -u -r1.45 -r1.46 src/sys/arch/evbarm/tegra/tegra_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/fdt/armv7_fdt.c diff -u src/sys/arch/arm/fdt/armv7_fdt.c:1.1 src/sys/arch/arm/fdt/armv7_fdt.c:1.2 --- src/sys/arch/arm/fdt/armv7_fdt.c:1.1 Sun May 28 00:40:20 2017 +++ src/sys/arch/arm/fdt/armv7_fdt.c Sun May 28 23:39:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: armv7_fdt.c,v 1.1 2017/05/28 00:40:20 jmcneill Exp $ */ +/* $NetBSD: armv7_fdt.c,v 1.2 2017/05/28 23:39:30 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: armv7_fdt.c,v 1.1 2017/05/28 00:40:20 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: armv7_fdt.c,v 1.2 2017/05/28 23:39:30 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -39,6 +39,8 @@ __KERNEL_RCSID(0, "$NetBSD: armv7_fdt.c, #include <dev/fdt/fdtvar.h> #include <dev/ofw/openfirm.h> +#include <arm/fdt/armv7_fdtvar.h> + static int armv7_fdt_match(device_t, cfdata_t, void *); static void armv7_fdt_attach(device_t, device_t, void *); @@ -51,6 +53,9 @@ extern struct bus_space armv7_generic_bs extern struct bus_space armv7_generic_a4x_bs_tag; extern struct arm32_bus_dma_tag armv7_generic_dma_tag; +static struct armv7_platlist armv7_platform_list = + TAILQ_HEAD_INITIALIZER(armv7_platform_list); + int armv7_fdt_match(device_t parent, cfdata_t cf, void *aux) { @@ -76,3 +81,30 @@ armv7_fdt_attach(device_t parent, device }; config_found(self, &faa, NULL); } + +const struct armv7_platform * +armv7_fdt_platform(void) +{ + static const struct armv7_platform_info *booted_platform = NULL; + + if (booted_platform == NULL) { + __link_set_decl(armv7_platforms, struct armv7_platform_info); + struct armv7_platform_info * const *info; + const struct armv7_platform_info *best_info = NULL; + const int phandle = OF_peer(0); + int match, best_match = 0; + + __link_set_foreach(info, armv7_platforms) { + const char * const compat[] = { (*info)->compat, NULL }; + match = of_match_compatible(phandle, compat); + if (match > best_match) { + best_match = match; + best_info = *info; + } + } + + booted_platform = best_info; + } + + return booted_platform == NULL ? NULL : booted_platform->ops; +} Index: src/sys/arch/arm/nvidia/files.tegra diff -u src/sys/arch/arm/nvidia/files.tegra:1.37 src/sys/arch/arm/nvidia/files.tegra:1.38 --- src/sys/arch/arm/nvidia/files.tegra:1.37 Sun May 28 00:40:20 2017 +++ src/sys/arch/arm/nvidia/files.tegra Sun May 28 23:39:30 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.tegra,v 1.37 2017/05/28 00:40:20 jmcneill Exp $ +# $NetBSD: files.tegra,v 1.38 2017/05/28 23:39:30 jmcneill Exp $ # # Configuration info for NVIDIA Tegra ARM Peripherals # @@ -14,6 +14,7 @@ file arch/arm/arm32/armv7_generic_space. file arch/arm/arm32/armv7_generic_dma.c file arch/arm/arm/bus_space_a4x.S +file arch/arm/nvidia/tegra_platform.c file arch/arm/nvidia/tegra_soc.c file arch/arm/nvidia/tegra_cpufreq.c Index: src/sys/arch/evbarm/tegra/platform.h diff -u src/sys/arch/evbarm/tegra/platform.h:1.2 src/sys/arch/evbarm/tegra/platform.h:1.3 --- src/sys/arch/evbarm/tegra/platform.h:1.2 Sun May 31 22:15:52 2015 +++ src/sys/arch/evbarm/tegra/platform.h Sun May 28 23:39:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: platform.h,v 1.2 2015/05/31 22:15:52 matt Exp $ */ +/* $NetBSD: platform.h,v 1.3 2017/05/28 23:39:30 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -39,6 +39,4 @@ #define KERNEL_VM_SIZE 0x50000000 /* 0x50000000 = 1.25GB */ #endif -#define CONSADDR_VA (CONSADDR - TEGRA_APB_BASE + TEGRA_APB_VBASE) - #endif /* _EVBARM_TEGRA_PLATFORM_H */ Index: src/sys/arch/evbarm/tegra/tegra_machdep.c diff -u src/sys/arch/evbarm/tegra/tegra_machdep.c:1.45 src/sys/arch/evbarm/tegra/tegra_machdep.c:1.46 --- src/sys/arch/evbarm/tegra/tegra_machdep.c:1.45 Sun May 28 15:55:11 2017 +++ src/sys/arch/evbarm/tegra/tegra_machdep.c Sun May 28 23:39:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: tegra_machdep.c,v 1.45 2017/05/28 15:55:11 jmcneill Exp $ */ +/* $NetBSD: tegra_machdep.c,v 1.46 2017/05/28 23:39:30 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tegra_machdep.c,v 1.45 2017/05/28 15:55:11 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tegra_machdep.c,v 1.46 2017/05/28 23:39:30 jmcneill Exp $"); #include "opt_tegra.h" #include "opt_machdep.h" @@ -36,11 +36,6 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_machde #include "opt_arm_debug.h" #include "opt_multiprocessor.h" -#include "com.h" -#include "ukbd.h" -#include "genfb.h" -#include "ether.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -55,13 +50,10 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_machde #include <sys/proc.h> #include <sys/reboot.h> #include <sys/termios.h> -#include <sys/gpio.h> #include <uvm/uvm_extern.h> #include <sys/conf.h> -#include <dev/cons.h> -#include <dev/md.h> #include <machine/db_machdep.h> #include <ddb/db_sym.h> @@ -73,20 +65,10 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_machde #include <arm/arm32/machdep.h> -#include <arm/nvidia/tegra_reg.h> -#include <arm/nvidia/tegra_var.h> - -#include <arm/cortex/gtmr_var.h> - #include <evbarm/include/autoconf.h> #include <evbarm/tegra/platform.h> -#include <dev/ic/ns16550reg.h> -#include <dev/ic/comreg.h> -#include <dev/ic/comvar.h> - -#include <dev/usb/ukbdvar.h> -#include <net/if_ether.h> +#include <arm/fdt/armv7_fdtvar.h> #ifndef TEGRA_MAX_BOOT_STRING #define TEGRA_MAX_BOOT_STRING 1024 @@ -109,46 +91,6 @@ static void tegra_device_register(device static void tegra_reset(void); static void tegra_powerdown(void); -bs_protos(bs_notimpl); - -#define _A(a) ((a) & ~L1_S_OFFSET) -#define _S(s) (((s) + L1_S_SIZE - 1) & ~(L1_S_SIZE-1)) - -static const struct pmap_devmap devmap[] = { - { - .pd_va = _A(TEGRA_HOST1X_VBASE), - .pd_pa = _A(TEGRA_HOST1X_BASE), - .pd_size = _S(TEGRA_HOST1X_SIZE), - .pd_prot = VM_PROT_READ|VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - { - .pd_va = _A(TEGRA_PPSB_VBASE), - .pd_pa = _A(TEGRA_PPSB_BASE), - .pd_size = _S(TEGRA_PPSB_SIZE), - .pd_prot = VM_PROT_READ|VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - { - .pd_va = _A(TEGRA_APB_VBASE), - .pd_pa = _A(TEGRA_APB_BASE), - .pd_size = _S(TEGRA_APB_SIZE), - .pd_prot = VM_PROT_READ|VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - { - .pd_va = _A(TEGRA_AHB_A2_VBASE), - .pd_pa = _A(TEGRA_AHB_A2_BASE), - .pd_size = _S(TEGRA_AHB_A2_SIZE), - .pd_prot = VM_PROT_READ|VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - {0} -}; - -#undef _A -#undef _S - #ifdef PMAP_NEED_ALLOC_POOLPAGE static struct boot_physmem bp_lowgig = { .bp_pages = (KERNEL_VM_BASE - KERNEL_BASE) / NBPG, @@ -161,15 +103,11 @@ static struct boot_physmem bp_lowgig = { static void tegra_putchar(char c) { -#ifdef CONSADDR - volatile uint32_t *uartaddr = (volatile uint32_t *)CONSADDR_VA; - - while ((uartaddr[com_lsr] & LSR_TXRDY) == 0) - ; - - uartaddr[com_data] = c; -#endif + const struct armv7_platform *plat = armv7_fdt_platform(); + if (plat && plat->early_purchar) + plat->early_putchar(c); } + static void tegra_putstr(const char *s) { @@ -201,8 +139,6 @@ tegra_printn(u_int n, int base) #define DPRINTN(x,b) #endif -extern void cortex_mpstart(void); - /* * u_int initarm(...) * @@ -219,24 +155,9 @@ extern void cortex_mpstart(void); u_int initarm(void *arg) { + const struct armv7_platform *plat; uint64_t memory_addr, memory_size; psize_t ram_size = 0; - DPRINT("initarm:"); - - DPRINT(" mpstart<0x"); - DPRINTN((uint32_t)cortex_mpstart, 16); - DPRINT(">"); - - DPRINT(" devmap"); - pmap_devmap_register(devmap); - - DPRINT(" bootstrap"); - tegra_bootstrap(); - - /* Heads up ... Setup the CPU / MMU / TLB functions. */ - DPRINT(" cpufunc"); - if (set_cpufuncs()) - panic("cpu not recognized!"); /* Load FDT */ const uint8_t *fdt_addr_r = (const uint8_t *)uboot_args[2]; @@ -244,15 +165,32 @@ initarm(void *arg) if (error == 0) { error = fdt_move(fdt_addr_r, fdt_data, sizeof(fdt_data)); if (error != 0) { - DPRINT(" (fdt_move failed!)\n"); panic("fdt_move failed: %s", fdt_strerror(error)); } fdtbus_set_data(fdt_data); } else { - DPRINT(" (fdt_check_header failed!)\n"); panic("fdt_check_header failed: %s", fdt_strerror(error)); } + /* Lookup platform specific backend */ + plat = armv7_fdt_platform(); + if (plat == NULL) + panic("Kernel does not support this device"); + + /* Early console may be available, announce ourselves. */ + DPRINT("NetBSD FDT init"); + + DPRINT(" devmap"); + pmap_devmap_register(plat->devmap()); + + DPRINT(" bootstrap"); + plat->bootstrap(); + + /* Heads up ... Setup the CPU / MMU / TLB functions. */ + DPRINT(" cpufunc"); + if (set_cpufuncs()) + panic("cpu not recognized!"); + DPRINT(" consinit"); consinit(); @@ -265,6 +203,7 @@ initarm(void *arg) cpu_reset_address = tegra_reset; cpu_powerdown_address = tegra_powerdown; + evbarm_device_register = tegra_device_register; /* Talk to the user */ DPRINTF("\nNetBSD/evbarm (tegra) booting ...\n"); @@ -326,8 +265,8 @@ initarm(void *arg) arm32_bootmem_init(bootconfig.dram[0].address, ram_size, KERNEL_BASE_PHYS); - arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_HIGH, 0, devmap, - mapallmem_p); + arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_HIGH, 0, + plat->devmap(), mapallmem_p); const int chosen = OF_finddevice("/chosen"); if (chosen >= 0) { @@ -339,8 +278,6 @@ initarm(void *arg) boot_args = bootargs; parse_mi_bootargs(boot_args); - evbarm_device_register = tegra_device_register; - #ifdef PMAP_NEED_ALLOC_POOLPAGE bp_lowgig.bp_start = memory_addr / NBPG; if (atop(ram_size) > bp_lowgig.bp_pages) { @@ -354,152 +291,33 @@ initarm(void *arg) } -#if NCOM > 0 -#ifndef CONMODE -#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ -#endif -#endif - void consinit(void) { - static bool consinit_called = false; + const struct armv7_platform *plat = armv7_fdt_platform(); - if (consinit_called) - return; - consinit_called = true; - -#if NCOM > 0 - bus_addr_t addr; - int speed; - -#ifdef CONSADDR - addr = CONSADDR; -#else - const char *stdout_path = fdtbus_get_stdout_path(); - if (stdout_path == NULL) { - DPRINT(" (can't find stdout-path!)\n"); - panic("Cannot find console device"); - } - DPRINT(" "); - DPRINT(stdout_path); - fdtbus_get_reg(fdtbus_get_stdout_phandle(), 0, &addr, NULL); -#endif - DPRINT(" 0x"); - DPRINTN((uint32_t)addr, 16); - -#ifdef CONSPEED - speed = CONSPEED; -#else - speed = fdtbus_get_stdout_speed(); - if (speed < 0) - speed = 115200; /* default */ -#endif - DPRINT(" "); - DPRINTN((uint32_t)speed, 10); - - const bus_space_tag_t bst = &armv7_generic_a4x_bs_tag; - const u_int freq = 408000000; /* 408MHz PLLP_OUT0 */ - if (comcnattach(bst, addr, speed, freq, COM_TYPE_TEGRA, CONMODE)) - panic("Serial console cannot be initialized."); -#else -#error only COM console is supported -#endif -} - -static bool -tegra_bootconf_match(const char *key, const char *val) -{ - char *s; - - if (!get_bootconf_option(boot_args, key, BOOTOPT_TYPE_STRING, &s)) - return false; - - return strncmp(s, val, strlen(val)) == 0; -} - -static char * -tegra_bootconf_strdup(const char *key) -{ - char *s, *ret; - int i = 0; - - if (!get_bootconf_option(boot_args, key, BOOTOPT_TYPE_STRING, &s)) - return NULL; - - for (;;) { - if (s[i] == ' ' || s[i] == '\t' || s[i] == '\0') - break; - ++i; - } - - ret = kmem_alloc(i + 1, KM_SLEEP); - if (ret == NULL) - return NULL; - - strlcpy(ret, s, i + 1); - return ret; + if (plat && plat->consinit) + plat->consinit(); } void tegra_device_register(device_t self, void *aux) { - prop_dictionary_t dict = device_properties(self); - - if (device_is_a(self, "tegrafb") - && tegra_bootconf_match("console", "fb")) { - prop_dictionary_set_bool(dict, "is_console", true); -#if NUKBD > 0 - ukbd_cnattach(); -#endif - } - - if (device_is_a(self, "tegradrm")) { - const char *video = tegra_bootconf_strdup("video"); - - if (tegra_bootconf_match("hdmi.forcemode", "dvi")) { - prop_dictionary_set_bool(dict, "force-dvi", true); - } - - if (video) { - prop_dictionary_set_cstring(dict, "HDMI-A-1", video); - } - } - - if (device_is_a(self, "tegracec")) { - prop_dictionary_set_cstring(dict, "hdmi-device", "tegradrm0"); - } - - if (device_is_a(self, "nouveau")) { - const char *config = tegra_bootconf_strdup("nouveau.config"); - const char *debug = tegra_bootconf_strdup("nouveau.debug"); - if (config) - prop_dictionary_set_cstring(dict, "config", config); - if (debug) - prop_dictionary_set_cstring(dict, "debug", debug); - } + const struct armv7_platform *plat = armv7_fdt_platform(); - if (device_is_a(self, "tegrapcie")) { - const char * const jetsontk1_compat[] = { - "nvidia,jetson-tk1", NULL - }; - int phandle = OF_peer(0); - if (of_match_compatible(phandle, jetsontk1_compat)) { - /* rfkill GPIO at GPIO X7 */ - struct tegra_gpio_pin *pin; - pin = tegra_gpio_acquire("X7", GPIO_PIN_OUTPUT); - if (pin) { - tegra_gpio_write(pin, 1); - } - } - } + if (plat && plat->device_register) + plat->device_register(self, aux); } static void tegra_reset(void) { + const struct armv7_platform *plat = armv7_fdt_platform(); + fdtbus_power_reset(); - tegra_pmc_reset(); + + if (plat && plat->reset) + plat->reset(); } static void Added files: Index: src/sys/arch/arm/fdt/armv7_fdtvar.h diff -u /dev/null src/sys/arch/arm/fdt/armv7_fdtvar.h:1.1 --- /dev/null Sun May 28 23:39:30 2017 +++ src/sys/arch/arm/fdt/armv7_fdtvar.h Sun May 28 23:39:30 2017 @@ -0,0 +1,60 @@ +/* $NetBSD: armv7_fdtvar.h,v 1.1 2017/05/28 23:39:30 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ARM_ARMV7_FDTVAR_H +#define _ARM_ARMV7_FDTVAR_H + +struct armv7_platform { + const struct pmap_devmap * (*devmap)(void); + void (*bootstrap)(void); + void (*early_putchar)(char); + void (*device_register)(device_t, void *); + void (*reset)(void); + void (*consinit)(void); +}; + +struct armv7_platform_info { + const char * compat; + const struct armv7_platform * ops; +}; + +#define _ARMV7_PLATFORM_REGISTER(name) \ + __link_set_add_rodata(armv7_platforms, __CONCAT(name,_platinfo)); + +#define ARMV7_PLATFORM(_name, _compat, _ops) \ +static const struct armv7_platform_info __CONCAT(_name,_platinfo) = { \ + .compat = (_compat), \ + .ops = (_ops) \ +}; \ +_ARMV7_PLATFORM_REGISTER(_name) + +TAILQ_HEAD(armv7_platlist, armv7_platform_info); + +const struct armv7_platform * armv7_fdt_platform(void); + +#endif /* !_ARM_ARMV7_FDTVAR_H */ Index: src/sys/arch/arm/nvidia/tegra_platform.c diff -u /dev/null src/sys/arch/arm/nvidia/tegra_platform.c:1.1 --- /dev/null Sun May 28 23:39:30 2017 +++ src/sys/arch/arm/nvidia/tegra_platform.c Sun May 28 23:39:30 2017 @@ -0,0 +1,223 @@ +/* $NetBSD: tegra_platform.c,v 1.1 2017/05/28 23:39:30 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_tegra.h" +#include "opt_multiprocessor.h" + +#include "com.h" +#include "ukbd.h" + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: tegra_platform.c,v 1.1 2017/05/28 23:39:30 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/cpu.h> +#include <sys/device.h> +#include <sys/termios.h> + +#include <dev/fdt/fdtvar.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bootconfig.h> +#include <arm/cpufunc.h> + +#include <arm/nvidia/tegra_reg.h> +#include <arm/nvidia/tegra_var.h> + +#include <arm/fdt/armv7_fdtvar.h> + +#if NUKBD > 0 +#include <dev/usb/ukbdvar.h> +#endif + +#if NCOM > 0 +#include <dev/ic/ns16550reg.h> +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> +#ifndef CONMODE +#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +#endif +#endif + +#define DEVMAP_ALIGN(a) ((a) & ~L1_S_OFFSET) +#define DEVMAP_SIZE(s) roundup2((s), L1_S_SIZE) +#define DEVMAP_ENTRY(va, pa, sz) \ + { \ + .pd_va = DEVMAP_ALIGN(va), \ + .pd_pa = DEVMAP_ALIGN(pa), \ + .pd_size = DEVMAP_SIZE(sz), \ + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, \ + .pd_cache = PTE_NOCACHE \ + } +#define DEVMAP_ENTRY_END { 0 } + +static const struct pmap_devmap * +tegra_platform_devmap(void) +{ + static const struct pmap_devmap devmap[] = { + DEVMAP_ENTRY(TEGRA_HOST1X_VBASE, + TEGRA_HOST1X_BASE, + TEGRA_HOST1X_SIZE), + DEVMAP_ENTRY(TEGRA_PPSB_VBASE, + TEGRA_PPSB_BASE, + TEGRA_PPSB_SIZE), + DEVMAP_ENTRY(TEGRA_APB_VBASE, + TEGRA_APB_BASE, + TEGRA_APB_SIZE), + DEVMAP_ENTRY(TEGRA_AHB_A2_VBASE, + TEGRA_AHB_A2_BASE, + TEGRA_AHB_A2_SIZE), + DEVMAP_ENTRY_END + }; + + return devmap; +} + +static void +tegra_platform_bootstrap(void) +{ + tegra_bootstrap(); +} + +static void +tegra_platform_early_putchar(char c) +{ +#ifdef CONSADDR +#define CONSADDR_VA (CONSADDR - TEGRA_APB_BASE + TEGRA_APB_VBASE) + volatile uint32_t *uartaddr = (volatile uint32_t *)CONSADDR_VA; + + while ((uartaddr[com_lsr] & LSR_TXRDY) == 0) + ; + + uartaddr[com_data] = c; +#endif +} + +static void +tegra_platform_device_register(device_t self, void *aux) +{ + prop_dictionary_t dict = device_properties(self); + + if (device_is_a(self, "tegrafb") && + match_bootconf_option(boot_args, "console", "fb")) { + prop_dictionary_set_bool(dict, "is_console", true); +#if NUKBD > 0 + ukbd_cnattach(); +#endif + } + + if (device_is_a(self, "tegradrm")) { + const char *video = get_bootconf_string(boot_args, "video"); + if (video) + prop_dictionary_set_cstring(dict, "HDMI-A-1", video); + if (match_bootconf_option(boot_args, "hdmi.forcemode", "dvi")) + prop_dictionary_set_bool(dict, "force-dvi", true); + } + + if (device_is_a(self, "tegracec")) + prop_dictionary_set_cstring(dict, "hdmi-device", "tegradrm0"); + + if (device_is_a(self, "nouveau")) { + const char *config = get_bootconf_string(boot_args, + "nouveau.config"); + if (config) + prop_dictionary_set_cstring(dict, "config", config); + const char *debug = get_bootconf_string(boot_args, + "nouveau.debug"); + if (debug) + prop_dictionary_set_cstring(dict, "debug", debug); + } + + if (device_is_a(self, "tegrapcie")) { + const char * const jetsontk1_compat[] = { + "nvidia,jetson-tk1", NULL + }; + const int phandle = OF_peer(0); + if (of_match_compatible(phandle, jetsontk1_compat)) { + /* rfkill GPIO at GPIO X7 */ + struct tegra_gpio_pin *pin = + tegra_gpio_acquire("X7", GPIO_PIN_OUTPUT); + if (pin) + tegra_gpio_write(pin, 1); + } + } +} + +static void +tegra_platform_reset(void) +{ + tegra_pmc_reset(); +} + +static void +tegra_platform_consinit(void) +{ + static bool consinit_called = false; + + if (consinit_called) + return; + consinit_called = true; + +#if NCOM > 0 + bus_addr_t addr; + int speed; + +#ifdef CONSADDR + addr = CONSADDR; +#else + fdtbus_get_reg(fdtbus_get_stdout_phandle(), 0, &addr, NULL); +#endif + +#ifdef CONSPEED + speed = CONSPEED; +#else + speed = fdtbus_get_stdout_speed(); + if (speed < 0) + speed = 115200; /* default */ +#endif + + const bus_space_tag_t bst = &armv7_generic_a4x_bs_tag; + const u_int freq = 408000000; /* 408MHz PLLP_OUT0 */ + if (comcnattach(bst, addr, speed, freq, COM_TYPE_TEGRA, CONMODE)) + panic("Serial console cannot be initialized."); +#endif +} + +static const struct armv7_platform tegra_platform = { + .devmap = tegra_platform_devmap, + .bootstrap = tegra_platform_bootstrap, + .early_putchar = tegra_platform_early_putchar, + .device_register = tegra_platform_device_register, + .reset = tegra_platform_reset, + .consinit = tegra_platform_consinit, +}; + +ARMV7_PLATFORM(tegra124, "nvidia,tegra124", &tegra_platform); +ARMV7_PLATFORM(tegra210, "nvidia,tegra210", &tegra_platform);