diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
commit | f987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch) | |
tree | 0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /arch/arm/mach-tegra/common.c | |
parent | f737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff) | |
parent | fc993d9bc48f772133d8cd156c67c296477db070 (diff) |
Merge branch 'l4t/l4t-r16-r2' into colibri
Conflicts:
arch/arm/mach-tegra/tegra3_usb_phy.c
arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/tegra_udc.c
drivers/usb/otg/Makefile
drivers/video/tegra/fb.c
sound/soc/tegra/tegra_pcm.c
Diffstat (limited to 'arch/arm/mach-tegra/common.c')
-rw-r--r-- | arch/arm/mach-tegra/common.c | 190 |
1 files changed, 116 insertions, 74 deletions
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 3a4f86079053..a34d37f2f250 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -2,7 +2,7 @@ * arch/arm/mach-tegra/common.c * * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2010-2012 NVIDIA Corporation + * Copyright (C) 2010-2012, NVIDIA Corporation. All rights reserved. * * Author: * Colin Cross <ccross@android.com> @@ -29,6 +29,7 @@ #include <linux/bitops.h> #include <linux/sched.h> #include <linux/cpufreq.h> +#include <linux/of.h> #include <asm/hardware/cache-l2x0.h> #include <asm/system.h> @@ -220,6 +221,7 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = { { "sbc5.sclk", NULL, 40000000, false}, { "sbc6.sclk", NULL, 40000000, false}, { "wake.sclk", NULL, 40000000, true }, + { "cpu_mode.sclk", NULL, 80000000, false }, { "cbus", "pll_c", 416000000, false }, { "pll_c_out1", "pll_c", 208000000, false }, { "mselect", "pll_p", 102000000, true }, @@ -227,61 +229,11 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = { { NULL, NULL, 0, 0}, }; -#ifdef CONFIG_CACHE_L2X0 #ifdef CONFIG_TRUSTED_FOUNDATIONS -static void tegra_cache_smc(bool enable, u32 arg) +static inline void tegra_l2x0_disable_tz(void) { - void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; - bool need_affinity_switch; - bool can_switch_affinity; - bool l2x0_enabled; - cpumask_t local_cpu_mask; - cpumask_t saved_cpu_mask; - unsigned long flags; - long ret; - - /* - * ISSUE : Some registers of PL310 controler must be written - * from Secure context (and from CPU0)! - * - * When called form Normal we obtain an abort or do nothing. - * Instructions that must be called in Secure: - * - Write to Control register (L2X0_CTRL==0x100) - * - Write in Auxiliary controler (L2X0_AUX_CTRL==0x104) - * - Invalidate all entries (L2X0_INV_WAY==0x77C), - * mandatory at boot time. - * - Tag and Data RAM Latency Control Registers - * (0x108 & 0x10C) must be written in Secure. - */ - need_affinity_switch = (smp_processor_id() != 0); - can_switch_affinity = !irqs_disabled(); - - WARN_ON(need_affinity_switch && !can_switch_affinity); - if (need_affinity_switch && can_switch_affinity) { - cpu_set(0, local_cpu_mask); - sched_getaffinity(0, &saved_cpu_mask); - ret = sched_setaffinity(0, &local_cpu_mask); - WARN_ON(ret != 0); - } - - local_irq_save(flags); - l2x0_enabled = readl_relaxed(p + L2X0_CTRL) & 1; - if (enable && !l2x0_enabled) - tegra_generic_smc(0xFFFFF100, 0x00000001, arg); - else if (!enable && l2x0_enabled) - tegra_generic_smc(0xFFFFF100, 0x00000002, arg); - local_irq_restore(flags); - - if (need_affinity_switch && can_switch_affinity) { - ret = sched_setaffinity(0, &saved_cpu_mask); - WARN_ON(ret != 0); - } -} - -static void tegra_l2x0_disable(void) -{ - unsigned long flags; static u32 l2x0_way_mask; + BUG_ON(smp_processor_id() != 0); if (!l2x0_way_mask) { void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; @@ -292,30 +244,75 @@ static void tegra_l2x0_disable(void) ways = (aux_ctrl & (1 << 16)) ? 16 : 8; l2x0_way_mask = (1 << ways) - 1; } - - local_irq_save(flags); - tegra_cache_smc(false, l2x0_way_mask); - local_irq_restore(flags); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + /* flush all ways on any disable */ + tegra_generic_smc_uncached(0xFFFFF100, 0x00000002, l2x0_way_mask); +#elif defined(CONFIG_ARCH_TEGRA_3x_SOC) + if (tegra_is_cpu_in_lp2(0) == false) { + /* + * If entering LP0/LP1, ask secureos to fully flush and + * disable the L2. + * + * If entering LP2, L2 disable is handled by the secureos + * as part of the tegra_sleep_cpu() SMC. This SMC indicates + * no more secureos tasks will be scheduled, allowing it + * to optimize out L2 flushes on its side. + */ + tegra_generic_smc_uncached(0xFFFFF100, + 0x00000002, l2x0_way_mask); + } +#endif } -#endif /* CONFIG_TRUSTED_FOUNDATIONS */ -void tegra_init_cache(bool init) +static inline void tegra_init_cache_tz(bool init) { void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; u32 aux_ctrl; -#ifdef CONFIG_TRUSTED_FOUNDATIONS - /* issue the SMC to enable the L2 */ - aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL); - tegra_cache_smc(true, aux_ctrl); + BUG_ON(smp_processor_id() != 0); + + if (init) { + /* init L2 from secureos */ + tegra_generic_smc(0xFFFFF100, 0x00000001, 0x0); + + /* common init called for outer call hookup */ + aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL); + l2x0_init(p, aux_ctrl, 0xFFFFFFFF); + + /* use our outer_disable() routine */ + outer_cache.disable = tegra_l2x0_disable_tz; + } else { + /* reenable L2 in secureos */ + aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL); + tegra_generic_smc_uncached(0xFFFFF100, 0x00000004, aux_ctrl); + } +} +#endif /* CONFIG_TRUSTED_FOUNDATIONS */ - /* after init, reread aux_ctrl and register handlers */ - aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL); - l2x0_init(p, aux_ctrl, 0xFFFFFFFF); +#ifdef CONFIG_CACHE_L2X0 +/* + * We define our own outer_disable() to avoid L2 flush upon LP2 entry. + * Since the Tegra kernel will always be in single core mode when + * L2 is being disabled, we can omit the locking. Since we are not + * accessing the spinlock we also avoid the problem of the spinlock + * storage getting out of sync. + */ +static inline void tegra_l2x0_disable(void) +{ + void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; + writel_relaxed(0, p + L2X0_CTRL); + dsb(); +} - /* override outer_disable() with our disable */ - outer_cache.disable = tegra_l2x0_disable; +void tegra_init_cache(bool init) +{ +#ifdef CONFIG_TRUSTED_FOUNDATIONS + /* enable/re-enable of L2 handled by secureos */ + return tegra_init_cache_tz(init); #else + void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; + u32 aux_ctrl; + #if defined(CONFIG_ARCH_TEGRA_2x_SOC) writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL); writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL); @@ -353,6 +350,8 @@ void tegra_init_cache(bool init) aux_ctrl |= 0x7C000001; if (init) { l2x0_init(p, aux_ctrl, 0x8200c3fe); + /* use our outer_disable() routine to avoid flush */ + outer_cache.disable = tegra_l2x0_disable; } else { u32 tmp; @@ -365,7 +364,7 @@ void tegra_init_cache(bool init) l2x0_enable(); #endif } -#endif +#endif /* CONFIG_CACHE_L2X0 */ static void __init tegra_init_power(void) { @@ -676,11 +675,54 @@ __setup("audio_codec=", tegra_audio_codec_type); void tegra_get_board_info(struct board_info *bi) { - bi->board_id = (system_serial_high >> 16) & 0xFFFF; - bi->sku = (system_serial_high) & 0xFFFF; - bi->fab = (system_serial_low >> 24) & 0xFF; - bi->major_revision = (system_serial_low >> 16) & 0xFF; - bi->minor_revision = (system_serial_low >> 8) & 0xFF; +#ifdef CONFIG_OF + struct device_node *board_info; + u32 prop_val; + int err; + + board_info = of_find_node_by_path("/chosen/board_info"); + if (!IS_ERR_OR_NULL(board_info)) { + memset(bi, 0, sizeof(*bi)); + + err = of_property_read_u32(board_info, "id", &prop_val); + if (err) + pr_err("failed to read /chosen/board_info/id\n"); + else + bi->board_id = prop_val; + + err = of_property_read_u32(board_info, "sku", &prop_val); + if (err) + pr_err("failed to read /chosen/board_info/sku\n"); + else + bi->sku = prop_val; + + err = of_property_read_u32(board_info, "fab", &prop_val); + if (err) + pr_err("failed to read /chosen/board_info/fab\n"); + else + bi->fab = prop_val; + + err = of_property_read_u32(board_info, "major_revision", &prop_val); + if (err) + pr_err("failed to read /chosen/board_info/major_revision\n"); + else + bi->major_revision = prop_val; + + err = of_property_read_u32(board_info, "minor_revision", &prop_val); + if (err) + pr_err("failed to read /chosen/board_info/minor_revision\n"); + else + bi->minor_revision = prop_val; + } else { +#endif + bi->board_id = (system_serial_high >> 16) & 0xFFFF; + bi->sku = (system_serial_high) & 0xFFFF; + bi->fab = (system_serial_low >> 24) & 0xFF; + bi->major_revision = (system_serial_low >> 16) & 0xFF; + bi->minor_revision = (system_serial_low >> 8) & 0xFF; +#ifdef CONFIG_OF + } +#endif } static int __init tegra_pmu_board_info(char *info) |