Merge branch 'master' of git://git.denx.de/u-boot-tegra

The bulk of these changes are an effort to unify Tegra186 builds with
builds of prior 64-bit Tegra generations. On top of that there are
various improvements that allow data (such as the MAC address and boot
arguments) to be passed through from early firmware to the kernel on
boot.
This commit is contained in:
Tom Rini 2019-06-08 09:10:31 -04:00
commit 5973901826
57 changed files with 1242 additions and 723 deletions

View File

@ -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>;

View File

@ -29,7 +29,7 @@
reg = <0x80000000 0x80000000>;
};
pcie-controller@01003000 {
pcie@1003000 {
status = "okay";
avddio-pex-supply = <&vdd_1v05_run>;

View File

@ -29,7 +29,7 @@
reg = <0x80000000 0x80000000>;
};
pcie-controller@01003000 {
pcie@1003000 {
status = "okay";
avddio-pex-supply = <&vdd_1v05_run>;

View File

@ -14,7 +14,7 @@
interrupt-parent = <&lic>;
pcie-controller@01003000 {
pcie@1003000 {
compatible = "nvidia,tegra124-pcie";
device_type = "pci";
reg = <0x01003000 0x00000800 /* PADS registers */

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 */

View File

@ -599,7 +599,7 @@
nvidia,sys-clock-req-active-high;
};
pcie-controller@80003000 {
pcie@80003000 {
status = "okay";
avdd-pex-supply = <&pci_vdd_reg>;

View File

@ -30,7 +30,7 @@
spi-max-frequency = <25000000>;
};
pcie-controller@80003000 {
pcie@80003000 {
status = "okay";
avdd-pex-supply = <&pci_vdd_reg>;

View File

@ -580,7 +580,7 @@
reset-names = "fuse";
};
pcie-controller@80003000 {
pcie@80003000 {
compatible = "nvidia,tegra20-pcie";
device_type = "pci";
reg = <0x80003000 0x00000800 /* PADS registers */

View File

@ -21,7 +21,7 @@
reg = <0x0 0x80000000 0x0 0xc0000000>;
};
pcie-controller@01003000 {
pcie@1003000 {
status = "okay";
pci@1,0 {

View File

@ -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 */

View File

@ -32,7 +32,7 @@
reg = <0x80000000 0x40000000>;
};
pcie-controller@00003000 {
pcie@3000 {
status = "okay";
avdd-pexa-supply = <&vdd2_reg>;
vdd-pexa-supply = <&vdd2_reg>;

View File

@ -28,7 +28,7 @@
reg = <0x80000000 0x7ff00000>;
};
pcie-controller@00003000 {
pcie@3000 {
status = "okay";
avdd-pexa-supply = <&ldo1_reg>;

View File

@ -27,7 +27,7 @@
reg = <0x80000000 0x40000000>;
};
pcie-controller@00003000 {
pcie@3000 {
status = "okay";
/* AVDD_PEXA and VDD_PEXA inputs are grounded on Cardhu. */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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_ */

View File

@ -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) || \

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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

View File

@ -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/

View File

@ -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)

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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)

620
arch/arm/mach-tegra/cboot.c Normal file
View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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()) {

View File

@ -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;

View File

@ -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

92
arch/arm/mach-tegra/pmc.c Normal file
View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 },

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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) # "

View File

@ -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

View File

@ -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) # "

View File

@ -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) # "

View File

@ -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

View File

@ -996,6 +996,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
*

View File

@ -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

View File

@ -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;

View File

@ -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