diff options
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/board.c | 56 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pinmux-common.c | 223 |
3 files changed, 250 insertions, 35 deletions
diff --git a/arch/arm/mach-tegra/board.c b/arch/arm/mach-tegra/board.c index b6a84a5..0ebaf19 100644 --- a/arch/arm/mach-tegra/board.c +++ b/arch/arm/mach-tegra/board.c @@ -11,6 +11,7 @@ #include <asm/arch/funcmux.h> #include <asm/arch/mc.h> #include <asm/arch/tegra.h> +#include <asm/arch-tegra/ap.h> #include <asm/arch-tegra/board.h> #include <asm/arch-tegra/pmc.h> #include <asm/arch-tegra/sys_proto.h> @@ -28,27 +29,66 @@ enum { UART_COUNT = 5, }; +#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) +#if !defined(CONFIG_TEGRA124) +#error tegra_cpu_is_non_secure has only been validated on Tegra124 +#endif +bool tegra_cpu_is_non_secure(void) +{ + /* + * This register reads 0xffffffff in non-secure mode. This register + * only implements bits 31:20, so the lower bits will always read 0 in + * secure mode. Thus, the lower bits are an indicator for secure vs. + * non-secure mode. + */ + struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE; + uint32_t mc_s_cfg0 = readl(&mc->mc_security_cfg0); + return (mc_s_cfg0 & 1) == 1; +} +#endif + /* Read the RAM size directly from the memory controller */ unsigned int query_sdram_size(void) { struct mc_ctlr *const mc = (struct mc_ctlr *)NV_PA_MC_BASE; - u32 size_mb; + u32 emem_cfg, size_bytes; - size_mb = readl(&mc->mc_emem_cfg); + emem_cfg = readl(&mc->mc_emem_cfg); #if defined(CONFIG_TEGRA20) - debug("mc->mc_emem_cfg (MEM_SIZE_KB) = 0x%08x\n", size_mb); - size_mb = get_ram_size((void *)PHYS_SDRAM_1, size_mb * 1024); + debug("mc->mc_emem_cfg (MEM_SIZE_KB) = 0x%08x\n", emem_cfg); + size_bytes = get_ram_size((void *)PHYS_SDRAM_1, emem_cfg * 1024); #else - debug("mc->mc_emem_cfg (MEM_SIZE_MB) = 0x%08x\n", size_mb); - size_mb = get_ram_size((void *)PHYS_SDRAM_1, size_mb * 1024 * 1024); + debug("mc->mc_emem_cfg (MEM_SIZE_MB) = 0x%08x\n", emem_cfg); + /* + * If >=4GB RAM is present, the byte RAM size won't fit into 32-bits + * and will wrap. Clip the reported size to the maximum that a 32-bit + * variable can represent (rounded to a page). + */ + if (emem_cfg >= 4096) { + size_bytes = U32_MAX & ~(0x1000 - 1); + } else { + /* RAM size EMC is programmed to. */ + size_bytes = emem_cfg * 1024 * 1024; + /* + * If all RAM fits within 32-bits, it can be accessed without + * LPAE, so go test the RAM size. Otherwise, we can't access + * all the RAM, and get_ram_size() would get confused, so + * avoid using it. There's no reason we should need this + * validation step anyway. + */ + if (emem_cfg <= (0 - PHYS_SDRAM_1) / (1024 * 1024)) + size_bytes = get_ram_size((void *)PHYS_SDRAM_1, + size_bytes); + } #endif #if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) /* External memory limited to 2047 MB due to IROM/HI-VEC */ - if (size_mb == SZ_2G) size_mb -= SZ_1M; + if (size_bytes == SZ_2G) + size_bytes -= SZ_1M; #endif - return size_mb; + return size_bytes; } int dram_init(void) diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 11c7435..7c274b5 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -20,6 +20,7 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/tegra.h> +#include <asm/arch-tegra/ap.h> #include <asm/arch-tegra/clk_rst.h> #include <asm/arch-tegra/timer.h> #include <div64.h> @@ -573,7 +574,10 @@ void clock_init(void) debug("PLLX = %d\n", pll_rate[CLOCK_ID_XCPU]); /* Do any special system timer/TSC setup */ - arch_timer_init(); +#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) + if (!tegra_cpu_is_non_secure()) +#endif + arch_timer_init(); } static void set_avp_clock_source(u32 src) diff --git a/arch/arm/mach-tegra/pinmux-common.c b/arch/arm/mach-tegra/pinmux-common.c index 6e3ab0c..912f65e 100644 --- a/arch/arm/mach-tegra/pinmux-common.c +++ b/arch/arm/mach-tegra/pinmux-common.c @@ -24,31 +24,59 @@ #define pmux_pin_tristate_isvalid(tristate) \ (((tristate) >= PMUX_TRI_NORMAL) && ((tristate) <= PMUX_TRI_TRISTATE)) -#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +#ifdef TEGRA_PMX_PINS_HAVE_E_INPUT /* return 1 if a pin_io_is in range */ #define pmux_pin_io_isvalid(io) \ (((io) >= PMUX_PIN_OUTPUT) && ((io) <= PMUX_PIN_INPUT)) +#endif +#ifdef TEGRA_PMX_PINS_HAVE_LOCK /* return 1 if a pin_lock is in range */ #define pmux_pin_lock_isvalid(lock) \ (((lock) >= PMUX_PIN_LOCK_DISABLE) && ((lock) <= PMUX_PIN_LOCK_ENABLE)) +#endif +#ifdef TEGRA_PMX_PINS_HAVE_OD /* return 1 if a pin_od is in range */ #define pmux_pin_od_isvalid(od) \ (((od) >= PMUX_PIN_OD_DISABLE) && ((od) <= PMUX_PIN_OD_ENABLE)) +#endif +#ifdef TEGRA_PMX_PINS_HAVE_IO_RESET /* return 1 if a pin_ioreset_is in range */ #define pmux_pin_ioreset_isvalid(ioreset) \ (((ioreset) >= PMUX_PIN_IO_RESET_DISABLE) && \ ((ioreset) <= PMUX_PIN_IO_RESET_ENABLE)) +#endif -#ifdef TEGRA_PMX_HAS_RCV_SEL +#ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL /* return 1 if a pin_rcv_sel_is in range */ #define pmux_pin_rcv_sel_isvalid(rcv_sel) \ (((rcv_sel) >= PMUX_PIN_RCV_SEL_NORMAL) && \ ((rcv_sel) <= PMUX_PIN_RCV_SEL_HIGH)) -#endif /* TEGRA_PMX_HAS_RCV_SEL */ -#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */ +#endif + +#ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV +/* return 1 if a pin_e_io_hv is in range */ +#define pmux_pin_e_io_hv_isvalid(e_io_hv) \ + (((e_io_hv) >= PMUX_PIN_E_IO_HV_NORMAL) && \ + ((e_io_hv) <= PMUX_PIN_E_IO_HV_HIGH)) +#endif + +#ifdef TEGRA_PMX_GRPS_HAVE_LPMD +#define pmux_lpmd_isvalid(lpm) \ + (((lpm) >= PMUX_LPMD_X8) && ((lpm) <= PMUX_LPMD_X)) +#endif + +#if defined(TEGRA_PMX_PINS_HAVE_SCHMT) || defined(TEGRA_PMX_GRPS_HAVE_SCHMT) +#define pmux_schmt_isvalid(schmt) \ + (((schmt) >= PMUX_SCHMT_DISABLE) && ((schmt) <= PMUX_SCHMT_ENABLE)) +#endif + +#if defined(TEGRA_PMX_PINS_HAVE_HSM) || defined(TEGRA_PMX_GRPS_HAVE_HSM) +#define pmux_hsm_isvalid(hsm) \ + (((hsm) >= PMUX_HSM_DISABLE) && ((hsm) <= PMUX_HSM_ENABLE)) +#endif #define _R(offset) (u32 *)(NV_PA_APB_MISC_BASE + (offset)) @@ -78,15 +106,34 @@ #endif /* CONFIG_TEGRA20 */ -#define DRV_REG(group) _R(0x868 + ((group) * 4)) +#define DRV_REG(group) _R(TEGRA_PMX_SOC_DRV_GROUP_BASE_REG + ((group) * 4)) +/* + * We could force arch-tegraNN/pinmux.h to define all of these. However, + * that's a lot of defines, and for now it's manageable to just put a + * special case here. It's possible this decision will change with future + * SoCs. + */ +#ifdef CONFIG_TEGRA210 +#define IO_SHIFT 6 +#define LOCK_SHIFT 7 +#ifdef TEGRA_PMX_PINS_HAVE_HSM +#define HSM_SHIFT 9 +#endif +#define E_IO_HV_SHIFT 10 +#define OD_SHIFT 11 +#ifdef TEGRA_PMX_PINS_HAVE_SCHMT +#define SCHMT_SHIFT 12 +#endif +#else #define IO_SHIFT 5 #define OD_SHIFT 6 #define LOCK_SHIFT 7 #define IO_RESET_SHIFT 8 #define RCV_SEL_SHIFT 9 +#endif -#if !defined(CONFIG_TEGRA20) && !defined(CONFIG_TEGRA30) +#ifdef TEGRA_PMX_SOC_HAS_IO_CLAMPING /* This register/field only exists on Tegra114 and later */ #define APB_MISC_PP_PINMUX_GLOBAL_0 0x40 #define CLAMP_INPUTS_WHEN_TRISTATED 1 @@ -94,11 +141,15 @@ void pinmux_set_tristate_input_clamping(void) { u32 *reg = _R(APB_MISC_PP_PINMUX_GLOBAL_0); - u32 val; - val = readl(reg); - val |= CLAMP_INPUTS_WHEN_TRISTATED; - writel(val, reg); + setbits_le32(reg, CLAMP_INPUTS_WHEN_TRISTATED); +} + +void pinmux_clear_tristate_input_clamping(void) +{ + u32 *reg = _R(APB_MISC_PP_PINMUX_GLOBAL_0); + + clrbits_le32(reg, CLAMP_INPUTS_WHEN_TRISTATED); } #endif @@ -176,7 +227,7 @@ void pinmux_tristate_disable(enum pmux_pingrp pin) pinmux_set_tristate(pin, PMUX_TRI_NORMAL); } -#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +#ifdef TEGRA_PMX_PINS_HAVE_E_INPUT void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io) { u32 *reg = REG(pin); @@ -196,7 +247,9 @@ void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io) val &= ~(1 << IO_SHIFT); writel(val, reg); } +#endif +#ifdef TEGRA_PMX_PINS_HAVE_LOCK static void pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock) { u32 *reg = REG(pin); @@ -221,7 +274,9 @@ static void pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock) return; } +#endif +#ifdef TEGRA_PMX_PINS_HAVE_OD static void pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od) { u32 *reg = REG(pin); @@ -243,7 +298,9 @@ static void pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od) return; } +#endif +#ifdef TEGRA_PMX_PINS_HAVE_IO_RESET static void pinmux_set_ioreset(enum pmux_pingrp pin, enum pmux_pin_ioreset ioreset) { @@ -266,8 +323,9 @@ static void pinmux_set_ioreset(enum pmux_pingrp pin, return; } +#endif -#ifdef TEGRA_PMX_HAS_RCV_SEL +#ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL static void pinmux_set_rcv_sel(enum pmux_pingrp pin, enum pmux_pin_rcv_sel rcv_sel) { @@ -290,8 +348,82 @@ static void pinmux_set_rcv_sel(enum pmux_pingrp pin, return; } -#endif /* TEGRA_PMX_HAS_RCV_SEL */ -#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */ +#endif + +#ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV +static void pinmux_set_e_io_hv(enum pmux_pingrp pin, + enum pmux_pin_e_io_hv e_io_hv) +{ + u32 *reg = REG(pin); + u32 val; + + if (e_io_hv == PMUX_PIN_E_IO_HV_DEFAULT) + return; + + /* Error check on pin and e_io_hv */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_e_io_hv_isvalid(e_io_hv)); + + val = readl(reg); + if (e_io_hv == PMUX_PIN_E_IO_HV_HIGH) + val |= (1 << E_IO_HV_SHIFT); + else + val &= ~(1 << E_IO_HV_SHIFT); + writel(val, reg); + + return; +} +#endif + +#ifdef TEGRA_PMX_PINS_HAVE_SCHMT +static void pinmux_set_schmt(enum pmux_pingrp pin, enum pmux_schmt schmt) +{ + u32 *reg = REG(grp); + u32 val; + + /* NONE means unspecified/do not change/use POR value */ + if (schmt == PMUX_SCHMT_NONE) + return; + + /* Error check pad */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_schmt_isvalid(schmt)); + + val = readl(reg); + if (schmt == PMUX_SCHMT_ENABLE) + val |= (1 << SCHMT_SHIFT); + else + val &= ~(1 << SCHMT_SHIFT); + writel(val, reg); + + return; +} +#endif + +#ifdef TEGRA_PMX_PINS_HAVE_HSM +static void pinmux_set_hsm(enum pmux_pingrp pin, enum pmux_hsm hsm) +{ + u32 *reg = REG(grp); + u32 val; + + /* NONE means unspecified/do not change/use POR value */ + if (hsm == PMUX_HSM_NONE) + return; + + /* Error check pad */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_hsm_isvalid(hsm)); + + val = readl(reg); + if (hsm == PMUX_HSM_ENABLE) + val |= (1 << HSM_SHIFT); + else + val &= ~(1 << HSM_SHIFT); + writel(val, reg); + + return; +} +#endif static void pinmux_config_pingrp(const struct pmux_pingrp_config *config) { @@ -300,14 +432,29 @@ static void pinmux_config_pingrp(const struct pmux_pingrp_config *config) pinmux_set_func(pin, config->func); pinmux_set_pullupdown(pin, config->pull); pinmux_set_tristate(pin, config->tristate); -#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +#ifdef TEGRA_PMX_PINS_HAVE_E_INPUT pinmux_set_io(pin, config->io); +#endif +#ifdef TEGRA_PMX_PINS_HAVE_LOCK pinmux_set_lock(pin, config->lock); +#endif +#ifdef TEGRA_PMX_PINS_HAVE_OD pinmux_set_od(pin, config->od); +#endif +#ifdef TEGRA_PMX_PINS_HAVE_IO_RESET pinmux_set_ioreset(pin, config->ioreset); -#ifdef TEGRA_PMX_HAS_RCV_SEL +#endif +#ifdef TEGRA_PMX_PINS_HAVE_RCV_SEL pinmux_set_rcv_sel(pin, config->rcv_sel); #endif +#ifdef TEGRA_PMX_PINS_HAVE_E_IO_HV + pinmux_set_e_io_hv(pin, config->e_io_hv); +#endif +#ifdef TEGRA_PMX_PINS_HAVE_SCHMT + pinmux_set_schmt(pin, config->schmt); +#endif +#ifdef TEGRA_PMX_PINS_HAVE_HSM + pinmux_set_hsm(pin, config->hsm); #endif } @@ -320,7 +467,7 @@ void pinmux_config_pingrp_table(const struct pmux_pingrp_config *config, pinmux_config_pingrp(&config[i]); } -#ifdef TEGRA_PMX_HAS_DRVGRPS +#ifdef TEGRA_PMX_SOC_HAS_DRVGRPS #define pmux_drvgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PMUX_DRVGRP_COUNT)) @@ -330,19 +477,31 @@ void pinmux_config_pingrp_table(const struct pmux_pingrp_config *config, #define pmux_drv_isvalid(drv) \ (((drv) >= PMUX_DRVUP_MIN) && ((drv) <= PMUX_DRVUP_MAX)) -#define pmux_lpmd_isvalid(lpm) \ - (((lpm) >= PMUX_LPMD_X8) && ((lpm) <= PMUX_LPMD_X)) - -#define pmux_schmt_isvalid(schmt) \ - (((schmt) >= PMUX_SCHMT_DISABLE) && ((schmt) <= PMUX_SCHMT_ENABLE)) - -#define pmux_hsm_isvalid(hsm) \ - (((hsm) >= PMUX_HSM_DISABLE) && ((hsm) <= PMUX_HSM_ENABLE)) - +#ifdef TEGRA_PMX_GRPS_HAVE_HSM #define HSM_SHIFT 2 +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_SCHMT #define SCHMT_SHIFT 3 +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_LPMD #define LPMD_SHIFT 4 #define LPMD_MASK (3 << LPMD_SHIFT) +#endif +/* + * Note that the following DRV* and SLW* defines are accurate for many drive + * groups on many SoCs. We really need a per-group data structure to solve + * this, since the fields are in different positions/sizes in different + * registers (for different groups). + * + * On Tegra30/114/124, the DRV*_SHIFT values vary. + * On Tegra30, the SLW*_SHIFT values vary. + * On Tegra30/114/124/210, the DRV*_MASK values vary, although the values + * below are wide enough to cover the widest fields, and hopefully don't + * interfere with any other fields. + * On Tegra30, the SLW*_MASK values vary, but we can't use a value that's + * wide enough to cover all cases, since that would cause the field to + * overlap with other fields in the narrower cases. + */ #define DRVDN_SHIFT 12 #define DRVDN_MASK (0x7F << DRVDN_SHIFT) #define DRVUP_SHIFT 20 @@ -436,6 +595,7 @@ static void pinmux_set_drvdn(enum pmux_drvgrp grp, int drvdn) return; } +#ifdef TEGRA_PMX_GRPS_HAVE_LPMD static void pinmux_set_lpmd(enum pmux_drvgrp grp, enum pmux_lpmd lpmd) { u32 *reg = DRV_REG(grp); @@ -456,7 +616,9 @@ static void pinmux_set_lpmd(enum pmux_drvgrp grp, enum pmux_lpmd lpmd) return; } +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_SCHMT static void pinmux_set_schmt(enum pmux_drvgrp grp, enum pmux_schmt schmt) { u32 *reg = DRV_REG(grp); @@ -479,7 +641,9 @@ static void pinmux_set_schmt(enum pmux_drvgrp grp, enum pmux_schmt schmt) return; } +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_HSM static void pinmux_set_hsm(enum pmux_drvgrp grp, enum pmux_hsm hsm) { u32 *reg = DRV_REG(grp); @@ -502,6 +666,7 @@ static void pinmux_set_hsm(enum pmux_drvgrp grp, enum pmux_hsm hsm) return; } +#endif static void pinmux_config_drvgrp(const struct pmux_drvgrp_config *config) { @@ -511,9 +676,15 @@ static void pinmux_config_drvgrp(const struct pmux_drvgrp_config *config) pinmux_set_drvdn_slwr(grp, config->slwr); pinmux_set_drvup(grp, config->drvup); pinmux_set_drvdn(grp, config->drvdn); +#ifdef TEGRA_PMX_GRPS_HAVE_LPMD pinmux_set_lpmd(grp, config->lpmd); +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_SCHMT pinmux_set_schmt(grp, config->schmt); +#endif +#ifdef TEGRA_PMX_GRPS_HAVE_HSM pinmux_set_hsm(grp, config->hsm); +#endif } void pinmux_config_drvgrp_table(const struct pmux_drvgrp_config *config, |