diff options
57 files changed, 1242 insertions, 723 deletions
diff --git a/arch/arm/dts/tegra124-apalis.dts b/arch/arm/dts/tegra124-apalis.dts index fe08d3ea73..a962c0a2f0 100644 --- a/arch/arm/dts/tegra124-apalis.dts +++ b/arch/arm/dts/tegra124-apalis.dts @@ -77,7 +77,7 @@ reg = <0x0 0x80000000 0x0 0x80000000>; }; - pcie-controller@01003000 { + pcie@1003000 { status = "okay"; avddio-pex-supply = <&vdd_1v05>; avdd-pex-pll-supply = <&vdd_1v05>; diff --git a/arch/arm/dts/tegra124-cei-tk1-som.dts b/arch/arm/dts/tegra124-cei-tk1-som.dts index b1dd4181ac..e5b41f3183 100644 --- a/arch/arm/dts/tegra124-cei-tk1-som.dts +++ b/arch/arm/dts/tegra124-cei-tk1-som.dts @@ -29,7 +29,7 @@ reg = <0x80000000 0x80000000>; }; - pcie-controller@01003000 { + pcie@1003000 { status = "okay"; avddio-pex-supply = <&vdd_1v05_run>; diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index d6420436cd..59e080a8af 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -29,7 +29,7 @@ reg = <0x80000000 0x80000000>; }; - pcie-controller@01003000 { + pcie@1003000 { status = "okay"; avddio-pex-supply = <&vdd_1v05_run>; diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi index 83d6348047..f473ba28e4 100644 --- a/arch/arm/dts/tegra124.dtsi +++ b/arch/arm/dts/tegra124.dtsi @@ -14,7 +14,7 @@ interrupt-parent = <&lic>; - pcie-controller@01003000 { + pcie@1003000 { compatible = "nvidia,tegra124-pcie"; device_type = "pci"; reg = <0x01003000 0x00000800 /* PADS registers */ diff --git a/arch/arm/dts/tegra186-p2771-0000-000.dts b/arch/arm/dts/tegra186-p2771-0000-000.dts index d97c6fd3d0..84e850d6fc 100644 --- a/arch/arm/dts/tegra186-p2771-0000-000.dts +++ b/arch/arm/dts/tegra186-p2771-0000-000.dts @@ -11,7 +11,7 @@ power-gpios = <&gpio_main TEGRA_MAIN_GPIO(P, 5) GPIO_ACTIVE_HIGH>; }; - pcie-controller@10003000 { + pcie@10003000 { status = "okay"; pci@1,0 { diff --git a/arch/arm/dts/tegra186-p2771-0000-500.dts b/arch/arm/dts/tegra186-p2771-0000-500.dts index 393a8b246a..1ac8ab431e 100644 --- a/arch/arm/dts/tegra186-p2771-0000-500.dts +++ b/arch/arm/dts/tegra186-p2771-0000-500.dts @@ -11,7 +11,7 @@ power-gpios = <&gpio_main TEGRA_MAIN_GPIO(P, 6) GPIO_ACTIVE_HIGH>; }; - pcie-controller@10003000 { + pcie@10003000 { status = "okay"; pci@1,0 { diff --git a/arch/arm/dts/tegra186-p2771-0000.dtsi b/arch/arm/dts/tegra186-p2771-0000.dtsi index a1319dc493..7cda0b41f7 100644 --- a/arch/arm/dts/tegra186-p2771-0000.dtsi +++ b/arch/arm/dts/tegra186-p2771-0000.dtsi @@ -9,6 +9,7 @@ }; aliases { + ethernet = "/ethernet@2490000"; mmc0 = "/sdhci@3460000"; mmc1 = "/sdhci@3400000"; i2c0 = "/bpmp/i2c"; @@ -28,6 +29,7 @@ ethernet@2490000 { status = "okay"; phy-reset-gpios = <&gpio_main TEGRA_MAIN_GPIO(M, 4) GPIO_ACTIVE_LOW>; + local-mac-address = [ 00 00 00 00 00 00 ]; }; i2c@3160000 { diff --git a/arch/arm/dts/tegra186.dtsi b/arch/arm/dts/tegra186.dtsi index dd9e3b869d..0a9db9825b 100644 --- a/arch/arm/dts/tegra186.dtsi +++ b/arch/arm/dts/tegra186.dtsi @@ -217,7 +217,7 @@ #interrupt-cells = <2>; }; - pcie-controller@10003000 { + pcie@10003000 { compatible = "nvidia,tegra186-pcie"; device_type = "pci"; reg = <0x0 0x10003000 0x0 0x00000800 /* PADS registers */ diff --git a/arch/arm/dts/tegra20-harmony.dts b/arch/arm/dts/tegra20-harmony.dts index 0c907054db..7fe7d52096 100644 --- a/arch/arm/dts/tegra20-harmony.dts +++ b/arch/arm/dts/tegra20-harmony.dts @@ -599,7 +599,7 @@ nvidia,sys-clock-req-active-high; }; - pcie-controller@80003000 { + pcie@80003000 { status = "okay"; avdd-pex-supply = <&pci_vdd_reg>; diff --git a/arch/arm/dts/tegra20-trimslice.dts b/arch/arm/dts/tegra20-trimslice.dts index 31f509ab12..e19001ee2b 100644 --- a/arch/arm/dts/tegra20-trimslice.dts +++ b/arch/arm/dts/tegra20-trimslice.dts @@ -30,7 +30,7 @@ spi-max-frequency = <25000000>; }; - pcie-controller@80003000 { + pcie@80003000 { status = "okay"; avdd-pex-supply = <&pci_vdd_reg>; diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index e21ee258b3..275b3432bd 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -580,7 +580,7 @@ reset-names = "fuse"; }; - pcie-controller@80003000 { + pcie@80003000 { compatible = "nvidia,tegra20-pcie"; device_type = "pci"; reg = <0x80003000 0x00000800 /* PADS registers */ diff --git a/arch/arm/dts/tegra210-p2371-2180.dts b/arch/arm/dts/tegra210-p2371-2180.dts index da4349bd03..c2f497c524 100644 --- a/arch/arm/dts/tegra210-p2371-2180.dts +++ b/arch/arm/dts/tegra210-p2371-2180.dts @@ -21,7 +21,7 @@ reg = <0x0 0x80000000 0x0 0xc0000000>; }; - pcie-controller@01003000 { + pcie@1003000 { status = "okay"; pci@1,0 { diff --git a/arch/arm/dts/tegra210.dtsi b/arch/arm/dts/tegra210.dtsi index 229fed0452..3ec54b11c4 100644 --- a/arch/arm/dts/tegra210.dtsi +++ b/arch/arm/dts/tegra210.dtsi @@ -11,7 +11,7 @@ #address-cells = <2>; #size-cells = <2>; - pcie-controller@01003000 { + pcie@1003000 { compatible = "nvidia,tegra210-pcie"; device_type = "pci"; reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */ diff --git a/arch/arm/dts/tegra30-apalis.dts b/arch/arm/dts/tegra30-apalis.dts index 1a9ce2720a..77502dfdb4 100644 --- a/arch/arm/dts/tegra30-apalis.dts +++ b/arch/arm/dts/tegra30-apalis.dts @@ -32,7 +32,7 @@ reg = <0x80000000 0x40000000>; }; - pcie-controller@00003000 { + pcie@3000 { status = "okay"; avdd-pexa-supply = <&vdd2_reg>; vdd-pexa-supply = <&vdd2_reg>; diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts index f5fbbe849e..9bb097b081 100644 --- a/arch/arm/dts/tegra30-beaver.dts +++ b/arch/arm/dts/tegra30-beaver.dts @@ -28,7 +28,7 @@ reg = <0x80000000 0x7ff00000>; }; - pcie-controller@00003000 { + pcie@3000 { status = "okay"; avdd-pexa-supply = <&ldo1_reg>; diff --git a/arch/arm/dts/tegra30-cardhu.dts b/arch/arm/dts/tegra30-cardhu.dts index 5b9798c5a8..7534861e40 100644 --- a/arch/arm/dts/tegra30-cardhu.dts +++ b/arch/arm/dts/tegra30-cardhu.dts @@ -27,7 +27,7 @@ reg = <0x80000000 0x40000000>; }; - pcie-controller@00003000 { + pcie@3000 { status = "okay"; /* AVDD_PEXA and VDD_PEXA inputs are grounded on Cardhu. */ diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi index 5030065cbd..f198bc0edb 100644 --- a/arch/arm/dts/tegra30.dtsi +++ b/arch/arm/dts/tegra30.dtsi @@ -10,7 +10,7 @@ compatible = "nvidia,tegra30"; interrupt-parent = <&lic>; - pcie-controller@00003000 { + pcie@3000 { compatible = "nvidia,tegra30-pcie"; device_type = "pci"; reg = <0x00003000 0x00000800 /* PADS registers */ diff --git a/arch/arm/include/asm/arch-tegra/cboot.h b/arch/arm/include/asm/arch-tegra/cboot.h new file mode 100644 index 0000000000..021c246175 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/cboot.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 NVIDIA Corporation. All rights reserved. + */ + +#ifndef _TEGRA_CBOOT_H_ +#define _TEGRA_CBOOT_H_ + +#ifdef CONFIG_ARM64 +extern unsigned long cboot_boot_x0; + +void cboot_save_boot_params(unsigned long x0, unsigned long x1, + unsigned long x2, unsigned long x3); +int cboot_dram_init(void); +int cboot_dram_init_banksize(void); +ulong cboot_get_usable_ram_top(ulong total_size); +int cboot_get_ethaddr(const void *fdt, uint8_t mac[ETH_ALEN]); +#else +static inline void cboot_save_boot_params(unsigned long x0, unsigned long x1, + unsigned long x2, unsigned long x3) +{ +} + +static inline int cboot_dram_init(void) +{ + return -ENOSYS; +} + +static inline int cboot_dram_init_banksize(void) +{ + return -ENOSYS; +} + +static inline ulong cboot_get_usable_ram_top(ulong total_size) +{ + return 0; +} + +static inline int cboot_get_ethaddr(const void *fdt, uint8_t mac[ETH_ALEN]) +{ + return -ENOSYS; +} +#endif + +#endif diff --git a/arch/arm/include/asm/arch-tegra/pmc.h b/arch/arm/include/asm/arch-tegra/pmc.h index 34bbe75d5f..1524bf2911 100644 --- a/arch/arm/include/asm/arch-tegra/pmc.h +++ b/arch/arm/include/asm/arch-tegra/pmc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * (C) Copyright 2010-2015 + * (C) Copyright 2010-2019 * NVIDIA Corporation <www.nvidia.com> */ @@ -388,4 +388,22 @@ struct pmc_ctlr { /* APBDEV_PMC_CNTRL2_0 0x440 */ #define HOLD_CKE_LOW_EN (1 << 12) +/* PMC read/write functions */ +u32 tegra_pmc_readl(unsigned long offset); +void tegra_pmc_writel(u32 value, unsigned long offset); + +#define PMC_CNTRL 0x0 +#define PMC_CNTRL_MAIN_RST BIT(4) + +#if IS_ENABLED(CONFIG_TEGRA186) +# define PMC_SCRATCH0 0x32000 +#else +# define PMC_SCRATCH0 0x00050 +#endif + +/* for secure PMC */ +#define TEGRA_SMC_PMC 0xc2fffe00 +#define TEGRA_SMC_PMC_READ 0xaa +#define TEGRA_SMC_PMC_WRITE 0xbb + #endif /* PMC_H */ diff --git a/arch/arm/include/asm/arch-tegra20/pmu.h b/arch/arm/include/asm/arch-tegra/pmu.h index 18766dfed2..e850875d31 100644 --- a/arch/arm/include/asm/arch-tegra20/pmu.h +++ b/arch/arm/include/asm/arch-tegra/pmu.h @@ -4,10 +4,10 @@ * NVIDIA Corporation <www.nvidia.com> */ -#ifndef _ARCH_PMU_H_ -#define _ARCH_PMU_H_ +#ifndef _TEGRA_PMU_H_ +#define _TEGRA_PMU_H_ /* Set core and CPU voltages to nominal levels */ int pmu_set_nominal(void); -#endif /* _ARCH_PMU_H_ */ +#endif /* _TEGRA_PMU_H_ */ diff --git a/arch/arm/include/asm/arch-tegra/tegra.h b/arch/arm/include/asm/arch-tegra/tegra.h index 7ae0129e2d..7a4e0972fb 100644 --- a/arch/arm/include/asm/arch-tegra/tegra.h +++ b/arch/arm/include/asm/arch-tegra/tegra.h @@ -30,7 +30,13 @@ #define NV_PA_SLINK5_BASE (NV_PA_APB_MISC_BASE + 0xDC00) #define NV_PA_SLINK6_BASE (NV_PA_APB_MISC_BASE + 0xDE00) #define TEGRA_DVC_BASE (NV_PA_APB_MISC_BASE + 0xD000) +#if defined(CONFIG_TEGRA20) || defined(CONFIG_TEGRA30) || \ + defined(CONFIG_TEGRA114) || defined(CONFIG_TEGRA124) || \ + defined(CONFIG_TEGRA132) || defined(CONFIG_TEGRA210) #define NV_PA_PMC_BASE (NV_PA_APB_MISC_BASE + 0xE400) +#else +#define NV_PA_PMC_BASE 0xc360000 +#endif #define NV_PA_EMC_BASE (NV_PA_APB_MISC_BASE + 0xF400) #define NV_PA_FUSE_BASE (NV_PA_APB_MISC_BASE + 0xF800) #if defined(CONFIG_TEGRA20) || defined(CONFIG_TEGRA30) || \ diff --git a/arch/arm/include/asm/arch-tegra114/pmu.h b/arch/arm/include/asm/arch-tegra114/pmu.h deleted file mode 100644 index 1e571ee7b3..0000000000 --- a/arch/arm/include/asm/arch-tegra114/pmu.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. - */ - -#ifndef _TEGRA114_PMU_H_ -#define _TEGRA114_PMU_H_ - -/* Set core and CPU voltages to nominal levels */ -int pmu_set_nominal(void); - -#endif /* _TEGRA114_PMU_H_ */ diff --git a/arch/arm/include/asm/arch-tegra124/pmu.h b/arch/arm/include/asm/arch-tegra124/pmu.h deleted file mode 100644 index c38393edef..0000000000 --- a/arch/arm/include/asm/arch-tegra124/pmu.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2010-2013 - * NVIDIA Corporation <www.nvidia.com> - */ - -#ifndef _TEGRA124_PMU_H_ -#define _TEGRA124_PMU_H_ - -/* Set core and CPU voltages to nominal levels */ -int pmu_set_nominal(void); - -#endif /* _TEGRA124_PMU_H_ */ diff --git a/arch/arm/include/asm/arch-tegra210/pmu.h b/arch/arm/include/asm/arch-tegra210/pmu.h deleted file mode 100644 index 6ea36aa418..0000000000 --- a/arch/arm/include/asm/arch-tegra210/pmu.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2010-2015 - * NVIDIA Corporation <www.nvidia.com> - */ - -#ifndef _TEGRA210_PMU_H_ -#define _TEGRA210_PMU_H_ - -/* Set core and CPU voltages to nominal levels */ -int pmu_set_nominal(void); - -#endif /* _TEGRA210_PMU_H_ */ diff --git a/arch/arm/include/asm/arch-tegra30/pmu.h b/arch/arm/include/asm/arch-tegra30/pmu.h deleted file mode 100644 index a823f0fbfc..0000000000 --- a/arch/arm/include/asm/arch-tegra30/pmu.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. - */ - -#ifndef _TEGRA30_PMU_H_ -#define _TEGRA30_PMU_H_ - -/* Set core and CPU voltages to nominal levels */ -int pmu_set_nominal(void); - -#endif /* _TEGRA30_PMU_H_ */ diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 86b1cd11f7..97e22ead59 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -12,6 +12,12 @@ config SPL_LIBGENERIC_SUPPORT config SPL_SERIAL_SUPPORT default y +config TEGRA_CLKRST + bool + +config TEGRA_GP_PADCTRL + bool + config TEGRA_IVC bool "Tegra IVC protocol" help @@ -20,6 +26,19 @@ config TEGRA_IVC U-Boot, it is typically used for communication between the main CPU and various auxiliary processors. +config TEGRA_MC + bool + +config TEGRA_PINCTRL + bool + +config TEGRA_PMC + bool + +config TEGRA_PMC_SECURE + bool + depends on TEGRA_PMC + config TEGRA_COMMON bool "Tegra common options" select BINMAN @@ -55,14 +74,20 @@ config TEGRA_ARMV7_COMMON select SPL select SPL_BOARD_INIT if SPL select SUPPORT_SPL + select TEGRA_CLKRST select TEGRA_COMMON select TEGRA_GPIO + select TEGRA_GP_PADCTRL + select TEGRA_MC select TEGRA_NO_BPMP + select TEGRA_PINCTRL + select TEGRA_PMC config TEGRA_ARMV8_COMMON bool "Tegra 64-bit common options" select ARM64 select LINUX_KERNEL_IMAGE_HEADER + select POSITION_INDEPENDENT select TEGRA_COMMON if TEGRA_ARMV8_COMMON @@ -100,8 +125,14 @@ config TEGRA124 config TEGRA210 bool "Tegra210 family" select TEGRA_ARMV8_COMMON + select TEGRA_CLKRST select TEGRA_GPIO + select TEGRA_GP_PADCTRL + select TEGRA_MC select TEGRA_NO_BPMP + select TEGRA_PINCTRL + select TEGRA_PMC + select TEGRA_PMC_SECURE config TEGRA186 bool "Tegra186 family" @@ -118,6 +149,7 @@ endchoice config TEGRA_DISCONNECT_UDC_ON_BOOT bool "Disconnect USB device mode controller on boot" + depends on CI_UDC default y help When loading U-Boot into RAM over USB protocols using tools such as diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index d4b4666fb1..7165d70a60 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -1,11 +1,10 @@ # SPDX-License-Identifier: GPL-2.0+ # -# (C) Copyright 2010-2015 Nvidia Corporation. +# (C) Copyright 2010-2019 Nvidia Corporation. # # (C) Copyright 2000-2008 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifndef CONFIG_TEGRA186 ifdef CONFIG_SPL_BUILD obj-y += spl.o obj-y += cpu.o @@ -13,25 +12,24 @@ else obj-$(CONFIG_CMD_ENTERRCM) += cmd_enterrcm.o endif -obj-y += ap.o +obj-$(CONFIG_TEGRA_GP_PADCTRL) += ap.o obj-y += board.o board2.o obj-y += cache.o -obj-y += clock.o -obj-y += pinmux-common.o -obj-y += powergate.o +obj-$(CONFIG_TEGRA_CLKRST) += clock.o +obj-$(CONFIG_TEGRA_PINCTRL) += pinmux-common.o +obj-$(CONFIG_TEGRA_PMC) += powergate.o obj-y += xusb-padctl-dummy.o -endif -obj-$(CONFIG_ARM64) += arm64-mmu.o +obj-$(CONFIG_ARM64) += arm64-mmu.o cboot.o obj-y += dt-setup.o obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o obj-$(CONFIG_TEGRA_GPU) += gpu.o obj-$(CONFIG_TEGRA_IVC) += ivc.o -obj-y += lowlevel_init.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMV7_PSCI) += psci.o endif obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o +obj-y += pmc.o obj-$(CONFIG_TEGRA20) += tegra20/ obj-$(CONFIG_TEGRA30) += tegra30/ diff --git a/arch/arm/mach-tegra/board.c b/arch/arm/mach-tegra/board.c index 4e159075d3..abcae15ea3 100644 --- a/arch/arm/mach-tegra/board.c +++ b/arch/arm/mach-tegra/board.c @@ -9,12 +9,19 @@ #include <ns16550.h> #include <spl.h> #include <asm/io.h> +#if IS_ENABLED(CONFIG_TEGRA_CLKRST) #include <asm/arch/clock.h> +#endif +#if IS_ENABLED(CONFIG_TEGRA_PINCTRL) #include <asm/arch/funcmux.h> +#endif +#if IS_ENABLED(CONFIG_TEGRA_MC) #include <asm/arch/mc.h> +#endif #include <asm/arch/tegra.h> #include <asm/arch-tegra/ap.h> #include <asm/arch-tegra/board.h> +#include <asm/arch-tegra/cboot.h> #include <asm/arch-tegra/pmc.h> #include <asm/arch-tegra/sys_proto.h> #include <asm/arch-tegra/warmboot.h> @@ -36,9 +43,25 @@ enum { static bool from_spl __attribute__ ((section(".data"))); #ifndef CONFIG_SPL_BUILD -void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) +void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2, + unsigned long r3) { from_spl = r0 != UBOOT_NOT_LOADED_FROM_SPL; + + /* + * The logic for this is somewhat indirect. The purpose of the marker + * (UBOOT_NOT_LOADED_FROM_SPL) is in fact used to determine if U-Boot + * was loaded from a read-only instance of itself, which is something + * that can happen in secure boot setups. So basically the presence + * of the marker is an indication that U-Boot was loaded by one such + * special variant of U-Boot. Conversely, the absence of the marker + * indicates that this instance of U-Boot was loaded by something + * other than a special U-Boot. This could be SPL, but it could just + * as well be one of any number of other first stage bootloaders. + */ + if (from_spl) + cboot_save_boot_params(r0, r1, r2, r3); + save_boot_params_ret(); } #endif @@ -66,6 +89,7 @@ bool tegra_cpu_is_non_secure(void) } #endif +#if IS_ENABLED(CONFIG_TEGRA_MC) /* Read the RAM size directly from the memory controller */ static phys_size_t query_sdram_size(void) { @@ -115,14 +139,26 @@ static phys_size_t query_sdram_size(void) return size_bytes; } +#endif int dram_init(void) { + int err; + + /* try to initialize DRAM from cboot DTB first */ + err = cboot_dram_init(); + if (err == 0) + return 0; + +#if IS_ENABLED(CONFIG_TEGRA_MC) /* We do not initialise DRAM here. We just query the size */ gd->ram_size = query_sdram_size(); +#endif + return 0; } +#if IS_ENABLED(CONFIG_TEGRA_PINCTRL) static int uart_configs[] = { #if defined(CONFIG_TEGRA20) #if defined(CONFIG_TEGRA_UARTA_UAA_UAB) @@ -190,9 +226,11 @@ static void setup_uarts(int uart_ids) } } } +#endif void board_init_uart_f(void) { +#if IS_ENABLED(CONFIG_TEGRA_PINCTRL) int uart_ids = 0; /* bit mask of which UART ids to enable */ #ifdef CONFIG_TEGRA_ENABLE_UARTA @@ -211,6 +249,7 @@ void board_init_uart_f(void) uart_ids |= UARTE; #endif setup_uarts(uart_ids); +#endif } #if !CONFIG_IS_ENABLED(OF_CONTROL) diff --git a/arch/arm/mach-tegra/board186.c b/arch/arm/mach-tegra/board186.c deleted file mode 100644 index 80b55707e9..0000000000 --- a/arch/arm/mach-tegra/board186.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2016, NVIDIA CORPORATION. - */ - -#include <common.h> -#include <asm/arch/tegra.h> - -int board_early_init_f(void) -{ - return 0; -} - -__weak int tegra_board_init(void) -{ - return 0; -} - -int board_init(void) -{ - return tegra_board_init(); -} - -__weak int tegra_soc_board_init_late(void) -{ - return 0; -} - -int board_late_init(void) -{ - return tegra_soc_board_init_late(); -} diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index 12257a42b5..bbc487aa3b 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -13,18 +13,23 @@ #include <asm/io.h> #include <asm/arch-tegra/ap.h> #include <asm/arch-tegra/board.h> +#include <asm/arch-tegra/cboot.h> #include <asm/arch-tegra/clk_rst.h> #include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/pmu.h> #include <asm/arch-tegra/sys_proto.h> #include <asm/arch-tegra/uart.h> #include <asm/arch-tegra/warmboot.h> #include <asm/arch-tegra/gpu.h> #include <asm/arch-tegra/usb.h> #include <asm/arch-tegra/xusb-padctl.h> +#if IS_ENABLED(CONFIG_TEGRA_CLKRST) #include <asm/arch/clock.h> +#endif +#if IS_ENABLED(CONFIG_TEGRA_PINCTRL) #include <asm/arch/funcmux.h> #include <asm/arch/pinmux.h> -#include <asm/arch/pmu.h> +#endif #include <asm/arch/tegra.h> #ifdef CONFIG_TEGRA_CLOCK_SCALING #include <asm/arch/emc.h> @@ -47,6 +52,7 @@ __weak void pin_mux_mmc(void) {} __weak void gpio_early_init_uart(void) {} __weak void pin_mux_display(void) {} __weak void start_cpu_fan(void) {} +__weak void cboot_late_init(void) {} #if defined(CONFIG_TEGRA_NAND) __weak void pin_mux_nand(void) @@ -109,8 +115,10 @@ int board_init(void) __maybe_unused int board_id; /* Do clocks and UART first so that printf() works */ +#if IS_ENABLED(CONFIG_TEGRA_CLKRST) clock_init(); clock_verify(); +#endif tegra_gpu_config(); @@ -181,8 +189,10 @@ void gpio_early_init(void) __attribute__((weak, alias("__gpio_early_init"))); int board_early_init_f(void) { +#if IS_ENABLED(CONFIG_TEGRA_CLKRST) if (!clock_early_init_done()) clock_early_init(); +#endif #if defined(CONFIG_TEGRA_DISCONNECT_UDC_ON_BOOT) #define USBCMD_FS2 (1 << 15) @@ -193,10 +203,12 @@ int board_early_init_f(void) #endif /* Do any special system timer/TSC setup */ -#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) +#if IS_ENABLED(CONFIG_TEGRA_CLKRST) +# if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) if (!tegra_cpu_is_non_secure()) -#endif +# endif arch_timer_init(); +#endif pinmux_init(); board_init_uart_f(); @@ -233,6 +245,7 @@ int board_late_init(void) } #endif start_cpu_fan(); + cboot_late_init(); return 0; } @@ -327,6 +340,15 @@ static ulong usable_ram_size_below_4g(void) */ int dram_init_banksize(void) { + int err; + + /* try to compute DRAM bank size based on cboot DTB first */ + err = cboot_dram_init_banksize(); + if (err == 0) + return err; + + /* fall back to default DRAM bank size computation */ + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; gd->bd->bi_dram[0].size = usable_ram_size_below_4g(); @@ -360,5 +382,14 @@ int dram_init_banksize(void) */ ulong board_get_usable_ram_top(ulong total_size) { + ulong ram_top; + + /* try to get top of usable RAM based on cboot DTB first */ + ram_top = cboot_get_usable_ram_top(total_size); + if (ram_top > 0) + return ram_top; + + /* fall back to default usable RAM computation */ + return CONFIG_SYS_SDRAM_BASE + usable_ram_size_below_4g(); } diff --git a/arch/arm/mach-tegra/cache.c b/arch/arm/mach-tegra/cache.c index be414e4e4a..d7063490e2 100644 --- a/arch/arm/mach-tegra/cache.c +++ b/arch/arm/mach-tegra/cache.c @@ -8,7 +8,9 @@ #include <common.h> #include <asm/io.h> #include <asm/arch-tegra/ap.h> +#if IS_ENABLED(CONFIG_TEGRA_GP_PADCTRL) #include <asm/arch/gp_padctrl.h> +#endif #ifndef CONFIG_ARM64 void config_cache(void) diff --git a/arch/arm/mach-tegra/cboot.c b/arch/arm/mach-tegra/cboot.c new file mode 100644 index 0000000000..a829ef794f --- /dev/null +++ b/arch/arm/mach-tegra/cboot.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2016-2018, NVIDIA CORPORATION. + */ + +#include <common.h> +#include <environment.h> +#include <fdt_support.h> +#include <fdtdec.h> +#include <stdlib.h> +#include <string.h> + +#include <linux/ctype.h> +#include <linux/sizes.h> + +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/cboot.h> +#include <asm/armv8/mmu.h> + +/* + * Size of a region that's large enough to hold the relocated U-Boot and all + * other allocations made around it (stack, heap, page tables, etc.) + * In practice, running "bdinfo" at the shell prompt, the stack reaches about + * 5MB from the address selected for ram_top as of the time of writing, + * so a 16MB region should be plenty. + */ +#define MIN_USABLE_RAM_SIZE SZ_16M +/* + * The amount of space we expect to require for stack usage. Used to validate + * that all reservations fit into the region selected for the relocation target + */ +#define MIN_USABLE_STACK_SIZE SZ_1M + +DECLARE_GLOBAL_DATA_PTR; + +extern struct mm_region tegra_mem_map[]; + +/* + * These variables are written to before relocation, and hence cannot be + * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. + * The section attribute forces this into .data and avoids this issue. This + * also has the nice side-effect of the content being valid after relocation. + */ + +/* The number of valid entries in ram_banks[] */ +static int ram_bank_count __attribute__((section(".data"))); + +/* + * The usable top-of-RAM for U-Boot. This is both: + * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. + * b) At the end of a region that has enough space to hold the relocated U-Boot + * and all other allocations made around it (stack, heap, page tables, etc.) + */ +static u64 ram_top __attribute__((section(".data"))); +/* The base address of the region of RAM that ends at ram_top */ +static u64 region_base __attribute__((section(".data"))); + +/* + * Explicitly put this in the .data section because it is written before the + * .bss section is zeroed out but it needs to persist. + */ +unsigned long cboot_boot_x0 __attribute__((section(".data"))); + +void cboot_save_boot_params(unsigned long x0, unsigned long x1, + unsigned long x2, unsigned long x3) +{ + cboot_boot_x0 = x0; +} + +int cboot_dram_init(void) +{ + unsigned int na, ns; + const void *cboot_blob = (void *)cboot_boot_x0; + int node, len, i; + const u32 *prop; + + if (!cboot_blob) + return -EINVAL; + + na = fdtdec_get_uint(cboot_blob, 0, "#address-cells", 2); + ns = fdtdec_get_uint(cboot_blob, 0, "#size-cells", 2); + + node = fdt_path_offset(cboot_blob, "/memory"); + if (node < 0) { + pr_err("Can't find /memory node in cboot DTB"); + hang(); + } + prop = fdt_getprop(cboot_blob, node, "reg", &len); + if (!prop) { + pr_err("Can't find /memory/reg property in cboot DTB"); + hang(); + } + + /* Calculate the true # of base/size pairs to read */ + len /= 4; /* Convert bytes to number of cells */ + len /= (na + ns); /* Convert cells to number of banks */ + if (len > CONFIG_NR_DRAM_BANKS) + len = CONFIG_NR_DRAM_BANKS; + + /* Parse the /memory node, and save useful entries */ + gd->ram_size = 0; + ram_bank_count = 0; + for (i = 0; i < len; i++) { + u64 bank_start, bank_end, bank_size, usable_bank_size; + + /* Extract raw memory region data from DTB */ + bank_start = fdt_read_number(prop, na); + prop += na; + bank_size = fdt_read_number(prop, ns); + prop += ns; + gd->ram_size += bank_size; + bank_end = bank_start + bank_size; + debug("Bank %d: %llx..%llx (+%llx)\n", i, + bank_start, bank_end, bank_size); + + /* + * Align the bank to MMU section size. This is not strictly + * necessary, since the translation table construction code + * handles page granularity without issue. However, aligning + * the MMU entries reduces the size and number of levels in the + * page table, so is worth it. + */ + bank_start = ROUND(bank_start, SZ_2M); + bank_end = bank_end & ~(SZ_2M - 1); + bank_size = bank_end - bank_start; + debug(" aligned: %llx..%llx (+%llx)\n", + bank_start, bank_end, bank_size); + if (bank_end <= bank_start) + continue; + + /* Record data used to create MMU translation tables */ + ram_bank_count++; + /* Index below is deliberately 1-based to skip MMIO entry */ + tegra_mem_map[ram_bank_count].virt = bank_start; + tegra_mem_map[ram_bank_count].phys = bank_start; + tegra_mem_map[ram_bank_count].size = bank_size; + tegra_mem_map[ram_bank_count].attrs = + PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; + + /* Determine best bank to relocate U-Boot into */ + if (bank_end > SZ_4G) + bank_end = SZ_4G; + debug(" end %llx (usable)\n", bank_end); + usable_bank_size = bank_end - bank_start; + debug(" size %llx (usable)\n", usable_bank_size); + if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && + (bank_end > ram_top)) { + ram_top = bank_end; + region_base = bank_start; + debug("ram top now %llx\n", ram_top); + } + } + + /* Ensure memory map contains the desired sentinel entry */ + tegra_mem_map[ram_bank_count + 1].virt = 0; + tegra_mem_map[ram_bank_count + 1].phys = 0; + tegra_mem_map[ram_bank_count + 1].size = 0; + tegra_mem_map[ram_bank_count + 1].attrs = 0; + + /* Error out if a relocation target couldn't be found */ + if (!ram_top) { + pr_err("Can't find a usable RAM top"); + hang(); + } + + return 0; +} + +int cboot_dram_init_banksize(void) +{ + int i; + + if (ram_bank_count == 0) + return -EINVAL; + + if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { + pr_err("Reservations exceed chosen region size"); + hang(); + } + + for (i = 0; i < ram_bank_count; i++) { + gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; + gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; + } + +#ifdef CONFIG_PCI + gd->pci_ram_top = ram_top; +#endif + + return 0; +} + +ulong cboot_get_usable_ram_top(ulong total_size) +{ + return ram_top; +} + +/* + * The following few functions run late during the boot process and dynamically + * calculate the load address of various binaries. To keep track of multiple + * allocations, some writable list of RAM banks must be used. tegra_mem_map[] + * is used for this purpose to avoid making yet another copy of the list of RAM + * banks. This is safe because tegra_mem_map[] is only used once during very + * early boot to create U-Boot's page tables, long before this code runs. If + * this assumption becomes invalid later, we can just fix the code to copy the + * list of RAM banks into some private data structure before running. + */ + +static char *gen_varname(const char *var, const char *ext) +{ + size_t len_var = strlen(var); + size_t len_ext = strlen(ext); + size_t len = len_var + len_ext + 1; + char *varext = malloc(len); + + if (!varext) + return 0; + strcpy(varext, var); + strcpy(varext + len_var, ext); + return varext; +} + +static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end) +{ + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + bool keep_front = allocated_start != bank_start; + bool keep_tail = allocated_end != bank_end; + + if (keep_front && keep_tail) { + /* + * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array, + * starting at index 1 (index 0 is MMIO). So, we are at DRAM + * entry "bank" not "bank - 1" as for a typical 0-base array. + * The number of remaining DRAM entries is therefore + * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the + * current entry and shift up the remaining entries, dropping + * the last one. Thus, we must copy one fewer entry than the + * number remaining. + */ + memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank], + CONFIG_NR_DRAM_BANKS - bank - 1); + tegra_mem_map[bank].size = allocated_start - bank_start; + bank++; + tegra_mem_map[bank].virt = allocated_end; + tegra_mem_map[bank].phys = allocated_end; + tegra_mem_map[bank].size = bank_end - allocated_end; + } else if (keep_front) { + tegra_mem_map[bank].size = allocated_start - bank_start; + } else if (keep_tail) { + tegra_mem_map[bank].virt = allocated_end; + tegra_mem_map[bank].phys = allocated_end; + tegra_mem_map[bank].size = bank_end - allocated_end; + } else { + /* + * We could move all subsequent banks down in the array but + * that's not necessary for subsequent allocations to work, so + * we skip doing so. + */ + tegra_mem_map[bank].size = 0; + } +} + +static void reserve_ram(u64 start, u64 size) +{ + int bank; + u64 end = start + size; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + + if (end <= bank_start || start > bank_end) + continue; + mark_ram_allocated(bank, start, end); + break; + } +} + +static u64 alloc_ram(u64 size, u64 align, u64 offset) +{ + int bank; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + u64 allocated = ROUND(bank_start, align) + offset; + u64 allocated_end = allocated + size; + + if (allocated_end > bank_end) + continue; + mark_ram_allocated(bank, allocated, allocated_end); + return allocated; + } + return 0; +} + +static void set_calculated_aliases(char *aliases, u64 address) +{ + char *tmp, *alias; + int err; + + aliases = strdup(aliases); + if (!aliases) { + pr_err("strdup(aliases) failed"); + return; + } + + tmp = aliases; + while (true) { + alias = strsep(&tmp, " "); + if (!alias) + break; + debug("%s: alias: %s\n", __func__, alias); + err = env_set_hex(alias, address); + if (err) + pr_err("Could not set %s\n", alias); + } + + free(aliases); +} + +static void set_calculated_env_var(const char *var) +{ + char *var_size; + char *var_align; + char *var_offset; + char *var_aliases; + u64 size; + u64 align; + u64 offset; + char *aliases; + u64 address; + int err; + + var_size = gen_varname(var, "_size"); + if (!var_size) + return; + var_align = gen_varname(var, "_align"); + if (!var_align) + goto out_free_var_size; + var_offset = gen_varname(var, "_offset"); + if (!var_offset) + goto out_free_var_align; + var_aliases = gen_varname(var, "_aliases"); + if (!var_aliases) + goto out_free_var_offset; + + size = env_get_hex(var_size, 0); + if (!size) { + pr_err("%s not set or zero\n", var_size); + goto out_free_var_aliases; + } + align = env_get_hex(var_align, 1); + /* Handle extant variables, but with a value of 0 */ + if (!align) + align = 1; + offset = env_get_hex(var_offset, 0); + aliases = env_get(var_aliases); + + debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n", + __func__, var, size, align, offset); + if (aliases) + debug("%s: Aliases: %s\n", __func__, aliases); + + address = alloc_ram(size, align, offset); + if (!address) { + pr_err("Could not allocate %s\n", var); + goto out_free_var_aliases; + } + debug("%s: Address %llx\n", __func__, address); + + err = env_set_hex(var, address); + if (err) + pr_err("Could not set %s\n", var); + if (aliases) + set_calculated_aliases(aliases, address); + +out_free_var_aliases: + free(var_aliases); +out_free_var_offset: + free(var_offset); +out_free_var_align: + free(var_align); +out_free_var_size: + free(var_size); +} + +#ifdef DEBUG +static void dump_ram_banks(void) +{ + int bank; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + + if (!bank_size) + continue; + printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1, + bank_start, bank_end, bank_size); + } +} +#endif + +static void set_calculated_env_vars(void) +{ + char *vars, *tmp, *var; + +#ifdef DEBUG + printf("RAM banks before any calculated env. var.s:\n"); + dump_ram_banks(); +#endif + + reserve_ram(cboot_boot_x0, fdt_totalsize(cboot_boot_x0)); + +#ifdef DEBUG + printf("RAM after reserving cboot DTB:\n"); + dump_ram_banks(); +#endif + + vars = env_get("calculated_vars"); + if (!vars) { + debug("%s: No env var calculated_vars\n", __func__); + return; + } + + vars = strdup(vars); + if (!vars) { + pr_err("strdup(calculated_vars) failed"); + return; + } + + tmp = vars; + while (true) { + var = strsep(&tmp, " "); + if (!var) + break; + debug("%s: var: %s\n", __func__, var); + set_calculated_env_var(var); +#ifdef DEBUG + printf("RAM banks after allocating %s:\n", var); + dump_ram_banks(); +#endif + } + + free(vars); +} + +static int set_fdt_addr(void) +{ + int ret; + + ret = env_set_hex("fdt_addr", cboot_boot_x0); + if (ret) { + printf("Failed to set fdt_addr to point at DTB: %d\n", ret); + return ret; + } + + return 0; +} + +/* + * Attempt to use /chosen/nvidia,ether-mac in the cboot DTB to U-Boot's + * ethaddr environment variable if possible. + */ +static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN]) +{ + const char *const properties[] = { + "nvidia,ethernet-mac", + "nvidia,ether-mac", + }; + const char *prop; + unsigned int i; + int node, len; + + node = fdt_path_offset(fdt, "/chosen"); + if (node < 0) { + printf("Can't find /chosen node in cboot DTB\n"); + return node; + } + + for (i = 0; i < ARRAY_SIZE(properties); i++) { + prop = fdt_getprop(fdt, node, properties[i], &len); + if (prop) + break; + } + + if (!prop) { + printf("Can't find Ethernet MAC address in cboot DTB\n"); + return -ENOENT; + } + + eth_parse_enetaddr(prop, mac); + + if (!is_valid_ethaddr(mac)) { + printf("Invalid MAC address: %s\n", prop); + return -EINVAL; + } + + debug("Legacy MAC address: %pM\n", mac); + + return 0; +} + +int cboot_get_ethaddr(const void *fdt, uint8_t mac[ETH_ALEN]) +{ + int node, len, err = 0; + const uchar *prop; + const char *path; + + path = fdt_get_alias(fdt, "ethernet"); + if (!path) { + err = -ENOENT; + goto out; + } + + debug("ethernet alias found: %s\n", path); + + node = fdt_path_offset(fdt, path); + if (node < 0) { + err = -ENOENT; + goto out; + } + + prop = fdt_getprop(fdt, node, "local-mac-address", &len); + if (!prop) { + err = -ENOENT; + goto out; + } + + if (len != ETH_ALEN) { + err = -EINVAL; + goto out; + } + + debug("MAC address: %pM\n", prop); + memcpy(mac, prop, ETH_ALEN); + +out: + if (err < 0) + err = cboot_get_ethaddr_legacy(fdt, mac); + + return err; +} + +static char *strip(const char *ptr) +{ + const char *end; + + while (*ptr && isblank(*ptr)) + ptr++; + + /* empty string */ + if (*ptr == '\0') + return strdup(ptr); + + end = ptr; + + while (end[1]) + end++; + + while (isblank(*end)) + end--; + + return strndup(ptr, end - ptr + 1); +} + +static char *cboot_get_bootargs(const void *fdt) +{ + const char *args; + int offset, len; + + offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) + return NULL; + + args = fdt_getprop(fdt, offset, "bootargs", &len); + if (!args) + return NULL; + + return strip(args); +} + +int cboot_late_init(void) +{ + const void *fdt = (const void *)cboot_boot_x0; + uint8_t mac[ETH_ALEN]; + char *bootargs; + int err; + + set_calculated_env_vars(); + /* + * Ignore errors here; the value may not be used depending on + * extlinux.conf or boot script content. + */ + set_fdt_addr(); + + /* Ignore errors here; not all cases care about Ethernet addresses */ + err = cboot_get_ethaddr(fdt, mac); + if (!err) { + void *blob = (void *)gd->fdt_blob; + + err = fdtdec_set_ethernet_mac_address(blob, mac, sizeof(mac)); + if (err < 0) + printf("failed to set MAC address %pM: %d\n", mac, err); + } + + bootargs = cboot_get_bootargs(fdt); + if (bootargs) { + env_set("cbootargs", bootargs); + free(bootargs); + } + + return 0; +} diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index dc5f16b41b..e539ad8b30 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2019, NVIDIA CORPORATION. All rights reserved. */ /* Tegra SoC common clock control functions */ @@ -815,11 +815,16 @@ void tegra30_set_up_pllp(void) int clock_external_output(int clk_id) { - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + u32 val; if (clk_id >= 1 && clk_id <= 3) { - setbits_le32(&pmc->pmc_clk_out_cntrl, - 1 << (2 + (clk_id - 1) * 8)); + val = tegra_pmc_readl(offsetof(struct pmc_ctlr, + pmc_clk_out_cntrl)); + val |= 1 << (2 + (clk_id - 1) * 8); + tegra_pmc_writel(val, + offsetof(struct pmc_ctlr, + pmc_clk_out_cntrl)); + } else { printf("%s: Unknown output clock id %d\n", __func__, clk_id); return -EINVAL; diff --git a/arch/arm/mach-tegra/cmd_enterrcm.c b/arch/arm/mach-tegra/cmd_enterrcm.c index 4e6beb3e5b..4a889f0e34 100644 --- a/arch/arm/mach-tegra/cmd_enterrcm.c +++ b/arch/arm/mach-tegra/cmd_enterrcm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2019, NVIDIA CORPORATION. All rights reserved. * * Derived from code (arch/arm/lib/reset.c) that is: * @@ -31,12 +31,10 @@ static int do_enterrcm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - puts("Entering RCM...\n"); udelay(50000); - pmc->pmc_scratch0 = 2; + tegra_pmc_writel(2, PMC_SCRATCH0); disable_interrupts(); reset_cpu(0); diff --git a/arch/arm/mach-tegra/cpu.c b/arch/arm/mach-tegra/cpu.c index 1b6ad074ed..3d140760e6 100644 --- a/arch/arm/mach-tegra/cpu.c +++ b/arch/arm/mach-tegra/cpu.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2019, NVIDIA CORPORATION. All rights reserved. */ #include <common.h> @@ -299,21 +299,19 @@ void enable_cpu_clock(int enable) static int is_cpu_powered(void) { - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - - return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; + return (tegra_pmc_readl(offsetof(struct pmc_ctlr, + pmc_pwrgate_status)) & CPU_PWRED) ? 1 : 0; } static void remove_cpu_io_clamps(void) { - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; u32 reg; debug("%s entry\n", __func__); /* Remove the clamps on the CPU I/O signals */ - reg = readl(&pmc->pmc_remove_clamping); + reg = tegra_pmc_readl(offsetof(struct pmc_ctlr, pmc_remove_clamping)); reg |= CPU_CLMP; - writel(reg, &pmc->pmc_remove_clamping); + tegra_pmc_writel(reg, offsetof(struct pmc_ctlr, pmc_remove_clamping)); /* Give I/O signals time to stabilize */ udelay(IO_STABILIZATION_DELAY); @@ -321,17 +319,19 @@ static void remove_cpu_io_clamps(void) void powerup_cpu(void) { - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; u32 reg; int timeout = IO_STABILIZATION_DELAY; debug("%s entry\n", __func__); if (!is_cpu_powered()) { /* Toggle the CPU power state (OFF -> ON) */ - reg = readl(&pmc->pmc_pwrgate_toggle); + reg = tegra_pmc_readl(offsetof(struct pmc_ctlr, + pmc_pwrgate_toggle)); reg &= PARTID_CP; reg |= START_CP; - writel(reg, &pmc->pmc_pwrgate_toggle); + tegra_pmc_writel(reg, + offsetof(struct pmc_ctlr, + pmc_pwrgate_toggle)); /* Wait for the power to come up */ while (!is_cpu_powered()) { diff --git a/arch/arm/mach-tegra/emc.c b/arch/arm/mach-tegra/emc.c index 6697909d9a..66628933b6 100644 --- a/arch/arm/mach-tegra/emc.c +++ b/arch/arm/mach-tegra/emc.c @@ -8,10 +8,10 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/emc.h> -#include <asm/arch/pmu.h> #include <asm/arch/tegra.h> #include <asm/arch-tegra/ap.h> #include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmu.h> #include <asm/arch-tegra/sys_proto.h> DECLARE_GLOBAL_DATA_PTR; diff --git a/arch/arm/mach-tegra/lowlevel_init.S b/arch/arm/mach-tegra/lowlevel_init.S deleted file mode 100644 index 626f1b6427..0000000000 --- a/arch/arm/mach-tegra/lowlevel_init.S +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * SoC-specific setup info - * - * (C) Copyright 2010,2011 - * NVIDIA Corporation <www.nvidia.com> - */ - -#include <config.h> -#include <linux/linkage.h> - -#ifdef CONFIG_ARM64 - .align 5 -ENTRY(reset_cpu) - /* get address for global reset register */ - ldr x1, =PRM_RSTCTRL - ldr w3, [x1] - /* force reset */ - orr w3, w3, #0x10 - str w3, [x1] - mov w0, w0 -1: - b 1b -ENDPROC(reset_cpu) -#else - .align 5 -ENTRY(reset_cpu) - ldr r1, rstctl @ get addr for global reset - @ reg - ldr r3, [r1] - orr r3, r3, #0x10 - str r3, [r1] @ force reset - mov r0, r0 -_loop_forever: - b _loop_forever -rstctl: - .word PRM_RSTCTRL -ENDPROC(reset_cpu) -#endif diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c new file mode 100644 index 0000000000..afd3c54179 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. + */ + +#include <common.h> + +#include <linux/arm-smccc.h> + +#include <asm/io.h> +#include <asm/arch-tegra/pmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE) +static bool tegra_pmc_detect_tz_only(void) +{ + static bool initialized = false; + static bool is_tz_only = false; + u32 value, saved; + + if (!initialized) { + saved = readl(NV_PA_PMC_BASE + PMC_SCRATCH0); + value = saved ^ 0xffffffff; + + if (value == 0xffffffff) + value = 0xdeadbeef; + + /* write pattern and read it back */ + writel(value, NV_PA_PMC_BASE + PMC_SCRATCH0); + value = readl(NV_PA_PMC_BASE + PMC_SCRATCH0); + + /* if we read all-zeroes, access is restricted to TZ only */ + if (value == 0) { + debug("access to PMC is restricted to TZ\n"); + is_tz_only = true; + } else { + /* restore original value */ + writel(saved, NV_PA_PMC_BASE + PMC_SCRATCH0); + } + + initialized = true; + } + + return is_tz_only; +} +#endif + +uint32_t tegra_pmc_readl(unsigned long offset) +{ +#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE) + if (tegra_pmc_detect_tz_only()) { + struct arm_smccc_res res; + + arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_READ, offset, 0, 0, + 0, 0, 0, &res); + if (res.a0) + printf("%s(): SMC failed: %lu\n", __func__, res.a0); + + return res.a1; + } +#endif + + return readl(NV_PA_PMC_BASE + offset); +} + +void tegra_pmc_writel(u32 value, unsigned long offset) +{ +#if IS_ENABLED(CONFIG_TEGRA_PMC_SECURE) + if (tegra_pmc_detect_tz_only()) { + struct arm_smccc_res res; + + arm_smccc_smc(TEGRA_SMC_PMC, TEGRA_SMC_PMC_WRITE, offset, + value, 0, 0, 0, 0, &res); + if (res.a0) + printf("%s(): SMC failed: %lu\n", __func__, res.a0); + + return; + } +#endif + + writel(value, NV_PA_PMC_BASE + offset); +} + +void reset_cpu(ulong addr) +{ + u32 value; + + value = tegra_pmc_readl(PMC_CNTRL); + value |= PMC_CNTRL_MAIN_RST; + tegra_pmc_writel(value, PMC_CNTRL); +} diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index e45f0961b2..761c9ef19e 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2019, NVIDIA CORPORATION. All rights reserved. */ #include <common.h> @@ -11,6 +11,7 @@ #include <asm/arch/powergate.h> #include <asm/arch/tegra.h> +#include <asm/arch-tegra/pmc.h> #define PWRGATE_TOGGLE 0x30 #define PWRGATE_TOGGLE_START (1 << 8) @@ -24,18 +25,18 @@ static int tegra_powergate_set(enum tegra_powergate id, bool state) u32 value, mask = state ? (1 << id) : 0, old_mask; unsigned long start, timeout = 25; - value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS); + value = tegra_pmc_readl(PWRGATE_STATUS); old_mask = value & (1 << id); if (mask == old_mask) return 0; - writel(PWRGATE_TOGGLE_START | id, NV_PA_PMC_BASE + PWRGATE_TOGGLE); + tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); start = get_timer(0); while (get_timer(start) < timeout) { - value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS); + value = tegra_pmc_readl(PWRGATE_STATUS); if ((value & (1 << id)) == mask) return 0; } @@ -69,7 +70,7 @@ static int tegra_powergate_remove_clamping(enum tegra_powergate id) else value = 1 << id; - writel(value, NV_PA_PMC_BASE + REMOVE_CLAMPING); + tegra_pmc_writel(value, REMOVE_CLAMPING); return 0; } diff --git a/arch/arm/mach-tegra/tegra186/Makefile b/arch/arm/mach-tegra/tegra186/Makefile index 56f3378ece..3a24050277 100644 --- a/arch/arm/mach-tegra/tegra186/Makefile +++ b/arch/arm/mach-tegra/tegra186/Makefile @@ -2,8 +2,4 @@ # # SPDX-License-Identifier: GPL-2.0 -obj-y += ../board186.o obj-y += cache.o -obj-y += nvtboot_board.o -obj-y += nvtboot_ll.o -obj-y += nvtboot_mem.o diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_board.c b/arch/arm/mach-tegra/tegra186/nvtboot_board.c deleted file mode 100644 index 83c0e931ea..0000000000 --- a/arch/arm/mach-tegra/tegra186/nvtboot_board.c +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2016-2018, NVIDIA CORPORATION. - */ - -#include <stdlib.h> -#include <common.h> -#include <fdt_support.h> -#include <fdtdec.h> -#include <asm/arch/tegra.h> -#include <asm/armv8/mmu.h> - -extern unsigned long nvtboot_boot_x0; - -/* - * The following few functions run late during the boot process and dynamically - * calculate the load address of various binaries. To keep track of multiple - * allocations, some writable list of RAM banks must be used. tegra_mem_map[] - * is used for this purpose to avoid making yet another copy of the list of RAM - * banks. This is safe because tegra_mem_map[] is only used once during very - * early boot to create U-Boot's page tables, long before this code runs. If - * this assumption becomes invalid later, we can just fix the code to copy the - * list of RAM banks into some private data structure before running. - */ - -extern struct mm_region tegra_mem_map[]; - -static char *gen_varname(const char *var, const char *ext) -{ - size_t len_var = strlen(var); - size_t len_ext = strlen(ext); - size_t len = len_var + len_ext + 1; - char *varext = malloc(len); - - if (!varext) - return 0; - strcpy(varext, var); - strcpy(varext + len_var, ext); - return varext; -} - -static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end) -{ - u64 bank_start = tegra_mem_map[bank].virt; - u64 bank_size = tegra_mem_map[bank].size; - u64 bank_end = bank_start + bank_size; - bool keep_front = allocated_start != bank_start; - bool keep_tail = allocated_end != bank_end; - - if (keep_front && keep_tail) { - /* - * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array, - * starting at index 1 (index 0 is MMIO). So, we are at DRAM - * entry "bank" not "bank - 1" as for a typical 0-base array. - * The number of remaining DRAM entries is therefore - * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the - * current entry and shift up the remaining entries, dropping - * the last one. Thus, we must copy one fewer entry than the - * number remaining. - */ - memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank], - CONFIG_NR_DRAM_BANKS - bank - 1); - tegra_mem_map[bank].size = allocated_start - bank_start; - bank++; - tegra_mem_map[bank].virt = allocated_end; - tegra_mem_map[bank].phys = allocated_end; - tegra_mem_map[bank].size = bank_end - allocated_end; - } else if (keep_front) { - tegra_mem_map[bank].size = allocated_start - bank_start; - } else if (keep_tail) { - tegra_mem_map[bank].virt = allocated_end; - tegra_mem_map[bank].phys = allocated_end; - tegra_mem_map[bank].size = bank_end - allocated_end; - } else { - /* - * We could move all subsequent banks down in the array but - * that's not necessary for subsequent allocations to work, so - * we skip doing so. - */ - tegra_mem_map[bank].size = 0; - } -} - -static void reserve_ram(u64 start, u64 size) -{ - int bank; - u64 end = start + size; - - for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { - u64 bank_start = tegra_mem_map[bank].virt; - u64 bank_size = tegra_mem_map[bank].size; - u64 bank_end = bank_start + bank_size; - - if (end <= bank_start || start > bank_end) - continue; - mark_ram_allocated(bank, start, end); - break; - } -} - -static u64 alloc_ram(u64 size, u64 align, u64 offset) -{ - int bank; - - for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { - u64 bank_start = tegra_mem_map[bank].virt; - u64 bank_size = tegra_mem_map[bank].size; - u64 bank_end = bank_start + bank_size; - u64 allocated = ROUND(bank_start, align) + offset; - u64 allocated_end = allocated + size; - - if (allocated_end > bank_end) - continue; - mark_ram_allocated(bank, allocated, allocated_end); - return allocated; - } - return 0; -} - -static void set_calculated_aliases(char *aliases, u64 address) -{ - char *tmp, *alias; - int err; - - aliases = strdup(aliases); - if (!aliases) { - pr_err("strdup(aliases) failed"); - return; - } - - tmp = aliases; - while (true) { - alias = strsep(&tmp, " "); - if (!alias) - break; - debug("%s: alias: %s\n", __func__, alias); - err = env_set_hex(alias, address); - if (err) - pr_err("Could not set %s\n", alias); - } - - free(aliases); -} - -static void set_calculated_env_var(const char *var) -{ - char *var_size; - char *var_align; - char *var_offset; - char *var_aliases; - u64 size; - u64 align; - u64 offset; - char *aliases; - u64 address; - int err; - - var_size = gen_varname(var, "_size"); - if (!var_size) - return; - var_align = gen_varname(var, "_align"); - if (!var_align) - goto out_free_var_size; - var_offset = gen_varname(var, "_offset"); - if (!var_offset) - goto out_free_var_align; - var_aliases = gen_varname(var, "_aliases"); - if (!var_aliases) - goto out_free_var_offset; - - size = env_get_hex(var_size, 0); - if (!size) { - pr_err("%s not set or zero\n", var_size); - goto out_free_var_aliases; - } - align = env_get_hex(var_align, 1); - /* Handle extant variables, but with a value of 0 */ - if (!align) - align = 1; - offset = env_get_hex(var_offset, 0); - aliases = env_get(var_aliases); - - debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n", - __func__, var, size, align, offset); - if (aliases) - debug("%s: Aliases: %s\n", __func__, aliases); - - address = alloc_ram(size, align, offset); - if (!address) { - pr_err("Could not allocate %s\n", var); - goto out_free_var_aliases; - } - debug("%s: Address %llx\n", __func__, address); - - err = env_set_hex(var, address); - if (err) - pr_err("Could not set %s\n", var); - if (aliases) - set_calculated_aliases(aliases, address); - -out_free_var_aliases: - free(var_aliases); -out_free_var_offset: - free(var_offset); -out_free_var_align: - free(var_align); -out_free_var_size: - free(var_size); -} - -#ifdef DEBUG -static void dump_ram_banks(void) -{ - int bank; - - for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { - u64 bank_start = tegra_mem_map[bank].virt; - u64 bank_size = tegra_mem_map[bank].size; - u64 bank_end = bank_start + bank_size; - - if (!bank_size) - continue; - printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1, - bank_start, bank_end, bank_size); - } -} -#endif - -static void set_calculated_env_vars(void) -{ - char *vars, *tmp, *var; - -#ifdef DEBUG - printf("RAM banks before any calculated env. var.s:\n"); - dump_ram_banks(); -#endif - - reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0)); - -#ifdef DEBUG - printf("RAM after reserving cboot DTB:\n"); - dump_ram_banks(); -#endif - - vars = env_get("calculated_vars"); - if (!vars) { - debug("%s: No env var calculated_vars\n", __func__); - return; - } - - vars = strdup(vars); - if (!vars) { - pr_err("strdup(calculated_vars) failed"); - return; - } - - tmp = vars; - while (true) { - var = strsep(&tmp, " "); - if (!var) - break; - debug("%s: var: %s\n", __func__, var); - set_calculated_env_var(var); -#ifdef DEBUG - printf("RAM banks affter allocating %s:\n", var); - dump_ram_banks(); -#endif - } - - free(vars); -} - -static int set_fdt_addr(void) -{ - int ret; - - ret = env_set_hex("fdt_addr", nvtboot_boot_x0); - if (ret) { - printf("Failed to set fdt_addr to point at DTB: %d\n", ret); - return ret; - } - - return 0; -} - -/* - * Attempt to use /chosen/nvidia,ether-mac in the nvtboot DTB to U-Boot's - * ethaddr environment variable if possible. - */ -static int set_ethaddr_from_nvtboot(void) -{ - const void *nvtboot_blob = (void *)nvtboot_boot_x0; - int ret, node, len; - const u32 *prop; - - /* Already a valid address in the environment? If so, keep it */ - if (env_get("ethaddr")) - return 0; - - node = fdt_path_offset(nvtboot_blob, "/chosen"); - if (node < 0) { - printf("Can't find /chosen node in nvtboot DTB\n"); - return node; - } - prop = fdt_getprop(nvtboot_blob, node, "nvidia,ether-mac", &len); - if (!prop) { - printf("Can't find nvidia,ether-mac property in nvtboot DTB\n"); - return -ENOENT; - } - - ret = env_set("ethaddr", (void *)prop); - if (ret) { - printf("Failed to set ethaddr from nvtboot DTB: %d\n", ret); - return ret; - } - - return 0; -} - -int tegra_soc_board_init_late(void) -{ - set_calculated_env_vars(); - /* - * Ignore errors here; the value may not be used depending on - * extlinux.conf or boot script content. - */ - set_fdt_addr(); - /* Ignore errors here; not all cases care about Ethernet addresses */ - set_ethaddr_from_nvtboot(); - - return 0; -} diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_ll.S b/arch/arm/mach-tegra/tegra186/nvtboot_ll.S deleted file mode 100644 index aa7a863d97..0000000000 --- a/arch/arm/mach-tegra/tegra186/nvtboot_ll.S +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Save nvtboot-related boot-time CPU state - * - * (C) Copyright 2015-2016 NVIDIA Corporation <www.nvidia.com> - */ - -#include <config.h> -#include <linux/linkage.h> - -.align 8 -.globl nvtboot_boot_x0 -nvtboot_boot_x0: - .dword 0 - -ENTRY(save_boot_params) - adr x8, nvtboot_boot_x0 - str x0, [x8] - b save_boot_params_ret -ENDPROC(save_boot_params) diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c deleted file mode 100644 index 62142821a5..0000000000 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2016-2018, NVIDIA CORPORATION. - */ - -#include <common.h> -#include <fdt_support.h> -#include <fdtdec.h> -#include <linux/sizes.h> -#include <asm/arch/tegra.h> -#include <asm/armv8/mmu.h> - -/* - * Size of a region that's large enough to hold the relocated U-Boot and all - * other allocations made around it (stack, heap, page tables, etc.) - * In practice, running "bdinfo" at the shell prompt, the stack reaches about - * 5MB from the address selected for ram_top as of the time of writing, - * so a 16MB region should be plenty. - */ -#define MIN_USABLE_RAM_SIZE SZ_16M -/* - * The amount of space we expect to require for stack usage. Used to validate - * that all reservations fit into the region selected for the relocation target - */ -#define MIN_USABLE_STACK_SIZE SZ_1M - -DECLARE_GLOBAL_DATA_PTR; - -extern unsigned long nvtboot_boot_x0; -extern struct mm_region tegra_mem_map[]; - -/* - * These variables are written to before relocation, and hence cannot be - * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. - * The section attribute forces this into .data and avoids this issue. This - * also has the nice side-effect of the content being valid after relocation. - */ - -/* The number of valid entries in ram_banks[] */ -static int ram_bank_count __attribute__((section(".data"))); - -/* - * The usable top-of-RAM for U-Boot. This is both: - * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. - * b) At the end of a region that has enough space to hold the relocated U-Boot - * and all other allocations made around it (stack, heap, page tables, etc.) - */ -static u64 ram_top __attribute__((section(".data"))); -/* The base address of the region of RAM that ends at ram_top */ -static u64 region_base __attribute__((section(".data"))); - -int dram_init(void) -{ - unsigned int na, ns; - const void *nvtboot_blob = (void *)nvtboot_boot_x0; - int node, len, i; - const u32 *prop; - - na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); - ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); - - node = fdt_path_offset(nvtboot_blob, "/memory"); - if (node < 0) { - pr_err("Can't find /memory node in nvtboot DTB"); - hang(); - } - prop = fdt_getprop(nvtboot_blob, node, "reg", &len); - if (!prop) { - pr_err("Can't find /memory/reg property in nvtboot DTB"); - hang(); - } - - /* Calculate the true # of base/size pairs to read */ - len /= 4; /* Convert bytes to number of cells */ - len /= (na + ns); /* Convert cells to number of banks */ - if (len > CONFIG_NR_DRAM_BANKS) - len = CONFIG_NR_DRAM_BANKS; - - /* Parse the /memory node, and save useful entries */ - gd->ram_size = 0; - ram_bank_count = 0; - for (i = 0; i < len; i++) { - u64 bank_start, bank_end, bank_size, usable_bank_size; - - /* Extract raw memory region data from DTB */ - bank_start = fdt_read_number(prop, na); - prop += na; - bank_size = fdt_read_number(prop, ns); - prop += ns; - gd->ram_size += bank_size; - bank_end = bank_start + bank_size; - debug("Bank %d: %llx..%llx (+%llx)\n", i, - bank_start, bank_end, bank_size); - - /* - * Align the bank to MMU section size. This is not strictly - * necessary, since the translation table construction code - * handles page granularity without issue. However, aligning - * the MMU entries reduces the size and number of levels in the - * page table, so is worth it. - */ - bank_start = ROUND(bank_start, SZ_2M); - bank_end = bank_end & ~(SZ_2M - 1); - bank_size = bank_end - bank_start; - debug(" aligned: %llx..%llx (+%llx)\n", - bank_start, bank_end, bank_size); - if (bank_end <= bank_start) - continue; - - /* Record data used to create MMU translation tables */ - ram_bank_count++; - /* Index below is deliberately 1-based to skip MMIO entry */ - tegra_mem_map[ram_bank_count].virt = bank_start; - tegra_mem_map[ram_bank_count].phys = bank_start; - tegra_mem_map[ram_bank_count].size = bank_size; - tegra_mem_map[ram_bank_count].attrs = - PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; - - /* Determine best bank to relocate U-Boot into */ - if (bank_end > SZ_4G) - bank_end = SZ_4G; - debug(" end %llx (usable)\n", bank_end); - usable_bank_size = bank_end - bank_start; - debug(" size %llx (usable)\n", usable_bank_size); - if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && - (bank_end > ram_top)) { - ram_top = bank_end; - region_base = bank_start; - debug("ram top now %llx\n", ram_top); - } - } - - /* Ensure memory map contains the desired sentinel entry */ - tegra_mem_map[ram_bank_count + 1].virt = 0; - tegra_mem_map[ram_bank_count + 1].phys = 0; - tegra_mem_map[ram_bank_count + 1].size = 0; - tegra_mem_map[ram_bank_count + 1].attrs = 0; - - /* Error out if a relocation target couldn't be found */ - if (!ram_top) { - pr_err("Can't find a usable RAM top"); - hang(); - } - - return 0; -} - -int dram_init_banksize(void) -{ - int i; - - if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { - pr_err("Reservations exceed chosen region size"); - hang(); - } - - for (i = 0; i < ram_bank_count; i++) { - gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; - gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; - } - -#ifdef CONFIG_PCI - gd->pci_ram_top = ram_top; -#endif - - return 0; -} - -ulong board_get_usable_ram_top(ulong total_size) -{ - return ram_top; -} diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 06068c4b7b..b240860f08 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -40,7 +40,7 @@ enum clock_type_id { CLOCK_TYPE_PDCT, CLOCK_TYPE_ACPT, CLOCK_TYPE_ASPTE, - CLOCK_TYPE_PMDACD2T, + CLOCK_TYPE_PDD2T, CLOCK_TYPE_PCST, CLOCK_TYPE_DP, @@ -97,8 +97,8 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = { { CLK(AUDIO), CLK(SFROM32KHZ), CLK(PERIPH), CLK(OSC), CLK(EPCI), CLK(NONE), CLK(NONE), CLK(NONE), MASK_BITS_31_29}, - { CLK(PERIPH), CLK(MEMORY), CLK(DISPLAY), CLK(AUDIO), - CLK(CGENERAL), CLK(DISPLAY2), CLK(OSC), CLK(NONE), + { CLK(PERIPH), CLK(NONE), CLK(DISPLAY), CLK(NONE), + CLK(NONE), CLK(DISPLAY2), CLK(OSC), CLK(NONE), MASK_BITS_31_29}, { CLK(PERIPH), CLK(CGENERAL), CLK(SFROM32KHZ), CLK(OSC), CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), @@ -174,8 +174,8 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { TYPE(PERIPHC_0bh, CLOCK_TYPE_NONE), TYPE(PERIPHC_0ch, CLOCK_TYPE_NONE), TYPE(PERIPHC_SBC1, CLOCK_TYPE_PC2CC3M_T), - TYPE(PERIPHC_DISP1, CLOCK_TYPE_PMDACD2T), - TYPE(PERIPHC_DISP2, CLOCK_TYPE_PMDACD2T), + TYPE(PERIPHC_DISP1, CLOCK_TYPE_PDD2T), + TYPE(PERIPHC_DISP2, CLOCK_TYPE_PDD2T), /* 0x10 */ TYPE(PERIPHC_10h, CLOCK_TYPE_NONE), @@ -1265,7 +1265,6 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC5, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC6, CLOCK_ID_PERIPH }, { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH }, - { PERIPH_ID_DISP1, CLOCK_ID_CGENERAL }, { PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, diff --git a/board/nvidia/p2371-2180/p2371-2180.c b/board/nvidia/p2371-2180/p2371-2180.c index 212037da5a..4985302d6b 100644 --- a/board/nvidia/p2371-2180/p2371-2180.c +++ b/board/nvidia/p2371-2180/p2371-2180.c @@ -5,9 +5,13 @@ */ #include <common.h> +#include <environment.h> +#include <fdtdec.h> #include <i2c.h> +#include <linux/libfdt.h> #include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> +#include <asm/arch-tegra/cboot.h> #include "../p2571/max77620_init.h" #include "pinmux-config-p2371-2180.h" @@ -94,3 +98,96 @@ int tegra_pcie_board_init(void) return 0; } #endif /* PCI */ + +static void ft_mac_address_setup(void *fdt) +{ + const void *cboot_fdt = (const void *)cboot_boot_x0; + uint8_t mac[ETH_ALEN], local_mac[ETH_ALEN]; + const char *path; + int offset, err; + + err = cboot_get_ethaddr(cboot_fdt, local_mac); + if (err < 0) + memset(local_mac, 0, ETH_ALEN); + + path = fdt_get_alias(fdt, "ethernet"); + if (!path) + return; + + debug("ethernet alias found: %s\n", path); + + offset = fdt_path_offset(fdt, path); + if (offset < 0) { + printf("ethernet alias points to absent node %s\n", path); + return; + } + + if (is_valid_ethaddr(local_mac)) { + err = fdt_setprop(fdt, offset, "local-mac-address", local_mac, + ETH_ALEN); + if (!err) + debug("Local MAC address set: %pM\n", local_mac); + } + + if (eth_env_get_enetaddr("ethaddr", mac)) { + if (memcmp(local_mac, mac, ETH_ALEN) != 0) { + err = fdt_setprop(fdt, offset, "mac-address", mac, + ETH_ALEN); + if (!err) + debug("MAC address set: %pM\n", mac); + } + } +} + +static int ft_copy_carveout(void *dst, const void *src, const char *node) +{ + struct fdt_memory fb; + int err; + + err = fdtdec_get_carveout(src, node, "memory-region", 0, &fb); + if (err < 0) { + if (err != -FDT_ERR_NOTFOUND) + printf("failed to get carveout for %s: %d\n", node, + err); + + return err; + } + + err = fdtdec_set_carveout(dst, node, "memory-region", 0, "framebuffer", + &fb); + if (err < 0) { + printf("failed to set carveout for %s: %d\n", node, err); + return err; + } + + return 0; +} + +static void ft_carveout_setup(void *fdt) +{ + const void *cboot_fdt = (const void *)cboot_boot_x0; + static const char * const nodes[] = { + "/host1x@50000000/dc@54200000", + "/host1x@50000000/dc@54240000", + }; + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + err = ft_copy_carveout(fdt, cboot_fdt, nodes[i]); + if (err < 0) { + if (err != -FDT_ERR_NOTFOUND) + printf("failed to copy carveout for %s: %d\n", + nodes[i], err); + continue; + } + } +} + +int ft_board_setup(void *fdt, bd_t *bd) +{ + ft_mac_address_setup(fdt); + ft_carveout_setup(fdt); + + return 0; +} diff --git a/board/nvidia/p2771-0000/p2771-0000.c b/board/nvidia/p2771-0000/p2771-0000.c index 496e8a0211..d294c7ae01 100644 --- a/board/nvidia/p2771-0000/p2771-0000.c +++ b/board/nvidia/p2771-0000/p2771-0000.c @@ -4,10 +4,14 @@ */ #include <common.h> +#include <environment.h> +#include <fdtdec.h> #include <i2c.h> +#include <linux/libfdt.h> +#include <asm/arch-tegra/cboot.h> #include "../p2571/max77620_init.h" -int tegra_board_init(void) +void pin_mux_mmc(void) { struct udevice *dev; uchar val; @@ -18,19 +22,18 @@ int tegra_board_init(void) ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev); if (ret) { printf("%s: Cannot find MAX77620 I2C chip\n", __func__); - return ret; + return; } /* 0xF2 for 3.3v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */ val = 0xF2; ret = dm_i2c_write(dev, MAX77620_CNFG1_L3_REG, &val, 1); if (ret) { printf("i2c_write 0 0x3c 0x27 failed: %d\n", ret); - return ret; + return; } - - return 0; } +#ifdef CONFIG_PCI_TEGRA int tegra_pcie_board_init(void) { struct udevice *dev; @@ -52,3 +55,101 @@ int tegra_pcie_board_init(void) return 0; } +#endif + +static void ft_mac_address_setup(void *fdt) +{ + const void *cboot_fdt = (const void *)cboot_boot_x0; + uint8_t mac[ETH_ALEN], local_mac[ETH_ALEN]; + const char *path; + int offset, err; + + err = cboot_get_ethaddr(cboot_fdt, local_mac); + if (err < 0) + memset(local_mac, 0, ETH_ALEN); + + path = fdt_get_alias(fdt, "ethernet"); + if (!path) + return; + + debug("ethernet alias found: %s\n", path); + + offset = fdt_path_offset(fdt, path); + if (offset < 0) { + printf("ethernet alias points to absent node %s\n", path); + return; + } + + if (is_valid_ethaddr(local_mac)) { + err = fdt_setprop(fdt, offset, "local-mac-address", local_mac, + ETH_ALEN); + if (!err) + debug("Local MAC address set: %pM\n", local_mac); + } + + if (eth_env_get_enetaddr("ethaddr", mac)) { + if (memcmp(local_mac, mac, ETH_ALEN) != 0) { + err = fdt_setprop(fdt, offset, "mac-address", mac, + ETH_ALEN); + if (!err) + debug("MAC address set: %pM\n", mac); + } + } +} + +static int ft_copy_carveout(void *dst, const void *src, const char *node) +{ + struct fdt_memory fb; + int err; + + err = fdtdec_get_carveout(src, node, "memory-region", 0, &fb); + if (err < 0) { + if (err != -FDT_ERR_NOTFOUND) + printf("failed to get carveout for %s: %d\n", node, + err); + + return err; + } + + err = fdtdec_set_carveout(dst, node, "memory-region", 0, "framebuffer", + &fb); + if (err < 0) { + printf("failed to set carveout for %s: %d\n", node, err); + return err; + } + + return 0; +} + +static void ft_carveout_setup(void *fdt) +{ + const void *cboot_fdt = (const void *)cboot_boot_x0; + static const char * const nodes[] = { + "/host1x@13e00000/display-hub@15200000/display@15200000", + "/host1x@13e00000/display-hub@15200000/display@15210000", + "/host1x@13e00000/display-hub@15200000/display@15220000", + }; + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(nodes); i++) { + printf("copying carveout for %s...\n", nodes[i]); + + err = ft_copy_carveout(fdt, cboot_fdt, nodes[i]); + if (err < 0) { + if (err != -FDT_ERR_NOTFOUND) + printf("failed to copy carveout for %s: %d\n", + nodes[i], err); + + continue; + } + } +} + +int ft_board_setup(void *fdt, bd_t *bd) +{ + ft_mac_address_setup(fdt); + ft_carveout_setup(fdt); + + return 0; +} diff --git a/configs/e2220-1170_defconfig b/configs/e2220-1170_defconfig index 4d253c5072..d650acae24 100644 --- a/configs/e2220-1170_defconfig +++ b/configs/e2220-1170_defconfig @@ -1,6 +1,6 @@ CONFIG_ARM=y CONFIG_TEGRA=y -CONFIG_SYS_TEXT_BASE=0x80110000 +CONFIG_SYS_TEXT_BASE=0x80080000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TEGRA210=y CONFIG_OF_SYSTEM_SETUP=y diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig index cdcb98a77e..aa9c1f66c4 100644 --- a/configs/p2371-0000_defconfig +++ b/configs/p2371-0000_defconfig @@ -1,6 +1,6 @@ CONFIG_ARM=y CONFIG_TEGRA=y -CONFIG_SYS_TEXT_BASE=0x80110000 +CONFIG_SYS_TEXT_BASE=0x80080000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TEGRA210=y CONFIG_TARGET_P2371_0000=y diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig index 122b1b1fd5..2a21ff1dd0 100644 --- a/configs/p2371-2180_defconfig +++ b/configs/p2371-2180_defconfig @@ -1,10 +1,11 @@ CONFIG_ARM=y CONFIG_TEGRA=y -CONFIG_SYS_TEXT_BASE=0x80110000 +CONFIG_SYS_TEXT_BASE=0x80080000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TEGRA210=y CONFIG_TARGET_P2371_2180=y CONFIG_OF_SYSTEM_SETUP=y +CONFIG_OF_BOARD_SETUP=y CONFIG_CONSOLE_MUX=y CONFIG_SYS_STDIO_DEREGISTER=y CONFIG_SYS_PROMPT="Tegra210 (P2371-2180) # " diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig index d28506b1c6..1c47064c04 100644 --- a/configs/p2571_defconfig +++ b/configs/p2571_defconfig @@ -1,6 +1,6 @@ CONFIG_ARM=y CONFIG_TEGRA=y -CONFIG_SYS_TEXT_BASE=0x80110000 +CONFIG_SYS_TEXT_BASE=0x80080000 CONFIG_NR_DRAM_BANKS=2 CONFIG_TEGRA210=y CONFIG_TARGET_P2571=y diff --git a/configs/p2771-0000-000_defconfig b/configs/p2771-0000-000_defconfig index 6d66cae3aa..4ac810db35 100644 --- a/configs/p2771-0000-000_defconfig +++ b/configs/p2771-0000-000_defconfig @@ -1,9 +1,10 @@ CONFIG_ARM=y CONFIG_TEGRA=y CONFIG_SYS_TEXT_BASE=0x80080000 -CONFIG_NR_DRAM_BANKS=8 +CONFIG_NR_DRAM_BANKS=1026 CONFIG_TEGRA186=y CONFIG_OF_SYSTEM_SETUP=y +CONFIG_OF_BOARD_SETUP=y CONFIG_CONSOLE_MUX=y CONFIG_SYS_STDIO_DEREGISTER=y CONFIG_SYS_PROMPT="Tegra186 (P2771-0000-000) # " diff --git a/configs/p2771-0000-500_defconfig b/configs/p2771-0000-500_defconfig index b8ac94ce60..3ca85272a8 100644 --- a/configs/p2771-0000-500_defconfig +++ b/configs/p2771-0000-500_defconfig @@ -1,9 +1,10 @@ CONFIG_ARM=y CONFIG_TEGRA=y CONFIG_SYS_TEXT_BASE=0x80080000 -CONFIG_NR_DRAM_BANKS=8 +CONFIG_NR_DRAM_BANKS=1026 CONFIG_TEGRA186=y CONFIG_OF_SYSTEM_SETUP=y +CONFIG_OF_BOARD_SETUP=y CONFIG_CONSOLE_MUX=y CONFIG_SYS_STDIO_DEREGISTER=y CONFIG_SYS_PROMPT="Tegra186 (P2771-0000-500) # " diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index e54428ba43..9685ee5059 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -21,12 +21,14 @@ #define CONFIG_SYS_NONCACHED_MEMORY (1 << 20) /* 1 MiB */ #ifndef CONFIG_SPL_BUILD +#ifndef BOOT_TARGET_DEVICES #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ func(USB, usb, 0) \ func(PXE, pxe, na) \ func(DHCP, dhcp, na) +#endif #include <config_distro_bootcmd.h> #else #define BOOTENV diff --git a/include/fdtdec.h b/include/fdtdec.h index fa8e34f6f9..e6c22dd5cd 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -997,6 +997,30 @@ int fdtdec_setup_memory_banksize_fdt(const void *blob); int fdtdec_setup_memory_banksize(void); /** + * fdtdec_set_ethernet_mac_address() - set MAC address for default interface + * + * Looks up the default interface via the "ethernet" alias (in the /aliases + * node) and stores the given MAC in its "local-mac-address" property. This + * is useful on platforms that store the MAC address in a custom location. + * Board code can call this in the late init stage to make sure that the + * interface device tree node has the right MAC address configured for the + * Ethernet uclass to pick it up. + * + * Typically the FDT passed into this function will be U-Boot's control DTB. + * Given that a lot of code may be holding offsets to various nodes in that + * tree, this code will only set the "local-mac-address" property in-place, + * which means that it needs to exist and have space for the 6-byte address. + * This ensures that the operation is non-destructive and does not invalidate + * offsets that other drivers may be using. + * + * @param fdt FDT blob + * @param mac buffer containing the MAC address to set + * @param size size of MAC address + * @return 0 on success or a negative error code on failure + */ +int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size); + +/** * fdtdec_set_phandle() - sets the phandle of a given node * * @param blob FDT blob diff --git a/include/linux/string.h b/include/linux/string.h index 3606620739..5d63be4ce5 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -94,6 +94,7 @@ size_t strcspn(const char *s, const char *reject); #ifndef __HAVE_ARCH_STRDUP extern char * strdup(const char *); #endif +extern char * strndup(const char *, size_t); #ifndef __HAVE_ARCH_STRSWAB extern char * strswab(const char *); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d0ba888973..3ee786b579 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1261,6 +1261,35 @@ __weak void *board_fdt_blob_setup(void) } #endif +int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size) +{ + const char *path; + int offset, err; + + if (!is_valid_ethaddr(mac)) + return -EINVAL; + + path = fdt_get_alias(fdt, "ethernet"); + if (!path) + return 0; + + debug("ethernet alias found: %s\n", path); + + offset = fdt_path_offset(fdt, path); + if (offset < 0) { + debug("ethernet alias points to absent node %s\n", path); + return -ENOENT; + } + + err = fdt_setprop_inplace(fdt, offset, "local-mac-address", mac, size); + if (err < 0) + return err; + + debug("MAC address: %pM\n", mac); + + return 0; +} + static int fdtdec_init_reserved_memory(void *blob) { int na, ns, node, err; diff --git a/lib/string.c b/lib/string.c index af17c16f61..9b779ddc3b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -326,6 +326,29 @@ char * strdup(const char *s) } #endif +char * strndup(const char *s, size_t n) +{ + size_t len; + char *new; + + if (s == NULL) + return NULL; + + len = strlen(s); + + if (n < len) + len = n; + + new = malloc(len + 1); + if (new == NULL) + return NULL; + + strncpy(new, s, len); + new[len] = '\0'; + + return new; +} + #ifndef __HAVE_ARCH_STRSPN /** * strspn - Calculate the length of the initial substring of @s which only |